IWallet implementation improvements
This commit is contained in:
parent
50cdbfa424
commit
49572fc425
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -2,3 +2,7 @@
|
|||
/build
|
||||
/tags
|
||||
.idea
|
||||
.ycm_extra_conf.py
|
||||
.ycm_extra_conf.pyc
|
||||
Release
|
||||
Debug
|
||||
|
|
|
@ -83,8 +83,8 @@ else()
|
|||
set(RELEASE_FLAGS "-Ofast -DNDEBUG -Wno-unused-variable")
|
||||
if(NOT APPLE)
|
||||
# There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux"
|
||||
AND ${CMAKE_BUILD_TYPE} STREQUAL "Release" AND ((CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.9) OR (CMAKE_C_COMPILER_VERSION VERSION_EQUAL 4.9)))
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_NAME STREQUAL "Linux"
|
||||
AND CMAKE_BUILD_TYPE STREQUAL "Release" AND ((CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.9) OR (CMAKE_C_COMPILER_VERSION VERSION_EQUAL 4.9)))
|
||||
# On linux, to build in lto mode, check that ld.gold linker is used: 'update-alternatives --install /usr/bin/ld ld /usr/bin/ld.gold HIGHEST_PRIORITY'
|
||||
set(CMAKE_AR gcc-ar)
|
||||
set(CMAKE_RANLIB gcc-ranlib)
|
||||
|
|
|
@ -155,7 +155,8 @@ const CheckpointData CHECKPOINTS[] = {
|
|||
{780000, "8dd55a9bae429e3685b90317281e633917023d3512eb7f37372209d1a5fc1070"},
|
||||
{785500, "de1a487d70964d25ed6f7de196866f357a293e867ee81313e7fd0352d0126bdd"},
|
||||
{789000, "acef490bbccce3b7b7ae8554a414f55413fbf4ca1472c6359b126a4439bd9f01"},
|
||||
{796000, "04e387a00d35db21d4d93d04040b31f22573972a7e61d72cc07d0ab69bcb9c44"}
|
||||
{796000, "04e387a00d35db21d4d93d04040b31f22573972a7e61d72cc07d0ab69bcb9c44"},
|
||||
{800000, "d7fa4eea02e5ce60b949136569c0ea7ac71ea46e0065311054072ac415560b86"}
|
||||
};
|
||||
} // CryptoNote
|
||||
|
||||
|
|
|
@ -261,7 +261,7 @@ bool core::check_tx_semantic(const Transaction& tx, bool keeped_by_block) {
|
|||
get_inputs_money_amount(tx, amount_in);
|
||||
uint64_t amount_out = get_outs_money_amount(tx);
|
||||
|
||||
if (amount_in <= amount_out) {
|
||||
if (amount_in < amount_out) {
|
||||
logger(ERROR) << "tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << getObjectHash(tx);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ namespace CryptoNote {
|
|||
|
||||
uint64_t outputs_amount = get_outs_money_amount(tx);
|
||||
|
||||
if (outputs_amount >= inputs_amount) {
|
||||
if (outputs_amount > inputs_amount) {
|
||||
logger(INFO) << "transaction use more money then it has: use " << m_currency.formatAmount(outputs_amount) <<
|
||||
", have " << m_currency.formatAmount(inputs_amount);
|
||||
tvc.m_verifivation_failed = true;
|
||||
|
|
|
@ -23,15 +23,7 @@
|
|||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
#include <System/Timer.h>
|
||||
#include <System/InterruptedException.h>
|
||||
|
@ -114,11 +106,8 @@ std::string createTemporaryFile(const std::string& path, std::fstream& tempFile)
|
|||
|
||||
//returns true on success
|
||||
bool deleteFile(const std::string& filename) {
|
||||
#ifdef WIN32
|
||||
return DeleteFile(filename.c_str()) != 0;
|
||||
#else
|
||||
return unlink(filename.c_str()) == 0;
|
||||
#endif
|
||||
boost::system::error_code err;
|
||||
return boost::filesystem::remove(filename, err) && !err;
|
||||
}
|
||||
|
||||
void replaceWalletFiles(const std::string &path, const std::string &tempFilePath) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <string.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
#include "ErrorMessage.h"
|
||||
|
||||
namespace System {
|
||||
|
||||
|
@ -40,7 +41,7 @@ public:
|
|||
MutextGuard(pthread_mutex_t& _mutex) : mutex(_mutex) {
|
||||
auto ret = pthread_mutex_lock(&mutex);
|
||||
if (ret != 0) {
|
||||
throw std::runtime_error("failed to acquire mutex, errno=" + std::to_string(ret) + ": " + strerror(ret));
|
||||
throw std::runtime_error("pthread_mutex_lock failed, " + errorMessage(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,15 +63,15 @@ Dispatcher::Dispatcher() {
|
|||
std::string message;
|
||||
epoll = ::epoll_create1(0);
|
||||
if (epoll == -1) {
|
||||
message = "epoll_create1() fail errno=" + std::to_string(errno);
|
||||
message = "epoll_create1 failed, " + lastErrorMessage();
|
||||
} else {
|
||||
mainContext.ucontext = new ucontext_t;
|
||||
if (getcontext(reinterpret_cast<ucontext_t*>(mainContext.ucontext)) == -1) {
|
||||
message = "getcontext() fail errno=" + std::to_string(errno);
|
||||
message = "getcontext failed, " + lastErrorMessage();
|
||||
} else {
|
||||
remoteSpawnEvent = eventfd(0, O_NONBLOCK);
|
||||
if(remoteSpawnEvent == -1) {
|
||||
message = "eventfd() fail errno=" + std::to_string(errno);
|
||||
message = "eventfd failed, " + lastErrorMessage();
|
||||
} else {
|
||||
remoteSpawnEventContext.writeContext = nullptr;
|
||||
remoteSpawnEventContext.readContext = nullptr;
|
||||
|
@ -80,7 +81,7 @@ Dispatcher::Dispatcher() {
|
|||
remoteSpawnEventEpollEvent.data.ptr = &remoteSpawnEventContext;
|
||||
|
||||
if (epoll_ctl(epoll, EPOLL_CTL_ADD, remoteSpawnEvent, &remoteSpawnEventEpollEvent) == -1) {
|
||||
message = "epoll_ctl() failed, errno=" + std::to_string(errno);
|
||||
message = "epoll_ctl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
*reinterpret_cast<pthread_mutex_t*>(this->mutex) = pthread_mutex_t(PTHREAD_MUTEX_INITIALIZER);
|
||||
|
||||
|
@ -155,7 +156,7 @@ void Dispatcher::clear() {
|
|||
while (!timers.empty()) {
|
||||
int result = ::close(timers.top());
|
||||
if (result == -1) {
|
||||
throw std::runtime_error("Dispatcher::clear, close failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::clear, close failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
timers.pop();
|
||||
|
@ -179,7 +180,7 @@ void Dispatcher::dispatch() {
|
|||
uint64_t buf;
|
||||
auto transferred = read(remoteSpawnEvent, &buf, sizeof buf);
|
||||
if(transferred == -1) {
|
||||
throw std::runtime_error("Dispatcher::dispatch() read(remoteSpawnEvent) fail errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::dispatch, read(remoteSpawnEvent) failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
MutextGuard guard(*reinterpret_cast<pthread_mutex_t*>(this->mutex));
|
||||
|
@ -206,7 +207,7 @@ void Dispatcher::dispatch() {
|
|||
}
|
||||
|
||||
if (errno != EINTR) {
|
||||
throw std::runtime_error("Dispatcher::dispatch(), epoll_wait() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::dispatch, epoll_wait failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +215,7 @@ void Dispatcher::dispatch() {
|
|||
ucontext_t* oldContext = static_cast<ucontext_t*>(currentContext->ucontext);
|
||||
currentContext = context;
|
||||
if (swapcontext(oldContext, static_cast<ucontext_t *>(context->ucontext)) == -1) {
|
||||
throw std::runtime_error("Dispatcher::dispatch() swapcontext() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::dispatch, swapcontext failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -269,7 +270,7 @@ void Dispatcher::remoteSpawn(std::function<void()>&& procedure) {
|
|||
uint64_t one = 1;
|
||||
auto transferred = write(remoteSpawnEvent, &one, sizeof one);
|
||||
if(transferred == - 1) {
|
||||
throw std::runtime_error("Dispatcher::remoteSpawn, write() failed errno = " + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::remoteSpawn, write failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,7 +309,7 @@ void Dispatcher::yield() {
|
|||
uint64_t buf;
|
||||
auto transferred = read(remoteSpawnEvent, &buf, sizeof buf);
|
||||
if(transferred == -1) {
|
||||
throw std::runtime_error("Dispatcher::dispatch() read(remoteSpawnEvent) fail errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::dispatch, read(remoteSpawnEvent) failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
MutextGuard guard(*reinterpret_cast<pthread_mutex_t*>(this->mutex));
|
||||
|
@ -334,7 +335,7 @@ void Dispatcher::yield() {
|
|||
}
|
||||
} else {
|
||||
if (errno != EINTR) {
|
||||
throw std::runtime_error("Dispatcher::dispatch(), epoll_wait() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::dispatch, epoll_wait failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -353,7 +354,7 @@ NativeContext& Dispatcher::getReusableContext() {
|
|||
if(firstReusableContext == nullptr) {
|
||||
ucontext_t* newlyCreatedContext = new ucontext_t;
|
||||
if (getcontext(newlyCreatedContext) == -1) { //makecontext precondition
|
||||
throw std::runtime_error("Dispatcher::getReusableContext(), getcontext() fail errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::getReusableContext, getcontext failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
auto stackPointer = new uint8_t[STACK_SIZE];
|
||||
|
@ -365,7 +366,7 @@ NativeContext& Dispatcher::getReusableContext() {
|
|||
|
||||
ucontext_t* oldContext = static_cast<ucontext_t*>(currentContext->ucontext);
|
||||
if (swapcontext(oldContext, newlyCreatedContext) == -1) {
|
||||
throw std::runtime_error("Dispatcher::getReusableContext() swapcontext() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::getReusableContext, swapcontext failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
assert(firstReusableContext != nullptr);
|
||||
|
@ -393,7 +394,7 @@ int Dispatcher::getTimer() {
|
|||
timerEvent.data.ptr = nullptr;
|
||||
|
||||
if (epoll_ctl(getEpoll(), EPOLL_CTL_ADD, timer, &timerEvent) == -1) {
|
||||
throw std::runtime_error("Dispatcher::getTimer(), epoll_ctl() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::getTimer, epoll_ctl failed, " + lastErrorMessage());
|
||||
}
|
||||
} else {
|
||||
timer = timers.top();
|
||||
|
@ -416,7 +417,7 @@ void Dispatcher::contextProcedure(void* ucontext) {
|
|||
firstReusableContext = &context;
|
||||
ucontext_t* oldContext = static_cast<ucontext_t*>(context.ucontext);
|
||||
if (swapcontext(oldContext, static_cast<ucontext_t*>(currentContext->ucontext)) == -1) {
|
||||
throw std::runtime_error("Dispatcher::contextProcedure() swapcontext() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::contextProcedure, swapcontext failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
|
32
src/Platform/Linux/System/ErrorMessage.cpp
Normal file
32
src/Platform/Linux/System/ErrorMessage.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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 "ErrorMessage.h"
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
namespace System {
|
||||
|
||||
std::string lastErrorMessage() {
|
||||
return errorMessage(errno);
|
||||
}
|
||||
|
||||
std::string errorMessage(int err) {
|
||||
return "result=" + std::to_string(err) + ", " + std::strerror(err);
|
||||
}
|
||||
|
||||
}
|
25
src/Platform/Linux/System/ErrorMessage.h
Normal file
25
src/Platform/Linux/System/ErrorMessage.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
// 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace System {
|
||||
std::string lastErrorMessage();
|
||||
std::string errorMessage(int);
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include <netdb.h>
|
||||
|
||||
#include <System/Dispatcher.h>
|
||||
#include <System/ErrorMessage.h>
|
||||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
|
||||
|
@ -62,7 +63,7 @@ Ipv4Address Ipv4Resolver::resolve(const std::string& host) {
|
|||
addrinfo* addressInfos;
|
||||
int result = getaddrinfo(host.c_str(), NULL, &hints, &addressInfos);
|
||||
if (result != 0) {
|
||||
throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, result=" + std::to_string(result));
|
||||
throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, " + errorMessage(result));
|
||||
}
|
||||
|
||||
std::size_t count = 0;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <System/ErrorMessage.h>
|
||||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
|
||||
|
@ -54,7 +55,7 @@ TcpConnection& TcpConnection::operator=(TcpConnection&& other) {
|
|||
assert(contextPair.readContext == nullptr);
|
||||
assert(contextPair.writeContext == nullptr);
|
||||
if (close(connection) == -1) {
|
||||
throw std::runtime_error("TcpConnection::operator=, close() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::operator=, close failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +82,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
ssize_t transferred = ::recv(connection, (void *)data, size, 0);
|
||||
if (transferred == -1) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
message = "recv failed, errno=" + std::to_string(errno);
|
||||
message = "recv failed, " + lastErrorMessage();
|
||||
} else {
|
||||
epoll_event connectionEvent;
|
||||
OperationContext operationContext;
|
||||
|
@ -97,7 +98,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
}
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) {
|
||||
message = "epoll_ctl() failed, errno=" + std::to_string(errno);
|
||||
message = "epoll_ctl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
dispatcher->getCurrentContext()->interruptProcedure = [&]() {
|
||||
assert(dispatcher != nullptr);
|
||||
|
@ -107,7 +108,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
connectionEvent.data.ptr = nullptr;
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) {
|
||||
throw std::runtime_error("TcpConnection::stop, epoll_ctl() fail, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::stop, epoll_ctl failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
contextPair.readContext->interrupted = true;
|
||||
|
@ -132,7 +133,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
connectionEvent.data.ptr = &contextPair;
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) {
|
||||
message = "epoll_ctl() failed, errno=" + std::to_string(errno);
|
||||
message = "epoll_ctl failed, " + lastErrorMessage();
|
||||
throw std::runtime_error("TcpConnection::read");
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +144,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
|
||||
ssize_t transferred = ::recv(connection, (void *)data, size, 0);
|
||||
if (transferred == -1) {
|
||||
message = "recv failed, errno=" + std::to_string(errno);
|
||||
message = "recv failed, " + lastErrorMessage();
|
||||
} else {
|
||||
assert(transferred <= static_cast<ssize_t>(size));
|
||||
return transferred;
|
||||
|
@ -168,7 +169,7 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
std::string message;
|
||||
if(size == 0) {
|
||||
if(shutdown(connection, SHUT_WR) == -1) {
|
||||
throw std::runtime_error("TcpConnection::write, shutdown failed, result=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::write, shutdown failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -177,7 +178,7 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
ssize_t transferred = ::send(connection, (void *)data, size, MSG_NOSIGNAL);
|
||||
if (transferred == -1) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
message = "send failed, result=" + std::to_string(errno);
|
||||
message = "send failed, " + lastErrorMessage();
|
||||
} else {
|
||||
epoll_event connectionEvent;
|
||||
OperationContext operationContext;
|
||||
|
@ -193,7 +194,7 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
}
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) {
|
||||
message = "epoll_ctl() failed, errno=" + std::to_string(errno);
|
||||
message = "epoll_ctl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
dispatcher->getCurrentContext()->interruptProcedure = [&]() {
|
||||
assert(dispatcher != nullptr);
|
||||
|
@ -203,7 +204,7 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
connectionEvent.data.ptr = nullptr;
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) {
|
||||
throw std::runtime_error("TcpConnection::stop, epoll_ctl() fail" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::stop, epoll_ctl failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
contextPair.writeContext->interrupted = true;
|
||||
|
@ -228,18 +229,18 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
connectionEvent.data.ptr = &contextPair;
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) {
|
||||
message = "epoll_ctl() failed, errno=" + std::to_string(errno);
|
||||
message = "epoll_ctl failed, " + lastErrorMessage();
|
||||
throw std::runtime_error("TcpConnection::write, " + message);
|
||||
}
|
||||
}
|
||||
|
||||
if((operationContext.events & (EPOLLERR | EPOLLHUP)) != 0) {
|
||||
throw std::runtime_error("TcpConnection::write: events & (EPOLLERR | EPOLLHUP) != 0");
|
||||
throw std::runtime_error("TcpConnection::write, events & (EPOLLERR | EPOLLHUP) != 0");
|
||||
}
|
||||
|
||||
ssize_t transferred = ::send(connection, (void *)data, size, 0);
|
||||
if (transferred == -1) {
|
||||
message = "send failed, errno=" + std::to_string(errno);
|
||||
message = "send failed, " + lastErrorMessage();
|
||||
} else {
|
||||
assert(transferred <= static_cast<ssize_t>(size));
|
||||
return transferred;
|
||||
|
@ -258,7 +259,7 @@ std::pair<Ipv4Address, uint16_t> TcpConnection::getPeerAddressAndPort() const {
|
|||
sockaddr_in addr;
|
||||
socklen_t size = sizeof(addr);
|
||||
if (getpeername(connection, reinterpret_cast<sockaddr*>(&addr), &size) != 0) {
|
||||
throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
assert(size == sizeof(sockaddr_in));
|
||||
|
@ -273,7 +274,7 @@ TcpConnection::TcpConnection(Dispatcher& dispatcher, int socket) : dispatcher(&d
|
|||
connectionEvent.data.ptr = nullptr;
|
||||
|
||||
if (epoll_ctl(dispatcher.getEpoll(), EPOLL_CTL_ADD, socket, &connectionEvent) == -1) {
|
||||
throw std::runtime_error("TcpConnection::TcpConnection, epoll_ctl() fail, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::TcpConnection, epoll_ctl failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
#include "Dispatcher.h"
|
||||
#include "ErrorMessage.h"
|
||||
#include "TcpConnection.h"
|
||||
|
||||
namespace System {
|
||||
|
@ -77,18 +78,18 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
std::string message;
|
||||
int connection = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (connection == -1) {
|
||||
message = "socket() failed, errno=" + std::to_string(errno);
|
||||
message = "socket failed, " + lastErrorMessage();
|
||||
} else {
|
||||
sockaddr_in bindAddress;
|
||||
bindAddress.sin_family = AF_INET;
|
||||
bindAddress.sin_port = 0;
|
||||
bindAddress.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(connection, reinterpret_cast<sockaddr*>(&bindAddress), sizeof bindAddress) != 0) {
|
||||
message = "bind failed, errno=" + std::to_string(errno);
|
||||
message = "bind failed, " + lastErrorMessage();
|
||||
} else {
|
||||
int flags = fcntl(connection, F_GETFL, 0);
|
||||
if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
message = "fcntl() failed errno=" + std::to_string(errno);
|
||||
message = "fcntl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
sockaddr_in addressData;
|
||||
addressData.sin_family = AF_INET;
|
||||
|
@ -111,14 +112,14 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
connectEvent.events = EPOLLOUT | EPOLLRDHUP | EPOLLERR | EPOLLONESHOT;
|
||||
connectEvent.data.ptr = &contextPair;
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_ADD, connection, &connectEvent) == -1) {
|
||||
message = "epoll_ctl() failed, errno=" + std::to_string(errno);
|
||||
message = "epoll_ctl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
context = &connectorContext;
|
||||
dispatcher->getCurrentContext()->interruptProcedure = [&] {
|
||||
TcpConnectorContextExt* connectorContext1 = static_cast<TcpConnectorContextExt*>(context);
|
||||
if (!connectorContext1->interrupted) {
|
||||
if (close(connectorContext1->connection) == -1) {
|
||||
throw std::runtime_error("TcpListener::stop, close failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpListener::stop, close failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
connectorContext1->interrupted = true;
|
||||
|
@ -139,7 +140,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
}
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_DEL, connection, NULL) == -1) {
|
||||
message = "epoll_ctl() failed, errno=" + std::to_string(errno);
|
||||
message = "epoll_ctl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
if((connectorContext.events & (EPOLLERR | EPOLLHUP)) != 0) {
|
||||
int result = close(connection);
|
||||
|
@ -152,10 +153,10 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
socklen_t retValLen = sizeof(retval);
|
||||
int s = getsockopt(connection, SOL_SOCKET, SO_ERROR, &retval, &retValLen);
|
||||
if (s == -1) {
|
||||
message = "getsockopt() failed, errno=" + std::to_string(errno);
|
||||
message = "getsockopt failed, " + lastErrorMessage();
|
||||
} else {
|
||||
if (retval != 0) {
|
||||
message = "connect failed; getsockopt retval =" + std::to_string(errno);
|
||||
message = "getsockopt failed, " + lastErrorMessage();
|
||||
} else {
|
||||
return TcpConnection(*dispatcher, connection);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "Dispatcher.h"
|
||||
#include "TcpConnection.h"
|
||||
#include <System/ErrorMessage.h>
|
||||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
|
||||
|
@ -39,31 +40,31 @@ TcpListener::TcpListener(Dispatcher& dispatcher, const Ipv4Address& addr, uint16
|
|||
std::string message;
|
||||
listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (listener == -1) {
|
||||
message = "socket() failed, errno=" + std::to_string(errno) + ": " + strerror(errno);
|
||||
message = "socket failed, " + lastErrorMessage();
|
||||
} else {
|
||||
int flags = fcntl(listener, F_GETFL, 0);
|
||||
if (flags == -1 || fcntl(listener, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
message = "fcntl() failed errno=" + std::to_string(errno) + ": " + strerror(errno);
|
||||
message = "fcntl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
int on = 1;
|
||||
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) == -1) {
|
||||
message = "setsockopt failed, errno=" + std::to_string(errno) + ": " + strerror(errno);
|
||||
message = "setsockopt failed, " + lastErrorMessage();
|
||||
} else {
|
||||
sockaddr_in address;
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(port);
|
||||
address.sin_addr.s_addr = htonl( addr.getValue());
|
||||
if (bind(listener, reinterpret_cast<sockaddr *>(&address), sizeof address) != 0) {
|
||||
message = "bind failed, errno=" + std::to_string(errno) + ": " + strerror(errno);
|
||||
message = "bind failed, " + lastErrorMessage();
|
||||
} else if (listen(listener, SOMAXCONN) != 0) {
|
||||
message = "listen failed, errno=" + std::to_string(errno) + ": " + strerror(errno);
|
||||
message = "listen failed, " + lastErrorMessage();
|
||||
} else {
|
||||
epoll_event listenEvent;
|
||||
listenEvent.events = 0;
|
||||
listenEvent.data.ptr = nullptr;
|
||||
|
||||
if (epoll_ctl(dispatcher.getEpoll(), EPOLL_CTL_ADD, listener, &listenEvent) == -1) {
|
||||
message = "epoll_ctl() failed, errno=" + std::to_string(errno) + ": " + strerror(errno);
|
||||
message = "epoll_ctl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
context = nullptr;
|
||||
return;
|
||||
|
@ -100,7 +101,7 @@ TcpListener& TcpListener::operator=(TcpListener&& other) {
|
|||
if (dispatcher != nullptr) {
|
||||
assert(context == nullptr);
|
||||
if (close(listener) == -1) {
|
||||
throw std::runtime_error("TcpListener::operator=, close failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpListener::operator=, close failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,7 +136,7 @@ TcpConnection TcpListener::accept() {
|
|||
listenEvent.data.ptr = &contextPair;
|
||||
std::string message;
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, listener, &listenEvent) == -1) {
|
||||
message = "epoll_ctl() failed, errno=" + std::to_string(errno);
|
||||
message = "epoll_ctl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
context = &listenerContext;
|
||||
dispatcher->getCurrentContext()->interruptProcedure = [&]() {
|
||||
|
@ -148,7 +149,7 @@ TcpConnection TcpListener::accept() {
|
|||
listenEvent.data.ptr = nullptr;
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, listener, &listenEvent) == -1) {
|
||||
throw std::runtime_error("TcpListener::stop, epoll_ctl() failed, errno=" + std::to_string(errno) );
|
||||
throw std::runtime_error("TcpListener::stop, epoll_ctl failed, " + lastErrorMessage() );
|
||||
}
|
||||
|
||||
listenerContext->interrupted = true;
|
||||
|
@ -176,11 +177,11 @@ TcpConnection TcpListener::accept() {
|
|||
socklen_t inLen = sizeof(inAddr);
|
||||
int connection = ::accept(listener, &inAddr, &inLen);
|
||||
if (connection == -1) {
|
||||
message = "accept() failed, errno=" + std::to_string(errno);
|
||||
message = "accept failed, " + lastErrorMessage();
|
||||
} else {
|
||||
int flags = fcntl(connection, F_GETFL, 0);
|
||||
if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
message = "fcntl() failed errno=" + std::to_string(errno);
|
||||
message = "fcntl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
return TcpConnection(*dispatcher, connection);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "Dispatcher.h"
|
||||
#include <System/ErrorMessage.h>
|
||||
#include <System/InterruptedException.h>
|
||||
|
||||
namespace System {
|
||||
|
@ -92,7 +93,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) {
|
|||
timerEvent.data.ptr = &contextPair;
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, timer, &timerEvent) == -1) {
|
||||
throw std::runtime_error("Timer::sleep, epoll_ctl() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Timer::sleep, epoll_ctl failed, " + lastErrorMessage());
|
||||
}
|
||||
dispatcher->getCurrentContext()->interruptProcedure = [&]() {
|
||||
assert(dispatcher != nullptr);
|
||||
|
@ -105,7 +106,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) {
|
|||
timerContext->interrupted = true;
|
||||
dispatcher->pushContext(timerContext->context);
|
||||
} else {
|
||||
throw std::runtime_error("Timer::interrupt, read failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Timer::interrupt, read failed, " + lastErrorMessage());
|
||||
}
|
||||
} else {
|
||||
assert(value>0);
|
||||
|
@ -117,7 +118,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) {
|
|||
timerEvent.data.ptr = nullptr;
|
||||
|
||||
if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, timer, &timerEvent) == -1) {
|
||||
throw std::runtime_error("Timer::interrupt epoll_ctl() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Timer::interrupt, epoll_ctl failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "Context.h"
|
||||
#include "ErrorMessage.h"
|
||||
|
||||
namespace System {
|
||||
|
||||
|
@ -42,7 +43,7 @@ public:
|
|||
MutextGuard(pthread_mutex_t& _mutex) : mutex(_mutex) {
|
||||
auto ret = pthread_mutex_lock(&mutex);
|
||||
if (ret != 0) {
|
||||
throw std::runtime_error("failed to acquire mutex, errno=" + std::to_string(ret) + ": " + strerror(ret));
|
||||
throw std::runtime_error("MutextGuard::MutextGuard, pthread_mutex_lock failed, " + errorMessage(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,19 +65,19 @@ Dispatcher::Dispatcher() : lastCreatedTimer(0) {
|
|||
std::string message;
|
||||
kqueue = ::kqueue();
|
||||
if (kqueue == -1) {
|
||||
message = "kqueue() fail errno=" + std::to_string(errno);
|
||||
message = "kqueue failed, " + lastErrorMessage();
|
||||
} else {
|
||||
mainContext.uctx = new uctx;
|
||||
if (getcontext(static_cast<uctx*>(mainContext.uctx)) == -1) {
|
||||
message = "getcontext() fail errno=" + std::to_string(errno);
|
||||
message = "getcontext failed, " + lastErrorMessage();
|
||||
} else {
|
||||
struct kevent event;
|
||||
EV_SET(&event, 0, EVFILT_USER, EV_ADD, NOTE_FFNOP, 0, NULL);
|
||||
if (kevent(kqueue, &event, 1, NULL, 0, NULL) == -1) {
|
||||
message = "kevent() fail errno=" + std::to_string(errno);
|
||||
message = "kevent failed, " + lastErrorMessage();
|
||||
} else {
|
||||
if(pthread_mutex_init(reinterpret_cast<pthread_mutex_t*>(this->mutex), NULL) == -1) {
|
||||
message = "pthread_mutex_init() fail errno=" + std::to_string(errno);
|
||||
message = "pthread_mutex_init failed, " + lastErrorMessage();
|
||||
} else {
|
||||
remoteSpawned = false;
|
||||
|
||||
|
@ -165,7 +166,7 @@ void Dispatcher::dispatch() {
|
|||
struct kevent event;
|
||||
EV_SET(&event, 0, EVFILT_USER, EV_ADD | EV_DISABLE, NOTE_FFNOP, 0, NULL);
|
||||
if (kevent(kqueue, &event, 1, NULL, 0, NULL) == -1) {
|
||||
throw std::runtime_error("kevent() fail errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::dispatch, kevent failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
continue;
|
||||
|
@ -176,7 +177,7 @@ void Dispatcher::dispatch() {
|
|||
}
|
||||
|
||||
if (errno != EINTR) {
|
||||
throw std::runtime_error("Dispatcher::dispatch(), kqueue() fail errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::dispatch, kqueue failed, " + lastErrorMessage());
|
||||
} else {
|
||||
MutextGuard guard(*reinterpret_cast<pthread_mutex_t*>(this->mutex));
|
||||
while (!remoteSpawningProcedures.empty()) {
|
||||
|
@ -191,7 +192,7 @@ void Dispatcher::dispatch() {
|
|||
uctx* oldContext = static_cast<uctx*>(currentContext->uctx);
|
||||
currentContext = context;
|
||||
if (swapcontext(oldContext,static_cast<uctx*>(currentContext->uctx)) == -1) {
|
||||
throw std::runtime_error("Dispatcher::dispatch(), swapcontext() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::dispatch, swapcontext failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +247,7 @@ void Dispatcher::remoteSpawn(std::function<void()>&& procedure) {
|
|||
struct kevent event;
|
||||
EV_SET(&event, 0, EVFILT_USER, EV_ADD | EV_ENABLE, NOTE_FFCOPY | NOTE_TRIGGER, 0, NULL);
|
||||
if (kevent(kqueue, &event, 1, NULL, 0, NULL) == -1) {
|
||||
throw std::runtime_error("Dispatcher::remoteSpawn(), kevent() fail errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::remoteSpawn, kevent failed, " + lastErrorMessage());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -286,7 +287,7 @@ void Dispatcher::yield() {
|
|||
struct kevent event;
|
||||
EV_SET(&event, 0, EVFILT_USER, EV_ADD | EV_DISABLE, NOTE_FFNOP, 0, NULL);
|
||||
if (kevent(kqueue, &event, 1, NULL, 0, NULL) == -1) {
|
||||
throw std::runtime_error("kevent() fail errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::yield, kevent failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
MutextGuard guard(*reinterpret_cast<pthread_mutex_t*>(this->mutex));
|
||||
|
@ -304,7 +305,7 @@ void Dispatcher::yield() {
|
|||
}
|
||||
} else {
|
||||
if (errno != EINTR) {
|
||||
throw std::runtime_error("Dispatcher::dispatch(), epoll_wait() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::dispatch, kevent failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -331,7 +332,7 @@ NativeContext& Dispatcher::getReusableContext() {
|
|||
|
||||
uctx* oldContext = static_cast<uctx*>(currentContext->uctx);
|
||||
if (swapcontext(oldContext, newlyCreatedContext) == -1) {
|
||||
throw std::runtime_error("Dispatcher::getReusableContext(), swapcontext() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::getReusableContext, swapcontext failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
assert(firstReusableContext != nullptr);
|
||||
|
@ -375,7 +376,7 @@ void Dispatcher::contextProcedure(void* ucontext) {
|
|||
firstReusableContext = &context;
|
||||
uctx* oldContext = static_cast<uctx*>(context.uctx);
|
||||
if (swapcontext(oldContext, static_cast<uctx*>(currentContext->uctx)) == -1) {
|
||||
throw std::runtime_error("Dispatcher::contextProcedure() swapcontext() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Dispatcher::contextProcedure, swapcontext failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
|
32
src/Platform/OSX/System/ErrorMessage.cpp
Normal file
32
src/Platform/OSX/System/ErrorMessage.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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 "ErrorMessage.h"
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
namespace System {
|
||||
|
||||
std::string lastErrorMessage() {
|
||||
return errorMessage(errno);
|
||||
}
|
||||
|
||||
std::string errorMessage(int err) {
|
||||
return "result=" + std::to_string(err) + ", " + std::strerror(err);
|
||||
}
|
||||
|
||||
}
|
25
src/Platform/OSX/System/ErrorMessage.h
Normal file
25
src/Platform/OSX/System/ErrorMessage.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
// 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace System {
|
||||
std::string lastErrorMessage();
|
||||
std::string errorMessage(int);
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include <netdb.h>
|
||||
|
||||
#include <System/Dispatcher.h>
|
||||
#include <System/ErrorMessage.h>
|
||||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
|
||||
|
@ -62,7 +63,7 @@ Ipv4Address Ipv4Resolver::resolve(const std::string& host) {
|
|||
addrinfo* addressInfos;
|
||||
int result = getaddrinfo(host.c_str(), NULL, &hints, &addressInfos);
|
||||
if (result != 0) {
|
||||
throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, result=" + std::to_string(result));
|
||||
throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, " + errorMessage(result));
|
||||
}
|
||||
|
||||
std::size_t count = 0;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "Dispatcher.h"
|
||||
#include <System/ErrorMessage.h>
|
||||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
|
||||
|
@ -58,7 +59,7 @@ TcpConnection& TcpConnection::operator=(TcpConnection&& other) {
|
|||
assert(readContext == nullptr);
|
||||
assert(writeContext == nullptr);
|
||||
if (close(connection) == -1) {
|
||||
throw std::runtime_error("TcpConnection::operator=, close() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::operator=, close failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +87,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
ssize_t transferred = ::recv(connection, (void *)data, size, 0);
|
||||
if (transferred == -1) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
message = "recv failed, errno=" + std::to_string(errno);
|
||||
message = "recv failed, " + lastErrorMessage();
|
||||
} else {
|
||||
OperationContext context;
|
||||
context.context = dispatcher->getCurrentContext();
|
||||
|
@ -94,7 +95,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
struct kevent event;
|
||||
EV_SET(&event, connection, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR | EV_ONESHOT, 0, 0, &context);
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
message = "kevent() failed, errno=" + std::to_string(errno);
|
||||
message = "kevent failed, " + lastErrorMessage();
|
||||
} else {
|
||||
readContext = &context;
|
||||
dispatcher->getCurrentContext()->interruptProcedure = [&] {
|
||||
|
@ -106,7 +107,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
EV_SET(&event, connection, EVFILT_READ, EV_DELETE | EV_DISABLE, 0, 0, NULL);
|
||||
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
throw std::runtime_error("TcpListener::interruptionProcedure, kevent() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpListener::interruptionProcedure, kevent failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
context->interrupted = true;
|
||||
|
@ -127,7 +128,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
|
||||
ssize_t transferred = ::recv(connection, (void *)data, size, 0);
|
||||
if (transferred == -1) {
|
||||
message = "recv failed, errno=" + std::to_string(errno);
|
||||
message = "recv failed, " + lastErrorMessage();
|
||||
} else {
|
||||
assert(transferred <= static_cast<ssize_t>(size));
|
||||
return transferred;
|
||||
|
@ -152,7 +153,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
std::string message;
|
||||
if (size == 0) {
|
||||
if (shutdown(connection, SHUT_WR) == -1) {
|
||||
throw std::runtime_error("TcpConnection::write, shutdown failed, result=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::write, shutdown failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -161,7 +162,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
ssize_t transferred = ::send(connection, (void *)data, size, 0);
|
||||
if (transferred == -1) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
message = "send failed, result=" + std::to_string(errno);
|
||||
message = "send failed, " + lastErrorMessage();
|
||||
} else {
|
||||
OperationContext context;
|
||||
context.context = dispatcher->getCurrentContext();
|
||||
|
@ -169,7 +170,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
struct kevent event;
|
||||
EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, &context);
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
message = "kevent() failed, errno=" + std::to_string(errno);
|
||||
message = "kevent failed, " + lastErrorMessage();
|
||||
} else {
|
||||
writeContext = &context;
|
||||
dispatcher->getCurrentContext()->interruptProcedure = [&] {
|
||||
|
@ -181,7 +182,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
EV_SET(&event, connection, EVFILT_WRITE, EV_DELETE | EV_DISABLE, 0, 0, NULL);
|
||||
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
throw std::runtime_error("TcpListener::stop, kevent() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpListener::stop, kevent failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
context->interrupted = true;
|
||||
|
@ -202,7 +203,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
|
||||
ssize_t transferred = ::send(connection, (void *)data, size, 0);
|
||||
if (transferred == -1) {
|
||||
message = "send failed, errno=" + std::to_string(errno);
|
||||
message = "send failed, " + lastErrorMessage();
|
||||
} else {
|
||||
assert(transferred <= static_cast<ssize_t>(size));
|
||||
return transferred;
|
||||
|
@ -221,7 +222,7 @@ std::pair<Ipv4Address, uint16_t> TcpConnection::getPeerAddressAndPort() const {
|
|||
sockaddr_in addr;
|
||||
socklen_t size = sizeof(addr);
|
||||
if (getpeername(connection, reinterpret_cast<sockaddr*>(&addr), &size) != 0) {
|
||||
throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, result=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
assert(size == sizeof(sockaddr_in));
|
||||
|
@ -231,7 +232,7 @@ std::pair<Ipv4Address, uint16_t> TcpConnection::getPeerAddressAndPort() const {
|
|||
TcpConnection::TcpConnection(Dispatcher& dispatcher, int socket) : dispatcher(&dispatcher), connection(socket), readContext(nullptr), writeContext(nullptr) {
|
||||
int val = 1;
|
||||
if (setsockopt(connection, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof val) == -1) {
|
||||
throw std::runtime_error("TcpConnection::TcpConnection, setsockopt failed, result=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpConnection::TcpConnection, setsockopt failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
#include "Dispatcher.h"
|
||||
#include "ErrorMessage.h"
|
||||
#include "TcpConnection.h"
|
||||
|
||||
namespace System {
|
||||
|
@ -80,18 +81,18 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
std::string message;
|
||||
int connection = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (connection == -1) {
|
||||
message = "socket() failed, errno=" + std::to_string(errno);
|
||||
message = "socket failed, " + lastErrorMessage();
|
||||
} else {
|
||||
sockaddr_in bindAddress;
|
||||
bindAddress.sin_family = AF_INET;
|
||||
bindAddress.sin_port = 0;
|
||||
bindAddress.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(connection, reinterpret_cast<sockaddr*>(&bindAddress), sizeof bindAddress) != 0) {
|
||||
message = "bind failed, errno=" + std::to_string(errno);
|
||||
message = "bind failed, " + lastErrorMessage();
|
||||
} else {
|
||||
int flags = fcntl(connection, F_GETFL, 0);
|
||||
if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
message = "fcntl() failed errno=" + std::to_string(errno);
|
||||
message = "fcntl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
sockaddr_in addressData;
|
||||
addressData.sin_family = AF_INET;
|
||||
|
@ -108,7 +109,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
struct kevent event;
|
||||
EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT | EV_CLEAR, 0, 0, &connectorContext);
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
message = "kevent() failed, errno=" + std::to_string(errno);
|
||||
message = "kevent failed, " + lastErrorMessage();
|
||||
} else {
|
||||
context = &connectorContext;
|
||||
dispatcher->getCurrentContext()->interruptProcedure = [&] {
|
||||
|
@ -117,7 +118,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
ConnectorContext* connectorContext = static_cast<ConnectorContext*>(context);
|
||||
if (!connectorContext->interrupted) {
|
||||
if (close(connectorContext->connection) == -1) {
|
||||
throw std::runtime_error("TcpListener::stop, close failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpListener::stop, close failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
dispatcher->pushContext(connectorContext->context);
|
||||
|
@ -140,16 +141,16 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_DISABLE, 0, 0, NULL);
|
||||
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
message = "kevent() failed, errno=" + std::to_string(errno);
|
||||
message = "kevent failed, " + lastErrorMessage();
|
||||
} else {
|
||||
int retval = -1;
|
||||
socklen_t retValLen = sizeof(retval);
|
||||
int s = getsockopt(connection, SOL_SOCKET, SO_ERROR, &retval, &retValLen);
|
||||
if (s == -1) {
|
||||
message = "getsockopt() failed, errno=" + std::to_string(errno);
|
||||
message = "getsockopt failed, " + lastErrorMessage();
|
||||
} else {
|
||||
if (retval != 0) {
|
||||
message = "connect failed; getsockopt retval =" + std::to_string(errno);
|
||||
message = "getsockopt failed, " + lastErrorMessage();
|
||||
} else {
|
||||
return TcpConnection(*dispatcher, connection);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "Dispatcher.h"
|
||||
#include "TcpConnection.h"
|
||||
#include <System/ErrorMessage.h>
|
||||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
|
||||
|
@ -41,30 +42,30 @@ TcpListener::TcpListener(Dispatcher& dispatcher, const Ipv4Address& addr, uint16
|
|||
std::string message;
|
||||
listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (listener == -1) {
|
||||
message = "socket() failed, errno=" + std::to_string(errno);
|
||||
message = "socket failed, " + lastErrorMessage();
|
||||
} else {
|
||||
int flags = fcntl(listener, F_GETFL, 0);
|
||||
if (flags == -1 || (fcntl(listener, F_SETFL, flags | O_NONBLOCK) == -1)) {
|
||||
message = "fcntl() failed errno=" + std::to_string(errno);
|
||||
message = "fcntl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
int on = 1;
|
||||
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) == -1) {
|
||||
message = "setsockopt failed, errno=" + std::to_string(errno);
|
||||
message = "setsockopt failed, " + lastErrorMessage();
|
||||
} else {
|
||||
sockaddr_in address;
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(port);
|
||||
address.sin_addr.s_addr = htonl(addr.getValue());
|
||||
if (bind(listener, reinterpret_cast<sockaddr*>(&address), sizeof address) != 0) {
|
||||
message = "bind failed, errno=" + std::to_string(errno);
|
||||
message = "bind failed, " + lastErrorMessage();
|
||||
} else if (listen(listener, SOMAXCONN) != 0) {
|
||||
message = "listen failed, errno=" + std::to_string(errno);
|
||||
message = "listen failed, " + lastErrorMessage();
|
||||
} else {
|
||||
struct kevent event;
|
||||
EV_SET(&event, listener, EVFILT_READ, EV_ADD | EV_DISABLE | EV_CLEAR, 0, SOMAXCONN, NULL);
|
||||
|
||||
if (kevent(dispatcher.getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
message = "kevent() failed, errno=" + std::to_string(errno);
|
||||
message = "kevent failed, " + lastErrorMessage();
|
||||
} else {
|
||||
context = nullptr;
|
||||
return;
|
||||
|
@ -74,7 +75,7 @@ TcpListener::TcpListener(Dispatcher& dispatcher, const Ipv4Address& addr, uint16
|
|||
}
|
||||
|
||||
if (close(listener) == -1) {
|
||||
message = "close failed, errno=" + std::to_string(errno);
|
||||
message = "close failed, " + lastErrorMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +103,7 @@ TcpListener& TcpListener::operator=(TcpListener&& other) {
|
|||
if (dispatcher != nullptr) {
|
||||
assert(context == nullptr);
|
||||
if (close(listener) == -1) {
|
||||
throw std::runtime_error("TcpListener::operator=, close failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpListener::operator=, close failed, " + lastErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +132,7 @@ TcpConnection TcpListener::accept() {
|
|||
struct kevent event;
|
||||
EV_SET(&event, listener, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR , 0, SOMAXCONN, &listenerContext);
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
message = "kevent() failed, errno=" + std::to_string(errno);
|
||||
message = "kevent failed, " + lastErrorMessage();
|
||||
} else {
|
||||
context = &listenerContext;
|
||||
dispatcher->getCurrentContext()->interruptProcedure = [&] {
|
||||
|
@ -144,7 +145,7 @@ TcpConnection TcpListener::accept() {
|
|||
EV_SET(&event, listener, EVFILT_READ, EV_DELETE | EV_DISABLE, 0, 0, NULL);
|
||||
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
throw std::runtime_error("TcpListener::stop, kevent() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("TcpListener::stop, kevent failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
listenerContext->interrupted = true;
|
||||
|
@ -167,11 +168,11 @@ TcpConnection TcpListener::accept() {
|
|||
socklen_t inLen = sizeof(inAddr);
|
||||
int connection = ::accept(listener, &inAddr, &inLen);
|
||||
if (connection == -1) {
|
||||
message = "accept() failed, errno=" + std::to_string(errno);
|
||||
message = "accept failed, " + lastErrorMessage();
|
||||
} else {
|
||||
int flags = fcntl(connection, F_GETFL, 0);
|
||||
if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
message = "fcntl() failed errno=" + std::to_string(errno);
|
||||
message = "fcntl failed, " + lastErrorMessage();
|
||||
} else {
|
||||
return TcpConnection(*dispatcher, connection);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "Dispatcher.h"
|
||||
#include <System/ErrorMessage.h>
|
||||
#include <System/InterruptedException.h>
|
||||
|
||||
namespace System {
|
||||
|
@ -79,7 +80,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) {
|
|||
EV_SET(&event, timer, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_NSECONDS, duration.count(), &timerContext);
|
||||
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
throw std::runtime_error("Timer::stop, kevent() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Timer::stop, kevent failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
context = &timerContext;
|
||||
|
@ -92,7 +93,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) {
|
|||
EV_SET(&event, timer, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
|
||||
|
||||
if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) {
|
||||
throw std::runtime_error("Timer::stop, kevent() failed, errno=" + std::to_string(errno));
|
||||
throw std::runtime_error("Timer::stop, kevent failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
dispatcher->pushContext(timerContext->context);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#define NOMINMAX
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#include "ErrorMessage.h"
|
||||
|
||||
namespace System {
|
||||
|
||||
|
@ -44,16 +45,16 @@ Dispatcher::Dispatcher() {
|
|||
assert(result != FALSE);
|
||||
std::string message;
|
||||
if (ConvertThreadToFiberEx(NULL, 0) == NULL) {
|
||||
message = "ConvertThreadToFiberEx failed, result=" + std::to_string(GetLastError());
|
||||
message = "ConvertThreadToFiberEx failed, " + lastErrorMessage();
|
||||
} else {
|
||||
completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
||||
if (completionPort == NULL) {
|
||||
message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError());
|
||||
message = "CreateIoCompletionPort failed, " + lastErrorMessage();
|
||||
} else {
|
||||
WSADATA wsaData;
|
||||
int wsaResult = WSAStartup(0x0202, &wsaData);
|
||||
if (wsaResult != 0) {
|
||||
message = "WSAStartup failed, result=" + std::to_string(wsaResult);
|
||||
message = "WSAStartup failed, " + errorMessage(wsaResult);
|
||||
} else {
|
||||
remoteNotificationSent = false;
|
||||
reinterpret_cast<LPOVERLAPPED>(remoteSpawnOverlapped)->hEvent = NULL;
|
||||
|
@ -179,7 +180,7 @@ void Dispatcher::dispatch() {
|
|||
}
|
||||
|
||||
if (lastError != WAIT_IO_COMPLETION) {
|
||||
throw std::runtime_error("Dispatcher::dispatch, GetQueuedCompletionStatusEx failed, result=" + std::to_string(lastError));
|
||||
throw std::runtime_error("Dispatcher::dispatch, GetQueuedCompletionStatusEx failed, " + errorMessage(lastError));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,7 +242,7 @@ void Dispatcher::remoteSpawn(std::function<void()>&& procedure) {
|
|||
remoteNotificationSent = true;
|
||||
if (PostQueuedCompletionStatus(completionPort, 0, 0, reinterpret_cast<LPOVERLAPPED>(remoteSpawnOverlapped)) == NULL) {
|
||||
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(criticalSection));
|
||||
throw std::runtime_error("Dispatcher::remoteSpawn, PostQueuedCompletionStatus failed, result=" + std::to_string(GetLastError()));
|
||||
throw std::runtime_error("Dispatcher::remoteSpawn, PostQueuedCompletionStatus failed, " + lastErrorMessage());
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -313,7 +314,7 @@ void Dispatcher::yield() {
|
|||
if (lastError == WAIT_TIMEOUT) {
|
||||
break;
|
||||
} else if (lastError != WAIT_IO_COMPLETION) {
|
||||
throw std::runtime_error("Dispatcher::yield, GetQueuedCompletionStatusEx failed, result=" + std::to_string(lastError));
|
||||
throw std::runtime_error("Dispatcher::yield, GetQueuedCompletionStatusEx failed, " + errorMessage(lastError));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -337,7 +338,7 @@ NativeContext& Dispatcher::getReusableContext() {
|
|||
if (firstReusableContext == nullptr) {
|
||||
void* fiber = CreateFiberEx(STACK_SIZE, RESERVE_STACK_SIZE, 0, contextProcedureStatic, this);
|
||||
if (fiber == NULL) {
|
||||
throw std::runtime_error("Dispatcher::getReusableContext, CreateFiberEx failed, result=" + std::to_string(GetLastError()));
|
||||
throw std::runtime_error("Dispatcher::getReusableContext, CreateFiberEx failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
SwitchToFiber(fiber);
|
||||
|
|
45
src/Platform/Windows/System/ErrorMessage.cpp
Normal file
45
src/Platform/Windows/System/ErrorMessage.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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 "ErrorMessage.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <windows.h>
|
||||
|
||||
namespace System {
|
||||
|
||||
std::string lastErrorMessage() {
|
||||
return errorMessage(GetLastError());
|
||||
}
|
||||
|
||||
std::string errorMessage(int error) {
|
||||
struct Buffer {
|
||||
~Buffer() {
|
||||
if (pointer != nullptr) {
|
||||
LocalFree(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
LPTSTR pointer = nullptr;
|
||||
} buffer;
|
||||
|
||||
auto size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, error,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPTSTR>(&buffer.pointer), 0, nullptr);
|
||||
return "result=" + std::to_string(error) + ", " + std::string(buffer.pointer, size);
|
||||
}
|
||||
|
||||
}
|
27
src/Platform/Windows/System/ErrorMessage.h
Normal file
27
src/Platform/Windows/System/ErrorMessage.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace System {
|
||||
|
||||
std::string lastErrorMessage();
|
||||
std::string errorMessage(int);
|
||||
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#endif
|
||||
#include <ws2tcpip.h>
|
||||
#include <System/Dispatcher.h>
|
||||
#include <System/ErrorMessage.h>
|
||||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
|
||||
|
@ -62,7 +63,7 @@ Ipv4Address Ipv4Resolver::resolve(const std::string& host) {
|
|||
addrinfo* addressInfos;
|
||||
int result = getaddrinfo(host.c_str(), NULL, &hints, &addressInfos);
|
||||
if (result != 0) {
|
||||
throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, result=" + std::to_string(result));
|
||||
throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, " + errorMessage(result));
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
#include "Dispatcher.h"
|
||||
#include "ErrorMessage.h"
|
||||
|
||||
namespace System {
|
||||
|
||||
|
@ -65,7 +66,7 @@ TcpConnection& TcpConnection::operator=(TcpConnection&& other) {
|
|||
assert(readContext == nullptr);
|
||||
assert(writeContext == nullptr);
|
||||
if (closesocket(connection) != 0) {
|
||||
throw std::runtime_error("TcpConnection::operator=, closesocket failed, result=" + std::to_string(WSAGetLastError()));
|
||||
throw std::runtime_error("TcpConnection::operator=, closesocket failed, " + errorMessage(WSAGetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +97,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
if (WSARecv(connection, &buf, 1, NULL, &flags, &context, NULL) != 0) {
|
||||
int lastError = WSAGetLastError();
|
||||
if (lastError != WSA_IO_PENDING) {
|
||||
throw std::runtime_error("TcpConnection::read, WSARecv failed, result=" + std::to_string(lastError));
|
||||
throw std::runtime_error("TcpConnection::read, WSARecv failed, " + errorMessage(lastError));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +113,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
if (CancelIoEx(reinterpret_cast<HANDLE>(connection), context) != TRUE) {
|
||||
DWORD lastError = GetLastError();
|
||||
if (lastError != ERROR_NOT_FOUND) {
|
||||
throw std::runtime_error("TcpConnection::stop, CancelIoEx failed, result=" + std::to_string(GetLastError()));
|
||||
throw std::runtime_error("TcpConnection::stop, CancelIoEx failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
context->context->interrupted = true;
|
||||
|
@ -132,7 +133,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
|
|||
if (WSAGetOverlappedResult(connection, &context, &transferred, FALSE, &flags) != TRUE) {
|
||||
int lastError = WSAGetLastError();
|
||||
if (lastError != ERROR_OPERATION_ABORTED) {
|
||||
throw std::runtime_error("TcpConnection::read, WSAGetOverlappedResult failed, result=" + std::to_string(lastError));
|
||||
throw std::runtime_error("TcpConnection::read, WSAGetOverlappedResult failed, " + errorMessage(lastError));
|
||||
}
|
||||
|
||||
assert(context.interrupted);
|
||||
|
@ -153,7 +154,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
|
||||
if (size == 0) {
|
||||
if (shutdown(connection, SD_SEND) != 0) {
|
||||
throw std::runtime_error("TcpConnection::write, shutdown failed, result=" + std::to_string(WSAGetLastError()));
|
||||
throw std::runtime_error("TcpConnection::write, shutdown failed, " + errorMessage(WSAGetLastError()));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -165,7 +166,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
if (WSASend(connection, &buf, 1, NULL, 0, &context, NULL) != 0) {
|
||||
int lastError = WSAGetLastError();
|
||||
if (lastError != WSA_IO_PENDING) {
|
||||
throw std::runtime_error("TcpConnection::write, WSASend failed, result=" + std::to_string(lastError));
|
||||
throw std::runtime_error("TcpConnection::write, WSASend failed, " + errorMessage(lastError));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +181,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
if (CancelIoEx(reinterpret_cast<HANDLE>(connection), context) != TRUE) {
|
||||
DWORD lastError = GetLastError();
|
||||
if (lastError != ERROR_NOT_FOUND) {
|
||||
throw std::runtime_error("TcpConnection::stop, CancelIoEx failed, result=" + std::to_string(GetLastError()));
|
||||
throw std::runtime_error("TcpConnection::stop, CancelIoEx failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
context->context->interrupted = true;
|
||||
|
@ -201,7 +202,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) {
|
|||
if (WSAGetOverlappedResult(connection, &context, &transferred, FALSE, &flags) != TRUE) {
|
||||
int lastError = WSAGetLastError();
|
||||
if (lastError != ERROR_OPERATION_ABORTED) {
|
||||
throw std::runtime_error("TcpConnection::write, WSAGetOverlappedResult failed, result=" + std::to_string(lastError));
|
||||
throw std::runtime_error("TcpConnection::write, WSAGetOverlappedResult failed, " + errorMessage(lastError));
|
||||
}
|
||||
|
||||
assert(context.interrupted);
|
||||
|
@ -217,7 +218,7 @@ std::pair<Ipv4Address, uint16_t> TcpConnection::getPeerAddressAndPort() const {
|
|||
sockaddr_in address;
|
||||
int size = sizeof(address);
|
||||
if (getpeername(connection, reinterpret_cast<sockaddr*>(&address), &size) != 0) {
|
||||
throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, result=" + std::to_string(WSAGetLastError()));
|
||||
throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, " + errorMessage(WSAGetLastError()));
|
||||
}
|
||||
|
||||
assert(size == sizeof(sockaddr_in));
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
#include "Dispatcher.h"
|
||||
#include "ErrorMessage.h"
|
||||
#include "TcpConnection.h"
|
||||
|
||||
namespace System {
|
||||
|
@ -81,23 +82,23 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
std::string message;
|
||||
SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (connection == INVALID_SOCKET) {
|
||||
message = "socket failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "socket failed, " + errorMessage(WSAGetLastError());
|
||||
} else {
|
||||
sockaddr_in bindAddress;
|
||||
bindAddress.sin_family = AF_INET;
|
||||
bindAddress.sin_port = 0;
|
||||
bindAddress.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(connection, reinterpret_cast<sockaddr*>(&bindAddress), sizeof bindAddress) != 0) {
|
||||
message = "bind failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "bind failed, " + errorMessage(WSAGetLastError());
|
||||
} else {
|
||||
GUID guidConnectEx = WSAID_CONNECTEX;
|
||||
DWORD read = sizeof connectEx;
|
||||
if (connectEx == nullptr && WSAIoctl(connection, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidConnectEx, sizeof guidConnectEx, &connectEx, sizeof connectEx, &read, NULL, NULL) != 0) {
|
||||
message = "WSAIoctl failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "WSAIoctl failed, " + errorMessage(WSAGetLastError());
|
||||
} else {
|
||||
assert(read == sizeof connectEx);
|
||||
if (CreateIoCompletionPort(reinterpret_cast<HANDLE>(connection), dispatcher->getCompletionPort(), 0, 0) != dispatcher->getCompletionPort()) {
|
||||
message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError());
|
||||
message = "CreateIoCompletionPort failed, " + lastErrorMessage();
|
||||
} else {
|
||||
sockaddr_in addressData;
|
||||
addressData.sin_family = AF_INET;
|
||||
|
@ -110,7 +111,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
} else {
|
||||
int lastError = WSAGetLastError();
|
||||
if (lastError != WSA_IO_PENDING) {
|
||||
message = "ConnectEx failed, result=" + std::to_string(lastError);
|
||||
message = "ConnectEx failed, " + errorMessage(lastError);
|
||||
} else {
|
||||
context2.context = dispatcher->getCurrentContext();
|
||||
context2.connection = connection;
|
||||
|
@ -124,7 +125,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
if (CancelIoEx(reinterpret_cast<HANDLE>(context2->connection), context2) != TRUE) {
|
||||
DWORD lastError = GetLastError();
|
||||
if (lastError != ERROR_NOT_FOUND) {
|
||||
throw std::runtime_error("TcpConnector::stop, CancelIoEx failed, result=" + std::to_string(GetLastError()));
|
||||
throw std::runtime_error("TcpConnector::stop, CancelIoEx failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
context2->context->interrupted = true;
|
||||
|
@ -146,11 +147,11 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
if (WSAGetOverlappedResult(connection, &context2, &transferred, FALSE, &flags) != TRUE) {
|
||||
lastError = WSAGetLastError();
|
||||
if (lastError != ERROR_OPERATION_ABORTED) {
|
||||
message = "ConnectEx failed, result=" + std::to_string(lastError);
|
||||
message = "ConnectEx failed, " + errorMessage(lastError);
|
||||
} else {
|
||||
assert(context2.interrupted);
|
||||
if (closesocket(connection) != 0) {
|
||||
throw std::runtime_error("TcpConnector::connect, closesocket failed, result=" + std::to_string(WSAGetLastError()));
|
||||
throw std::runtime_error("TcpConnector::connect, closesocket failed, " + errorMessage(WSAGetLastError()));
|
||||
} else {
|
||||
throw InterruptedException();
|
||||
}
|
||||
|
@ -160,7 +161,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) {
|
|||
assert(flags == 0);
|
||||
DWORD value = 1;
|
||||
if (setsockopt(connection, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, reinterpret_cast<char*>(&value), sizeof(value)) != 0) {
|
||||
message = "setsockopt failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "setsockopt failed, " + errorMessage(WSAGetLastError());
|
||||
} else {
|
||||
return TcpConnection(*dispatcher, connection);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <System/InterruptedException.h>
|
||||
#include <System/Ipv4Address.h>
|
||||
#include "Dispatcher.h"
|
||||
#include "ErrorMessage.h"
|
||||
#include "TcpConnection.h"
|
||||
|
||||
namespace System {
|
||||
|
@ -47,25 +48,25 @@ TcpListener::TcpListener(Dispatcher& dispatcher, const Ipv4Address& address, uin
|
|||
std::string message;
|
||||
listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (listener == INVALID_SOCKET) {
|
||||
message = "socket failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "socket failed, " + errorMessage(WSAGetLastError());
|
||||
} else {
|
||||
sockaddr_in addressData;
|
||||
addressData.sin_family = AF_INET;
|
||||
addressData.sin_port = htons(port);
|
||||
addressData.sin_addr.S_un.S_addr = htonl(address.getValue());
|
||||
if (bind(listener, reinterpret_cast<sockaddr*>(&addressData), sizeof(addressData)) != 0) {
|
||||
message = "bind failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "bind failed, " + errorMessage(WSAGetLastError());
|
||||
} else if (listen(listener, SOMAXCONN) != 0) {
|
||||
message = "listen failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "listen failed, " + errorMessage(WSAGetLastError());
|
||||
} else {
|
||||
GUID guidAcceptEx = WSAID_ACCEPTEX;
|
||||
DWORD read = sizeof acceptEx;
|
||||
if (acceptEx == nullptr && WSAIoctl(listener, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx, sizeof guidAcceptEx, &acceptEx, sizeof acceptEx, &read, NULL, NULL) != 0) {
|
||||
message = "WSAIoctl failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "WSAIoctl failed, " + errorMessage(WSAGetLastError());
|
||||
} else {
|
||||
assert(read == sizeof acceptEx);
|
||||
if (CreateIoCompletionPort(reinterpret_cast<HANDLE>(listener), dispatcher.getCompletionPort(), 0, 0) != dispatcher.getCompletionPort()) {
|
||||
message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError());
|
||||
message = "CreateIoCompletionPort failed, " + lastErrorMessage();
|
||||
} else {
|
||||
context = nullptr;
|
||||
return;
|
||||
|
@ -101,7 +102,7 @@ TcpListener& TcpListener::operator=(TcpListener&& other) {
|
|||
if (dispatcher != nullptr) {
|
||||
assert(context == nullptr);
|
||||
if (closesocket(listener) != 0) {
|
||||
throw std::runtime_error("TcpListener::operator=, closesocket failed, result=" + std::to_string(WSAGetLastError()));
|
||||
throw std::runtime_error("TcpListener::operator=, closesocket failed, " + errorMessage(WSAGetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +127,7 @@ TcpConnection TcpListener::accept() {
|
|||
std::string message;
|
||||
SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (connection == INVALID_SOCKET) {
|
||||
message = "socket failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "socket failed, " + errorMessage(WSAGetLastError());
|
||||
} else {
|
||||
uint8_t addresses[sizeof sockaddr_in * 2 + 32];
|
||||
DWORD received;
|
||||
|
@ -137,7 +138,7 @@ TcpConnection TcpListener::accept() {
|
|||
} else {
|
||||
int lastError = WSAGetLastError();
|
||||
if (lastError != WSA_IO_PENDING) {
|
||||
message = "AcceptEx failed, result=" + std::to_string(lastError);
|
||||
message = "AcceptEx failed, " + errorMessage(lastError);
|
||||
} else {
|
||||
context2.context = dispatcher->getCurrentContext();
|
||||
context2.interrupted = false;
|
||||
|
@ -150,7 +151,7 @@ TcpConnection TcpListener::accept() {
|
|||
if (CancelIoEx(reinterpret_cast<HANDLE>(listener), context2) != TRUE) {
|
||||
DWORD lastError = GetLastError();
|
||||
if (lastError != ERROR_NOT_FOUND) {
|
||||
throw std::runtime_error("TcpListener::stop, CancelIoEx failed, result=" + std::to_string(GetLastError()));
|
||||
throw std::runtime_error("TcpListener::stop, CancelIoEx failed, " + lastErrorMessage());
|
||||
}
|
||||
|
||||
context2->context->interrupted = true;
|
||||
|
@ -171,11 +172,11 @@ TcpConnection TcpListener::accept() {
|
|||
if (WSAGetOverlappedResult(listener, &context2, &transferred, FALSE, &flags) != TRUE) {
|
||||
lastError = WSAGetLastError();
|
||||
if (lastError != ERROR_OPERATION_ABORTED) {
|
||||
message = "AcceptEx failed, result=" + std::to_string(lastError);
|
||||
message = "AcceptEx failed, " + errorMessage(lastError);
|
||||
} else {
|
||||
assert(context2.interrupted);
|
||||
if (closesocket(connection) != 0) {
|
||||
throw std::runtime_error("TcpListener::accept, closesocket failed, result=" + std::to_string(WSAGetLastError()));
|
||||
throw std::runtime_error("TcpListener::accept, closesocket failed, " + errorMessage(WSAGetLastError()));
|
||||
} else {
|
||||
throw InterruptedException();
|
||||
}
|
||||
|
@ -184,10 +185,10 @@ TcpConnection TcpListener::accept() {
|
|||
assert(transferred == 0);
|
||||
assert(flags == 0);
|
||||
if (setsockopt(connection, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, reinterpret_cast<char*>(&listener), sizeof listener) != 0) {
|
||||
message = "setsockopt failed, result=" + std::to_string(WSAGetLastError());
|
||||
message = "setsockopt failed, " + errorMessage(WSAGetLastError());
|
||||
} else {
|
||||
if (CreateIoCompletionPort(reinterpret_cast<HANDLE>(connection), dispatcher->getCompletionPort(), 0, 0) != dispatcher->getCompletionPort()) {
|
||||
message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError());
|
||||
message = "CreateIoCompletionPort failed, " + lastErrorMessage();
|
||||
} else {
|
||||
return TcpConnection(*dispatcher, connection);
|
||||
}
|
||||
|
|
45
src/Serialization/SerializationOverloads.cpp
Normal file
45
src/Serialization/SerializationOverloads.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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 "Serialization/SerializationOverloads.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace CryptoNote {
|
||||
|
||||
void serializeBlockHeight(ISerializer& s, uint32_t& blockHeight, Common::StringView name) {
|
||||
if (s.type() == ISerializer::INPUT) {
|
||||
uint64_t height;
|
||||
s(height, name);
|
||||
|
||||
if (height == std::numeric_limits<uint64_t>::max()) {
|
||||
blockHeight = std::numeric_limits<uint32_t>::max();
|
||||
} else if (height > std::numeric_limits<uint32_t>::max() && height < std::numeric_limits<uint64_t>::max()) {
|
||||
throw std::runtime_error("Deserialization error: wrong value");
|
||||
} else {
|
||||
blockHeight = static_cast<uint32_t>(height);
|
||||
}
|
||||
} else {
|
||||
s(blockHeight, name);
|
||||
}
|
||||
}
|
||||
|
||||
void serializeGlobalOutputIndex(ISerializer& s, uint32_t& globalOutputIndex, Common::StringView name) {
|
||||
serializeBlockHeight(s, globalOutputIndex, name);
|
||||
}
|
||||
|
||||
} //namespace CryptoNote
|
|
@ -249,4 +249,10 @@ void readSequence(Iterator outputIterator, Common::StringView name, ISerializer&
|
|||
s.endArray();
|
||||
}
|
||||
|
||||
//convinience function since we change block height type
|
||||
void serializeBlockHeight(ISerializer& s, uint32_t& blockHeight, Common::StringView name);
|
||||
|
||||
//convinience function since we change global output index type
|
||||
void serializeGlobalOutputIndex(ISerializer& s, uint32_t& globalOutputIndex, Common::StringView name);
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "CryptoNoteCore/CryptoNoteFormatUtils.h"
|
||||
#include "Serialization/BinaryInputStreamSerializer.h"
|
||||
#include "Serialization/BinaryOutputStreamSerializer.h"
|
||||
#include "Serialization/SerializationOverloads.h"
|
||||
|
||||
using namespace Common;
|
||||
using namespace Crypto;
|
||||
|
@ -31,7 +32,7 @@ namespace CryptoNote {
|
|||
void serialize(TransactionInformation& ti, CryptoNote::ISerializer& s) {
|
||||
s(ti.transactionHash, "");
|
||||
s(ti.publicKey, "");
|
||||
s(ti.blockHeight, "");
|
||||
serializeBlockHeight(s, ti.blockHeight, "");
|
||||
s(ti.timestamp, "");
|
||||
s(ti.unlockTime, "");
|
||||
s(ti.totalAmountIn, "");
|
||||
|
|
|
@ -89,12 +89,12 @@ struct TransactionOutputInformationEx : public TransactionOutputInformationIn {
|
|||
void serialize(CryptoNote::ISerializer& s) {
|
||||
s(reinterpret_cast<uint8_t&>(type), "type");
|
||||
s(amount, "");
|
||||
s(globalOutputIndex, "");
|
||||
serializeGlobalOutputIndex(s, globalOutputIndex, "");
|
||||
s(outputInTransaction, "");
|
||||
s(transactionPublicKey, "");
|
||||
s(keyImage, "");
|
||||
s(unlockTime, "");
|
||||
s(blockHeight, "");
|
||||
serializeBlockHeight(s, blockHeight, "");
|
||||
s(transactionIndex, "");
|
||||
s(transactionHash, "");
|
||||
s(visible, "");
|
||||
|
@ -113,7 +113,7 @@ struct BlockInfo {
|
|||
uint32_t transactionIndex;
|
||||
|
||||
void serialize(ISerializer& s) {
|
||||
s(height, "height");
|
||||
serializeBlockHeight(s, height, "height");
|
||||
s(timestamp, "timestamp");
|
||||
s(transactionIndex, "transactionIndex");
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ void serialize(WalletTransactionDto& value, CryptoNote::ISerializer& serializer)
|
|||
value.state = static_cast<CryptoNote::WalletTransactionState>(state);
|
||||
|
||||
serializer(value.timestamp, "timestamp");
|
||||
serializer(value.blockHeight, "block_height");
|
||||
CryptoNote::serializeBlockHeight(serializer, value.blockHeight, "block_height");
|
||||
serializer(value.hash, "hash");
|
||||
serializer(value.totalAmount, "total_amount");
|
||||
serializer(value.fee, "fee");
|
||||
|
|
|
@ -113,6 +113,7 @@ WalletLegacy::WalletLegacy(const CryptoNote::Currency& currency, INode& node) :
|
|||
m_blockchainSync(node, currency.genesisBlockHash()),
|
||||
m_transfersSync(currency, m_blockchainSync, node),
|
||||
m_transferDetails(nullptr),
|
||||
m_transactionsCache(m_currency.mempoolTxLiveTime()),
|
||||
m_sender(nullptr),
|
||||
m_onInitSyncStarter(new SyncStarter(m_blockchainSync))
|
||||
{
|
||||
|
@ -501,9 +502,15 @@ std::error_code WalletLegacy::cancelTransaction(size_t transactionId) {
|
|||
}
|
||||
|
||||
void WalletLegacy::synchronizationProgressUpdated(uint32_t current, uint32_t total) {
|
||||
auto deletedTransactions = deleteOutdatedUnconfirmedTransactions();
|
||||
|
||||
// forward notification
|
||||
m_observerManager.notify(&IWalletLegacyObserver::synchronizationProgressUpdated, current, total);
|
||||
|
||||
for (auto transactionId: deletedTransactions) {
|
||||
m_observerManager.notify(&IWalletLegacyObserver::transactionUpdated, transactionId);
|
||||
}
|
||||
|
||||
// check if balance has changed and notify client
|
||||
notifyIfBalanceChanged();
|
||||
}
|
||||
|
@ -513,9 +520,16 @@ void WalletLegacy::synchronizationCompleted(std::error_code result) {
|
|||
m_observerManager.notify(&IWalletLegacyObserver::synchronizationCompleted, result);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
notifyIfBalanceChanged();
|
||||
if (result) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto deletedTransactions = deleteOutdatedUnconfirmedTransactions();
|
||||
std::for_each(deletedTransactions.begin(), deletedTransactions.end(), [&] (TransactionId transactionId) {
|
||||
m_observerManager.notify(&IWalletLegacyObserver::transactionUpdated, transactionId);
|
||||
});
|
||||
|
||||
notifyIfBalanceChanged();
|
||||
}
|
||||
|
||||
void WalletLegacy::onTransactionUpdated(ITransfersSubscription* object, const Hash& transactionHash) {
|
||||
|
@ -586,4 +600,9 @@ void WalletLegacy::getAccountKeys(AccountKeys& keys) {
|
|||
keys = m_account.getAccountKeys();
|
||||
}
|
||||
|
||||
std::vector<TransactionId> WalletLegacy::deleteOutdatedUnconfirmedTransactions() {
|
||||
std::lock_guard<std::mutex> lock(m_cacheMutex);
|
||||
return m_transactionsCache.deleteOutdatedTransactions();
|
||||
}
|
||||
|
||||
} //namespace CryptoNote
|
||||
|
|
|
@ -106,6 +106,8 @@ private:
|
|||
void notifyClients(std::deque<std::shared_ptr<WalletLegacyEvent> >& events);
|
||||
void notifyIfBalanceChanged();
|
||||
|
||||
std::vector<TransactionId> deleteOutdatedUnconfirmedTransactions();
|
||||
|
||||
enum WalletState
|
||||
{
|
||||
NOT_INITIALIZED = 0,
|
||||
|
|
|
@ -52,18 +52,7 @@ void serialize(WalletLegacyTransaction& txi, CryptoNote::ISerializer& serializer
|
|||
serializer(txi.hash, "hash");
|
||||
serializer(txi.isCoinbase, "is_coinbase");
|
||||
|
||||
if (serializer.type() == ISerializer::INPUT) {
|
||||
uint64_t height = 0;
|
||||
serializer(height, "block_height");
|
||||
|
||||
if (height == std::numeric_limits<uint64_t>::max()) {
|
||||
txi.blockHeight = WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT;
|
||||
} else {
|
||||
txi.blockHeight = static_cast<uint32_t>(height);
|
||||
}
|
||||
} else {
|
||||
serializer(txi.blockHeight, "block_height");
|
||||
}
|
||||
CryptoNote::serializeBlockHeight(serializer, txi.blockHeight, "block_height");
|
||||
|
||||
serializer(txi.timestamp, "timestamp");
|
||||
serializer(txi.unlockTime, "unlock_time");
|
||||
|
|
|
@ -30,6 +30,11 @@ inline TransactionOutputId getOutputId(const TransactionOutputInformation& out)
|
|||
return std::make_pair(out.transactionPublicKey, out.outputInTransaction);
|
||||
}
|
||||
|
||||
WalletUnconfirmedTransactions::WalletUnconfirmedTransactions(uint64_t uncofirmedTransactionsLiveTime):
|
||||
m_uncofirmedTransactionsLiveTime(uncofirmedTransactionsLiveTime) {
|
||||
|
||||
}
|
||||
|
||||
bool WalletUnconfirmedTransactions::serialize(ISerializer& s) {
|
||||
s(m_unconfirmedTxs, "transactions");
|
||||
if (s.type() == ISerializer::INPUT) {
|
||||
|
@ -54,9 +59,7 @@ void WalletUnconfirmedTransactions::erase(const Hash& hash) {
|
|||
return;
|
||||
}
|
||||
|
||||
for (const auto& o : it->second.usedOutputs) {
|
||||
m_usedOutputs.erase(o);
|
||||
}
|
||||
deleteUsedOutputs(it->second.usedOutputs);
|
||||
m_unconfirmedTxs.erase(it);
|
||||
}
|
||||
|
||||
|
@ -125,4 +128,29 @@ void WalletUnconfirmedTransactions::reset() {
|
|||
m_usedOutputs.clear();
|
||||
}
|
||||
|
||||
void WalletUnconfirmedTransactions::deleteUsedOutputs(const std::vector<TransactionOutputId>& usedOutputs) {
|
||||
for (const auto& output: usedOutputs) {
|
||||
m_usedOutputs.erase(output);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TransactionId> WalletUnconfirmedTransactions::deleteOutdatedTransactions() {
|
||||
std::vector<TransactionId> deletedTransactions;
|
||||
|
||||
uint64_t now = static_cast<uint64_t>(time(nullptr));
|
||||
assert(now >= m_uncofirmedTransactionsLiveTime);
|
||||
|
||||
for (auto it = m_unconfirmedTxs.begin(); it != m_unconfirmedTxs.end();) {
|
||||
if (static_cast<uint64_t>(it->second.sentTime) <= now - m_uncofirmedTransactionsLiveTime) {
|
||||
deleteUsedOutputs(it->second.usedOutputs);
|
||||
deletedTransactions.push_back(it->second.transactionId);
|
||||
it = m_unconfirmedTxs.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return deletedTransactions;
|
||||
}
|
||||
|
||||
} /* namespace CryptoNote */
|
||||
|
|
|
@ -65,6 +65,8 @@ class WalletUnconfirmedTransactions
|
|||
{
|
||||
public:
|
||||
|
||||
explicit WalletUnconfirmedTransactions(uint64_t uncofirmedTransactionsLiveTime);
|
||||
|
||||
bool serialize(CryptoNote::ISerializer& s);
|
||||
|
||||
bool findTransactionId(const Crypto::Hash& hash, TransactionId& id);
|
||||
|
@ -78,15 +80,19 @@ public:
|
|||
bool isUsed(const TransactionOutputInformation& out) const;
|
||||
void reset();
|
||||
|
||||
std::vector<TransactionId> deleteOutdatedTransactions();
|
||||
|
||||
private:
|
||||
|
||||
void collectUsedOutputs();
|
||||
void deleteUsedOutputs(const std::vector<TransactionOutputId>& usedOutputs);
|
||||
|
||||
typedef std::unordered_map<Crypto::Hash, UnconfirmedTransferDetails, boost::hash<Crypto::Hash>> UnconfirmedTxsContainer;
|
||||
typedef std::unordered_set<TransactionOutputId> UsedOutputsContainer;
|
||||
|
||||
UnconfirmedTxsContainer m_unconfirmedTxs;
|
||||
UsedOutputsContainer m_usedOutputs;
|
||||
uint64_t m_uncofirmedTransactionsLiveTime;
|
||||
};
|
||||
|
||||
} // namespace CryptoNote
|
||||
|
|
|
@ -28,12 +28,18 @@
|
|||
using namespace Crypto;
|
||||
|
||||
namespace CryptoNote {
|
||||
|
||||
WalletUserTransactionsCache::WalletUserTransactionsCache(uint64_t mempoolTxLiveTime) : m_unconfirmedTransactions(mempoolTxLiveTime) {
|
||||
}
|
||||
|
||||
bool WalletUserTransactionsCache::serialize(CryptoNote::ISerializer& s) {
|
||||
if (s.type() == CryptoNote::ISerializer::INPUT) {
|
||||
s(m_transactions, "transactions");
|
||||
s(m_transfers, "transfers");
|
||||
s(m_unconfirmedTransactions, "unconfirmed");
|
||||
|
||||
updateUnconfirmedTransactions();
|
||||
deleteOutdatedTransactions();
|
||||
} else {
|
||||
UserTransactions txsToSave;
|
||||
UserTransfers transfersToSave;
|
||||
|
@ -298,4 +304,15 @@ void WalletUserTransactionsCache::reset() {
|
|||
m_unconfirmedTransactions.reset();
|
||||
}
|
||||
|
||||
std::vector<TransactionId> WalletUserTransactionsCache::deleteOutdatedTransactions() {
|
||||
auto deletedTransactions = m_unconfirmedTransactions.deleteOutdatedTransactions();
|
||||
|
||||
for (auto id: deletedTransactions) {
|
||||
assert(id < m_transactions.size());
|
||||
m_transactions[id].state = WalletLegacyTransactionState::Deleted;
|
||||
}
|
||||
|
||||
return deletedTransactions;
|
||||
}
|
||||
|
||||
} //namespace CryptoNote
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace CryptoNote {
|
|||
class WalletUserTransactionsCache
|
||||
{
|
||||
public:
|
||||
WalletUserTransactionsCache() {}
|
||||
explicit WalletUserTransactionsCache(uint64_t mempoolTxLiveTime = 60 * 60 * 24);
|
||||
|
||||
bool serialize(CryptoNote::ISerializer& serializer);
|
||||
|
||||
|
@ -59,6 +59,8 @@ public:
|
|||
bool isUsed(const TransactionOutputInformation& out) const;
|
||||
void reset();
|
||||
|
||||
std::vector<TransactionId> deleteOutdatedTransactions();
|
||||
|
||||
private:
|
||||
|
||||
TransactionId findTransactionByHash(const Crypto::Hash& hash);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#define BUILD_COMMIT_ID "@VERSION@"
|
||||
#define PROJECT_VERSION "1.0.6"
|
||||
#define PROJECT_VERSION_BUILD_NO "542"
|
||||
#define PROJECT_VERSION "1.0.6.1"
|
||||
#define PROJECT_VERSION_BUILD_NO "550"
|
||||
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
|
||||
|
|
|
@ -17,90 +17,47 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <boost/archive/binary_oarchive.hpp>
|
||||
#include <boost/archive/binary_iarchive.hpp>
|
||||
|
||||
namespace Tools
|
||||
{
|
||||
template<class t_object>
|
||||
bool serialize_obj_to_file(t_object& obj, const std::string& file_path)
|
||||
{
|
||||
try {
|
||||
#ifdef _WIN32
|
||||
// Need to know HANDLE of file to call FlushFileBuffers
|
||||
HANDLE data_file_handle = ::CreateFile(file_path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (INVALID_HANDLE_VALUE == data_file_handle)
|
||||
return false;
|
||||
namespace Tools {
|
||||
|
||||
int data_file_descriptor = _open_osfhandle((intptr_t)data_file_handle, 0);
|
||||
if (-1 == data_file_descriptor) {
|
||||
::CloseHandle(data_file_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* data_file_file = _fdopen(data_file_descriptor, "wb");
|
||||
if (0 == data_file_file) {
|
||||
// Call CloseHandle is not necessary
|
||||
_close(data_file_descriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
// HACK: undocumented constructor, this code may not compile
|
||||
std::ofstream data_file(data_file_file);
|
||||
if (data_file.fail()) {
|
||||
// Call CloseHandle and _close are not necessary
|
||||
fclose(data_file_file);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
std::ofstream data_file;
|
||||
data_file.open(file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc);
|
||||
if (data_file.fail())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
boost::archive::binary_oarchive a(data_file);
|
||||
a << obj;
|
||||
if (data_file.fail())
|
||||
return false;
|
||||
|
||||
data_file.flush();
|
||||
#ifdef _WIN32
|
||||
// To make sure the file is fully stored on disk
|
||||
::FlushFileBuffers(data_file_handle);
|
||||
fclose(data_file_file);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
} catch (std::exception&) {
|
||||
template <class t_object>
|
||||
bool serialize_obj_to_file(t_object& obj, const std::string& file_path) {
|
||||
try {
|
||||
std::ofstream file(file_path);
|
||||
boost::archive::binary_oarchive a(file);
|
||||
a << obj;
|
||||
if (file.fail()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<class t_object>
|
||||
bool unserialize_obj_from_file(t_object& obj, const std::string& file_path)
|
||||
{
|
||||
try {
|
||||
std::ifstream data_file;
|
||||
data_file.open( file_path, std::ios_base::binary | std::ios_base::in);
|
||||
if(data_file.fail())
|
||||
return false;
|
||||
boost::archive::binary_iarchive a(data_file);
|
||||
|
||||
a >> obj;
|
||||
return !data_file.fail();
|
||||
} catch (std::exception&) {
|
||||
return false;
|
||||
}
|
||||
file.flush();
|
||||
return true;
|
||||
} catch (std::exception&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class t_object>
|
||||
bool unserialize_obj_from_file(t_object& obj, const std::string& file_path) {
|
||||
try {
|
||||
std::ifstream dataFile;
|
||||
dataFile.open(file_path, std::ios_base::binary | std::ios_base::in);
|
||||
if (dataFile.fail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::archive::binary_iarchive a(dataFile);
|
||||
a >> obj;
|
||||
return !dataFile.fail();
|
||||
} catch (std::exception&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -150,6 +150,8 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(gen_tx_txout_to_key_has_invalid_key);
|
||||
GENERATE_AND_PLAY(gen_tx_output_with_zero_amount);
|
||||
GENERATE_AND_PLAY(gen_tx_signatures_are_invalid);
|
||||
GENERATE_AND_PLAY_EX(GenerateTransactionWithZeroFee(false));
|
||||
GENERATE_AND_PLAY_EX(GenerateTransactionWithZeroFee(true));
|
||||
|
||||
// multisignature output
|
||||
GENERATE_AND_PLAY_EX(MultiSigTx_OutputSignatures(1, 1, true));
|
||||
|
@ -187,7 +189,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendInTx(false));
|
||||
GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendInTx(true));
|
||||
GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendSameBlock(false));
|
||||
GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendSameBlock(true));
|
||||
GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendSameBlock(true));
|
||||
GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendDifferentBlocks(false));
|
||||
GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendDifferentBlocks(true));
|
||||
GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendAltChainSameBlock(false));
|
||||
|
|
|
@ -682,6 +682,34 @@ bool gen_tx_signatures_are_invalid::generate(std::vector<test_event_entry>& even
|
|||
return true;
|
||||
}
|
||||
|
||||
GenerateTransactionWithZeroFee::GenerateTransactionWithZeroFee(bool keptByBlock) : m_keptByBlock(keptByBlock) {
|
||||
}
|
||||
|
||||
bool GenerateTransactionWithZeroFee::generate(std::vector<test_event_entry>& events) const {
|
||||
uint64_t ts_start = 1338224400;
|
||||
|
||||
GENERATE_ACCOUNT(alice_account);
|
||||
GENERATE_ACCOUNT(bob_account);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, alice_account, ts_start);
|
||||
REWIND_BLOCKS(events, blk_0r, blk_0, alice_account);
|
||||
|
||||
CryptoNote::Transaction tx;
|
||||
construct_tx_to_key(m_logger, events, tx, blk_0, alice_account, bob_account, MK_COINS(1), 0, 0);
|
||||
|
||||
if (!m_keptByBlock) {
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
} else {
|
||||
event_visitor_settings settings;
|
||||
settings.txs_keeped_by_block = true;
|
||||
settings.valid_mask = 1;
|
||||
events.push_back(settings);
|
||||
}
|
||||
|
||||
events.push_back(tx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MultiSigTx_OutputSignatures::MultiSigTx_OutputSignatures(size_t givenKeys, uint32_t requiredSignatures, bool shouldSucceed) :
|
||||
m_givenKeys(givenKeys), m_requiredSignatures(requiredSignatures), m_shouldSucceed(shouldSucceed) {
|
||||
|
||||
|
|
|
@ -141,6 +141,14 @@ struct gen_tx_signatures_are_invalid : public get_tx_validation_base
|
|||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct GenerateTransactionWithZeroFee : public get_tx_validation_base
|
||||
{
|
||||
explicit GenerateTransactionWithZeroFee(bool keptByBlock);
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
|
||||
bool m_keptByBlock;
|
||||
};
|
||||
|
||||
// MultiSignature
|
||||
|
||||
class TestGenerator;
|
||||
|
|
26
tests/System/ErrorMessageTests.cpp
Normal file
26
tests/System/ErrorMessageTests.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
// 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 <System/ErrorMessage.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace System;
|
||||
|
||||
TEST(ErrorMessageTests, testErrorMessage) {
|
||||
auto msg = errorMessage(100);
|
||||
ASSERT_EQ(msg.substr(0, 12), "result=100, ");
|
||||
}
|
|
@ -291,6 +291,10 @@ void INodeTrivialRefreshStub::setNextTransactionToPool() {
|
|||
m_nextTxToPool = true;
|
||||
}
|
||||
|
||||
void INodeTrivialRefreshStub::cleanTransactionPool() {
|
||||
m_blockchainGenerator.clearTxPool();
|
||||
}
|
||||
|
||||
void INodeTrivialRefreshStub::getPoolSymmetricDifference(std::vector<Crypto::Hash>&& known_pool_tx_ids, Crypto::Hash known_block_id, bool& is_bc_actual,
|
||||
std::vector<std::unique_ptr<ITransactionReader>>& new_txs, std::vector<Crypto::Hash>& deleted_tx_ids, const Callback& callback)
|
||||
{
|
||||
|
|
|
@ -104,6 +104,7 @@ public:
|
|||
virtual void startAlternativeChain(uint32_t height);
|
||||
void setNextTransactionError();
|
||||
void setNextTransactionToPool();
|
||||
void cleanTransactionPool();
|
||||
void setMaxMixinCount(uint64_t maxMixin);
|
||||
void includeTransactionsFromPoolToBlock();
|
||||
|
||||
|
|
|
@ -61,8 +61,8 @@ public:
|
|||
}
|
||||
|
||||
virtual void synchronizationCompleted(std::error_code result) override {
|
||||
synced.notify();
|
||||
}
|
||||
synced.notify();
|
||||
}
|
||||
|
||||
virtual void sendTransactionCompleted(CryptoNote::TransactionId transactionId, std::error_code result) override {
|
||||
sendResult = result;
|
||||
|
@ -166,6 +166,9 @@ protected:
|
|||
void prepareCarolWallet();
|
||||
|
||||
void GetOneBlockReward(CryptoNote::WalletLegacy& wallet);
|
||||
void GetOneBlockReward(CryptoNote::WalletLegacy& wallet, const CryptoNote::Currency& currency, TestBlockchainGenerator& blockchainGenerator);
|
||||
void GetOneBlockRewardAndUnlock(CryptoNote::WalletLegacy& wallet, TrivialWalletObserver& observer, INodeTrivialRefreshStub& node,
|
||||
const CryptoNote::Currency& currency, TestBlockchainGenerator& blockchainGenerator);
|
||||
|
||||
void TestSendMoney(int64_t transferAmount, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "");
|
||||
void performTransferWithErrorTx(const std::array<int64_t, 5>& amounts, uint64_t fee);
|
||||
|
@ -221,9 +224,21 @@ void WalletLegacyApi::prepareCarolWallet() {
|
|||
}
|
||||
|
||||
void WalletLegacyApi::GetOneBlockReward(CryptoNote::WalletLegacy& wallet) {
|
||||
GetOneBlockReward(wallet, m_currency, generator);
|
||||
}
|
||||
|
||||
void WalletLegacyApi::GetOneBlockReward(CryptoNote::WalletLegacy& wallet, const CryptoNote::Currency& currency, TestBlockchainGenerator& blockchainGenerator) {
|
||||
CryptoNote::AccountPublicAddress address;
|
||||
ASSERT_TRUE(m_currency.parseAccountAddressString(wallet.getAddress(), address));
|
||||
generator.getBlockRewardForAddress(address);
|
||||
ASSERT_TRUE(currency.parseAccountAddressString(wallet.getAddress(), address));
|
||||
blockchainGenerator.getBlockRewardForAddress(address);
|
||||
}
|
||||
|
||||
void WalletLegacyApi::GetOneBlockRewardAndUnlock(CryptoNote::WalletLegacy& wallet, TrivialWalletObserver& observer, INodeTrivialRefreshStub& node,
|
||||
const CryptoNote::Currency& currency, TestBlockchainGenerator& blockchainGenerator) {
|
||||
GetOneBlockReward(wallet, currency, blockchainGenerator);
|
||||
blockchainGenerator.generateEmptyBlocks(10);
|
||||
node.updateObservers();
|
||||
WaitWalletSync(&observer);
|
||||
}
|
||||
|
||||
void WalletLegacyApi::performTransferWithErrorTx(const std::array<int64_t, 5>& amounts, uint64_t fee) {
|
||||
|
@ -1720,3 +1735,86 @@ TEST_F(WalletLegacyApi, resetAndSyncDoNotRestoreTransfers) {
|
|||
|
||||
alice->shutdown();
|
||||
}
|
||||
|
||||
void generateWallet(CryptoNote::IWalletLegacy& wallet, TrivialWalletObserver& observer, const std::string& pass) {
|
||||
wallet.initAndGenerate(pass);
|
||||
WaitWalletSync(&observer);
|
||||
}
|
||||
|
||||
TEST_F(WalletLegacyApi, outdatedUnconfirmedTransactionDeletedOnNewBlock) {
|
||||
const uint64_t TRANSACTION_MEMPOOL_TIME = 1;
|
||||
CryptoNote::Currency currency(CryptoNote::CurrencyBuilder(m_logger).mempoolTxLiveTime(TRANSACTION_MEMPOOL_TIME).currency());
|
||||
TestBlockchainGenerator blockchainGenerator(currency);
|
||||
INodeTrivialRefreshStub node(blockchainGenerator);
|
||||
CryptoNote::WalletLegacy wallet(currency, node);
|
||||
TrivialWalletObserver walletObserver;
|
||||
wallet.addObserver(&walletObserver);
|
||||
|
||||
wallet.initAndGenerate("pass");
|
||||
WaitWalletSync(&walletObserver);
|
||||
|
||||
GetOneBlockRewardAndUnlock(wallet, walletObserver, node, currency, blockchainGenerator);
|
||||
|
||||
const std::string ADDRESS = "2634US2FAz86jZT73YmM8u5GPCknT2Wxj8bUCKivYKpThFhF2xsjygMGxbxZzM42zXhKUhym6Yy6qHHgkuWtruqiGkDpX6m";
|
||||
node.setNextTransactionToPool();
|
||||
auto id = wallet.sendTransaction({ADDRESS, static_cast<int64_t>(TEST_BLOCK_REWARD - m_currency.minimumFee())}, m_currency.minimumFee());
|
||||
WaitWalletSend(&walletObserver);
|
||||
|
||||
node.cleanTransactionPool();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(TRANSACTION_MEMPOOL_TIME));
|
||||
|
||||
blockchainGenerator.generateEmptyBlocks(1);
|
||||
node.updateObservers();
|
||||
WaitWalletSync(&walletObserver);
|
||||
|
||||
ASSERT_EQ(TEST_BLOCK_REWARD, wallet.actualBalance());
|
||||
|
||||
CryptoNote::WalletLegacyTransaction transaction;
|
||||
ASSERT_TRUE(wallet.getTransaction(id, transaction));
|
||||
EXPECT_EQ(CryptoNote::WalletLegacyTransactionState::Deleted, transaction.state);
|
||||
|
||||
wallet.removeObserver(&walletObserver);
|
||||
wallet.shutdown();
|
||||
}
|
||||
|
||||
TEST_F(WalletLegacyApi, outdatedUnconfirmedTransactionDeletedOnLoad) {
|
||||
const uint64_t TRANSACTION_MEMPOOL_TIME = 1;
|
||||
CryptoNote::Currency currency(CryptoNote::CurrencyBuilder(m_logger).mempoolTxLiveTime(TRANSACTION_MEMPOOL_TIME).currency());
|
||||
TestBlockchainGenerator blockchainGenerator(currency);
|
||||
INodeTrivialRefreshStub node(blockchainGenerator);
|
||||
CryptoNote::WalletLegacy wallet(currency, node);
|
||||
TrivialWalletObserver walletObserver;
|
||||
wallet.addObserver(&walletObserver);
|
||||
|
||||
wallet.initAndGenerate("pass");
|
||||
WaitWalletSync(&walletObserver);
|
||||
|
||||
GetOneBlockRewardAndUnlock(wallet, walletObserver, node, currency, blockchainGenerator);
|
||||
|
||||
const std::string ADDRESS = "2634US2FAz86jZT73YmM8u5GPCknT2Wxj8bUCKivYKpThFhF2xsjygMGxbxZzM42zXhKUhym6Yy6qHHgkuWtruqiGkDpX6m";
|
||||
node.setNextTransactionToPool();
|
||||
auto id = wallet.sendTransaction({ADDRESS, static_cast<int64_t>(TEST_BLOCK_REWARD - m_currency.minimumFee())}, m_currency.minimumFee());
|
||||
WaitWalletSend(&walletObserver);
|
||||
|
||||
node.cleanTransactionPool();
|
||||
|
||||
std::stringstream data;
|
||||
wallet.save(data);
|
||||
WaitWalletSave(&walletObserver);
|
||||
|
||||
wallet.shutdown();
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(TRANSACTION_MEMPOOL_TIME));
|
||||
|
||||
wallet.initAndLoad(data, "pass");
|
||||
WaitWalletSync(&walletObserver);
|
||||
|
||||
ASSERT_EQ(TEST_BLOCK_REWARD, wallet.actualBalance());
|
||||
|
||||
CryptoNote::WalletLegacyTransaction transaction;
|
||||
ASSERT_TRUE(wallet.getTransaction(id, transaction));
|
||||
EXPECT_EQ(CryptoNote::WalletLegacyTransactionState::Deleted, transaction.state);
|
||||
|
||||
wallet.removeObserver(&walletObserver);
|
||||
wallet.shutdown();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue