diff --git a/.gitignore b/.gitignore index ef853da..d4c816b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ *.P *.bat *.exe -*.filter +*.filters +*.log *.user \ No newline at end of file diff --git a/README.md b/README.md index 1c61332..4f83401 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ MySQL There is a VS2017 project available. Needed includes and libs will be searched in .\deps\include and .\deps\libs. Dependencies - Boost - - OpenSSL (version < 1.1.0) - Mpir - MySQL Connector C (available in MYSQL package) diff --git a/makefile.mingw b/makefile.mingw index e278d39..a8152cb 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -8,12 +8,10 @@ INCLUDEPATHS= \ -I"$(CURDIR)\src\hash" \ -I"$(CURDIR)\src\LLP" \ -I"C:\Deps\boost_1_57_0" \ - -I"C:\Deps\openssl-1.0.1l\include" \ -I"C:\Deps\GMP\include" LIBPATHS= \ -L"C:\Deps\boost_1_57_0\stage\lib" \ - -L"C:\Deps\openssl-1.0.1l" \ -L"C:\Deps\GMP\lib" LIBS= \ @@ -21,8 +19,6 @@ LIBS= \ -l boost_filesystem-mgw49-mt-s-1_57 \ -l boost_program_options-mgw49-mt-s-1_57 \ -l boost_thread-mgw49-mt-s-1_57 \ - -l ssl \ - -l crypto \ -l gmp \ -l mysqlclient diff --git a/makefile.unix b/makefile.unix index 5f0173b..87ed1d3 100644 --- a/makefile.unix +++ b/makefile.unix @@ -4,8 +4,8 @@ DEFS=-DBOOST_SPIRIT_THREADSAFE -DBOOST_THREAD_USE_LIB -DEFS += $(addprefix -I,$(CURDIR)/src $(CURDIR)/src/build $(CURDIR)/src/hash $(CURDIR)/src/json $(BOOST_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) -LIBS = -lc -lpthread $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) +DEFS += $(addprefix -I,$(CURDIR)/src $(CURDIR)/src/build $(CURDIR)/src/hash $(CURDIR)/src/json $(BOOST_INCLUDE_PATH) +LIBS = -lc -lpthread $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH)) #For Boost 1.55 Builds Uncomment the Following #BOOST_LIB_PATH=/usr/local/lib @@ -18,7 +18,6 @@ LIBS += \ -l boost_program_options$(BOOST_LIB_SUFFIX) \ -l boost_thread$(BOOST_LIB_SUFFIX) \ -l boost_serialization$(BOOST_LIB_SUFFIX) \ - -l crypto \ -l gmp \ -l mysqlclient diff --git a/pool.conf.example b/pool.conf.example index 9c200bc..682b637 100644 --- a/pool.conf.example +++ b/pool.conf.example @@ -6,7 +6,7 @@ "daemon_threads" : 10, "pool_threads" : 20, - "enable_ddos" : "true", + "enable_ddos" : true, "ddos_rscore" : 20, "ddos_cscore" : 2, "min_share" : 40000000, diff --git a/src/LLD/database.h b/src/LLD/database.h index 0bd9c6b..5d1d0c6 100644 --- a/src/LLD/database.h +++ b/src/LLD/database.h @@ -1,22 +1,27 @@ -#ifndef COINSHIELD_LLD_DATABASE -#define COINSHIELD_LLD_DATABASE +#ifndef NEXUS_LLD_DATABASE +#define NEXUS_LLD_DATABASE #include #include +#include +#include #include "../util.h" namespace LLD { /** Main Class to be inherited Creating Customized Database Handles. Contains only the Key. **/ - template class Record { public: KeyType cKey; }; - + template + class Record + { + public: KeyType cKey; + }; /** Base Template Class for the Database Handle. Processes main Lower Level Disk Communications. **/ template class Database { /** Mutex for Thread Synchronization. **/ - boost::mutex DATABASE_MUTEX; + std::mutex DATABASE_MUTEX; std::string strFilename; typename std::map mapRecords; diff --git a/src/LLP/block.h b/src/LLP/block.h new file mode 100644 index 0000000..cbab2b8 --- /dev/null +++ b/src/LLP/block.h @@ -0,0 +1,48 @@ +#ifndef NEXUS_LLP_BLOCK_H +#define NEXUS_LLP_BLOCK_H + +#include "../hash/uint1024.h" +#include "../hash/templates.h" +#include + +#define BEGIN(a) ((char*)&(a)) +#define END(a) ((char*)&((&(a))[1])) + +namespace LLP { + + /** Mock Class for Building Block Hash. **/ + class CBlock + { + public: + using Uptr = std::unique_ptr; + using Sptr = std::shared_ptr; + + /** Begin of Header. BEGIN(nVersion) **/ + unsigned int nVersion; + uint1024 hashPrevBlock; + uint512 hashMerkleRoot; + unsigned int nChannel; + unsigned int nHeight; + unsigned int nBits; + uint64 nNonce; + /** End of Header. END(nNonce). + All the components to build an SK1024 Block Hash. **/ + + + CBlock() + { + nVersion = 0; + hashPrevBlock = 0; + hashMerkleRoot = 0; + nChannel = 0; + nHeight = 0; + nBits = 0; + nNonce = 0; + } + + inline uint1024 GetHash() const { return SK1024(BEGIN(nVersion), END(nBits)); } + inline uint1024 GetPrime() const { return GetHash() + nNonce; } + }; +} + +#endif \ No newline at end of file diff --git a/src/LLP/connection.cpp b/src/LLP/connection.cpp new file mode 100644 index 0000000..e6f05c1 --- /dev/null +++ b/src/LLP/connection.cpp @@ -0,0 +1,130 @@ +#include "connection.h" +#include "ddos.h" +#include "socket.h" +#include + +namespace LLP +{ + /** Connection Constructors **/ + Connection::Connection() : SOCKET(), DDOS(NULL), INCOMING(), CONNECTED(false) + { + INCOMING.SetNull(); + } + + Connection::Connection(std::shared_ptr SOCKET_IN, DDOS_Filter* DDOS_IN) + : SOCKET(SOCKET_IN) + , DDOS(DDOS_IN) + , INCOMING() + , CONNECTED(true) + { + TIMER.Start(); + } + + /** Checks for any flags in the Error Handle. **/ + bool Connection::Errors() + { + return SOCKET->Error() != 0; + } + + /** Determines if nTime seconds have elapsed since last Read / Write. **/ + bool Connection::Timeout(unsigned int nTime) + { + return (TIMER.Elapsed() >= nTime); + } + + /** Flag to determine if TCP Connection is still alive. **/ + bool Connection::Connected() + { + return CONNECTED; + } + + /** Handles two types of packets, requests which are of header >= 128, and data which are of header < 128. **/ + bool Connection::PacketComplete() + { + return INCOMING.Complete(); + } + + /** Used to reset the packet to Null after it has been processed. This then flags the Connection to read another packet. **/ + void Connection::ResetPacket() + { + INCOMING.SetNull(); + } + + /** Write a single packet to the TCP stream. **/ + void Connection::WritePacket(Packet PACKET) + { + if (Errors()) + return; + + Write(PACKET.GetBytes()); + } + + /** Non-Blocking Packet reader to build a packet from TCP Connection. + This keeps thread from spending too much time for each Connection. **/ + void Connection::ReadPacket() + { + /** Handle Reading Packet Type Header. **/ + if (SOCKET->Available() >= 1 && INCOMING.IsNull()) + { + std::vector HEADER(1, 255); + if (Read(HEADER, 1) == 1) + INCOMING.HEADER = HEADER[0]; + + } + + if (!INCOMING.IsNull() && !INCOMING.Complete()) + { + + /** Handle Reading Packet Length Header. **/ + if (SOCKET->Available() >= 4 && INCOMING.LENGTH == 0) + { + std::vector BYTES(4, 0); + if (Read(BYTES, 4) == 4) + { + INCOMING.SetLength(BYTES); + Event(0); + } + } + + /** Handle Reading Packet Data. **/ + uint32_t nAvailable = SOCKET->Available(); + if (nAvailable > 0 && INCOMING.LENGTH > 0 && INCOMING.DATA.size() < INCOMING.LENGTH) + { + std::vector DATA( std::min( std::min(nAvailable, 512u), (uint32_t)(INCOMING.LENGTH - INCOMING.DATA.size())), 0); + + if (Read(DATA, DATA.size()) == DATA.size()) + { + INCOMING.DATA.insert(INCOMING.DATA.end(), DATA.begin(), DATA.end()); + //Event(EVENT_PACKET, DATA.size()); + } + } + } + } + + /** Disconnect Socket. **/ + void Connection::Disconnect() + { + SOCKET->Close(); + + CONNECTED = false; + } + + /** Lower level network communications: Read. Interacts with OS sockets. **/ + size_t Connection::Read(std::vector &DATA, size_t nBytes) + { + TIMER.Reset(); + + return SOCKET->Read(DATA, nBytes); + } + + /** Lower level network communications: Write. Interacts with OS sockets. **/ + void Connection::Write(std::vector DATA) + { + SOCKET->Write(DATA, DATA.size()); + } + + std::string Connection::GetRemoteIPAddress() const + { + SOCKET->addr.ToStringIP(); + } +} diff --git a/src/LLP/connection.h b/src/LLP/connection.h new file mode 100644 index 0000000..15d71b1 --- /dev/null +++ b/src/LLP/connection.h @@ -0,0 +1,88 @@ +#ifndef NEXUS_LLP_CONNECTION_H +#define NEXUS_LLP_CONNECTION_H + +#include "timer.h" +#include "packet.h" +#include + +namespace LLP +{ + /* forward declarations */ + class DDOS_Filter; + class Socket; + + /** Base Template class to handle outgoing / incoming LLP data for both Client and Server. **/ + class Connection + { + protected: + /** Incoming Packet Being Built. **/ + Packet INCOMING; + + /** Basic Connection Variables. **/ + Timer TIMER; + std::shared_ptr SOCKET; + + /** Connected Flag. **/ + bool CONNECTED; + + /** + Virtual Event Function to be Overridden allowing Custom Read Events. + Each event fired on Header Complete, and each time data is read to fill packet. + Useful to check Header length to maximum size of packet type for DDOS protection, + sending a keep-alive ping while downloading large files, etc. + + nSize == 0 : Header Is Complete for Data Packet + nSize > 0 : Read nSize Bytes into Data Packet + **/ + virtual inline void Event(unsigned int nSize = 0) { } + + public: + + /** DDOS Score if a Incoming Server Connection. **/ + DDOS_Filter *DDOS; + + /** Connection Constructors **/ + Connection(); + + Connection(std::shared_ptr SOCKET_IN, DDOS_Filter* DDOS_IN); + + /** Checks for any flags in the Error Handle. **/ + bool Errors(); + + /** Determines if nTime seconds have elapsed since last Read / Write. **/ + bool Timeout(unsigned int nTime); + + /** Flag to determine if TCP Connection is still alive. **/ + bool Connected(); + + /** Handles two types of packets, requests which are of header >= 128, and data which are of header < 128. **/ + bool PacketComplete(); + + /** Used to reset the packet to Null after it has been processed. This then flags the Connection to read another packet. **/ + void ResetPacket(); + + /** Write a single packet to the TCP stream. **/ + void WritePacket(Packet PACKET); + + /** Non-Blocking Packet reader to build a packet from TCP Connection. + This keeps thread from spending too much time for each Connection. **/ + void ReadPacket(); + + /** Disconnect Socket. **/ + void Disconnect(); + + /** Get the IP address from remote endpoint **/ + inline std::string GetRemoteIPAddress() const; + + private: + + /** Lower level network communications: Read. Interacts with OS sockets. **/ + size_t Read(std::vector &DATA, size_t nBytes); + + /** Lower level network communications: Write. Interacts with OS sockets. **/ + void Write(std::vector DATA); + + }; +} + +#endif diff --git a/src/LLP/daemon.cpp b/src/LLP/daemon.cpp index 733fc6c..5144f51 100644 --- a/src/LLP/daemon.cpp +++ b/src/LLP/daemon.cpp @@ -5,6 +5,8 @@ #include "../util.h" #include "../statscollector.h" +#include + namespace LLP { @@ -50,9 +52,9 @@ namespace LLP } - Core::CBlock* DaemonConnection::DeserializeBlock(std::vector DATA) + CBlock::Uptr DaemonConnection::DeserializeBlock(std::vector const& DATA) { - Core::CBlock* BLOCK = new Core::CBlock(); + CBlock::Uptr BLOCK = std::make_unique(); BLOCK->nVersion = bytes2uint(std::vector(DATA.begin(), DATA.begin() + 4)); BLOCK->hashPrevBlock.SetBytes (std::vector(DATA.begin() + 4, DATA.begin() + 132)); @@ -81,10 +83,9 @@ namespace LLP CONNECTIONS[nID] = pConnection; nTotalConnections++; - printf("[DAEMON] Pool Connection %i Added to Daemon Handle %u. IP: %s\n", nID, ID, CONNECTIONS[nID]->GetIPAddress().c_str()); + std::cout << "[DAEMON] Pool Connection " << nID << " Added to Daemon Handle " << ID << " IP: " << CONNECTIONS[nID]->GetRemoteIPAddress() << std::endl; return nID; - } - + } void DaemonHandle::NewBlock() { @@ -95,8 +96,7 @@ namespace LLP CONNECTIONS[nIndex]->fNewBlock = true; CLIENT->ClearMaps(); - } - + } void DaemonHandle::RemoveConnection(int nIndex) { @@ -105,12 +105,12 @@ namespace LLP if( CONNECTIONS[nIndex]->ADDRESS != "") Core::STATSCOLLECTOR.DecConnectionCount(CONNECTIONS[nIndex]->ADDRESS, CONNECTIONS[nIndex]->GUID); - printf("[DAEMON] Pool Connection %i Removed from Daemon Handle %u. IP: %s\n", nIndex, ID, CONNECTIONS[nIndex]->GetIPAddress().c_str()); + std::cout << "[DAEMON] Pool Connection " << nIndex << " Removed from Daemon Handle " << ID << std::endl; + // printf("[DAEMON] Pool Connection %i Removed from Daemon Handle %u. IP: %s\n", nIndex, ID, CONNECTIONS[nIndex]->GetIPAddress().c_str()); CONNECTIONS[nIndex] = NULL; nTotalConnections--; - } - + } int DaemonHandle::FindConnection() { @@ -208,35 +208,38 @@ namespace LLP /** Add a Block to the Stack if it is received by the Daemon Connection. **/ else if(PACKET.HEADER == CLIENT->BLOCK_DATA) { - Core::CBlock* BLOCK = CLIENT->DeserializeBlock(PACKET.DATA); - if(BLOCK->nHeight == Core::nBestHeight) + CBlock::Uptr BLOCK = CLIENT->DeserializeBlock(PACKET.DATA); + /** If the Block isn't less than 1024-bits request a new one **/ + if(BLOCK->GetHash().high_bits(0x80000000)) { - { LOCK(CONNECTION_MUTEX); - for(int nIndex = 0; nIndex < CONNECTIONS.size(); nIndex++) - { - if(!CONNECTIONS[nIndex]) - continue; - - if(CONNECTIONS[nIndex]->nBlocksWaiting > 0) - { - CONNECTIONS[nIndex]->AddBlock(BLOCK); - - //printf("[DAEMON] Block Received Height = %u on Handle %u Assigned to %u\n", nBestHeight, ID, nIndex); - break; - } - } - } - + printf("[DAEMON] Block isn't less than 1024-bits. Request new one on Handle %u\n", ID); + CLIENT->GetBlock(); } else { - printf("[DAEMON] Block Obsolete Height = %u but wanted %u, Skipping over on Handle %u\n", BLOCK->nHeight, Core::nBestHeight, ID); - CLIENT->GetBlock(); //request another block as the last one was obsolete + if(BLOCK->nHeight == Core::nBestHeight) + { + { LOCK(CONNECTION_MUTEX); + for(int nIndex = 0; nIndex < CONNECTIONS.size(); nIndex++) + { + if(!CONNECTIONS[nIndex]) + continue; + + if(CONNECTIONS[nIndex]->nBlocksWaiting > 0) + { + CONNECTIONS[nIndex]->AddBlock(std::move(BLOCK)); + + printf("[DAEMON] Block Received Height = %u on Handle %u Assigned to %u\n", Core::nBestHeight, ID, nIndex); + break; + } + } + } + } + else + printf("[DAEMON] Block Obsolete Height = %u, Skipping over on Handle %u\n", BLOCK->nHeight, ID); } - } - - } - + } + } /** Don't Request Anything if Waiting for New Round to Reset. **/ if(Core::fCoinbasePending || Core::fSubmittingBlock || Core::fNewRound || fCoinbasePending) @@ -292,7 +295,7 @@ namespace LLP /** Reset the Submission Block Pointer. **/ - CONNECTIONS[nIndex]->SUBMISSION_BLOCK = NULL; + CONNECTIONS[nIndex]->SUBMISSION_BLOCK = nullptr; break; } } @@ -305,13 +308,12 @@ namespace LLP CONNECTIONS[nIndex]->nBlocksWaiting++; CLIENT->GetBlock(); - //CLIENT->GetBlock(); - //printf("[DAEMON] Requesting Block from Daemon Handle %u\n", ID); + printf("[DAEMON] Requesting Block from Daemon Handle %u\n", ID); } } } } } } -} \ No newline at end of file +} diff --git a/src/LLP/daemon.h b/src/LLP/daemon.h index 0ecab91..f80604d 100644 --- a/src/LLP/daemon.h +++ b/src/LLP/daemon.h @@ -1,10 +1,15 @@ -#ifndef COINSHEILD_DAEMON_H -#define COINSHIELD_DAEMON_H - +#ifndef NEXUS_DAEMON_H +#define NEXUS_DAEMON_H #include "types.h" +#include "block.h" +#include "connection.h" +#include "network.h" +#include "socket.h" #include "../hash/uint1024.h" +#include + class Coinbase; namespace Core { class CBlock; } namespace LLP @@ -17,11 +22,15 @@ namespace LLP /** Daemon Connection Class. Handles all the Reading / Writing from the Daemon Server. **/ class DaemonConnection : public Connection { - Service_t IO_SERVICE; std::string IP, PORT; + uint32_t TIMEOUT; public: - DaemonConnection(std::string ip, std::string port) { IP = ip; PORT = port; } + DaemonConnection(std::string ip, std::string port, uint32_t timeout = 10) + : IP{ip} + , PORT{port} + , TIMEOUT{timeout} + {} /** Enumeration to interpret Daemon Packets. **/ enum @@ -131,33 +140,31 @@ namespace LLP { try { - using boost::asio::ip::tcp; - - tcp::resolver RESOLVER(IO_SERVICE); - tcp::resolver::query QUERY (tcp::v4(), IP.c_str(), PORT.c_str()); - tcp::resolver::iterator ADDRESS = RESOLVER.resolve(QUERY); - - this->SOCKET = Socket_t(new tcp::socket(IO_SERVICE)); - this->SOCKET -> connect(*ADDRESS, this->ERROR_HANDLE); - - if(Errors()) + uint16_t port = (uint16_t)atoi(PORT.c_str()); + CNetAddr ip(IP); + CService addr(ip, port); + SOCKET = std::make_shared(); + SOCKET->Connect(addr, TIMEOUT); + + if (Errors()) { - this->Disconnect(); + Disconnect(); return false; } - - this->CONNECTED = true; - this->TIMER.Start(); + + CONNECTED = true; + TIMER.Start(); + return true; } - catch(...){ } - - this->CONNECTED = false; + catch (...) {} + + CONNECTED = false; return false; } - Core::CBlock* DeserializeBlock(std::vector DATA); + CBlock::Uptr DeserializeBlock(std::vector const& DATA); }; @@ -168,7 +175,7 @@ namespace LLP /** Incoming / Outgoing Blocks and Mutex Locks. **/ std::vector CONNECTIONS; - boost::mutex CONNECTION_MUTEX; + std::mutex CONNECTION_MUTEX; /** Daemon Outgoing Connection Handle **/ DaemonConnection* CLIENT; @@ -178,7 +185,12 @@ namespace LLP unsigned int nTotalConnections = 0, ID = 0; bool fNewBlock = false; - DaemonHandle(unsigned int nID, std::string IP, std::string PORT) : ID(nID), THREAD(boost::bind(&DaemonHandle::DaemonThread, this)){ CLIENT = new LLP::DaemonConnection(IP, PORT); } + DaemonHandle(unsigned int nID, std::string IP, std::string PORT) + : ID(nID) + , THREAD(std::bind(&DaemonHandle::DaemonThread, this)) + { + CLIENT = new LLP::DaemonConnection(std::move(IP), std::move(PORT)); + } /** Flag to allow Handle to Resupply on New Block. **/ bool fCoinbasePending = false; diff --git a/src/LLP/ddos.cpp b/src/LLP/ddos.cpp new file mode 100644 index 0000000..08d4d75 --- /dev/null +++ b/src/LLP/ddos.cpp @@ -0,0 +1,122 @@ +#include "ddos.h" +#include +#include + +namespace LLP +{ + DDOS_Score::DDOS_Score(int nTimespan) + { + for (int i = 0; i < nTimespan; i++) + SCORE.push_back(std::make_pair(true, 0)); + + TIMER.Start(); + nIterator = 0; + } + + int DDOS_Score::Score() const + { + int nMovingAverage = 0; + for (auto const score : SCORE) + nMovingAverage += score.second; + + return nMovingAverage / (int)SCORE.size(); + } + + void DDOS_Score::Flush() + { + for(auto score : SCORE) + score.second = 0; + } + + DDOS_Score &DDOS_Score::operator++(int) + { + int nTime = TIMER.Elapsed(); + if (nTime >= SCORE.size()) + { + Reset(); + nTime -= (int)SCORE.size(); + } + + + for (int i = nIterator; i <= nTime; i++) + { + if (!SCORE[i].first) + { + SCORE[i].first = true; + SCORE[i].second = 0; + } + } + + SCORE[nTime].second++; + nIterator = nTime; + + return *this; + } + + DDOS_Score &DDOS_Score::operator+=(int nScore) + { + int nTime = TIMER.Elapsed(); + + /** If the Time has been greater than Moving Average Timespan, Set to Add Score on Time Overlap. **/ + if(nTime >= SCORE.size()) + { + Reset(); + nTime = nTime % SCORE.size(); + } + + /** Iterate as many seconds as needed, flagging that each has been iterated. **/ + for(int i = nIterator; i <= nTime; i++) + { + if(!SCORE[i].first) + { + SCORE[i].first = true; + SCORE[i].second = 0; + } + } + + /** Update the Moving Average Iterator and Score for that Second Instance. **/ + SCORE[nTime].second += nScore; + nIterator = nTime; + + return *this; + } + + + void DDOS_Score::Reset() + { + for (auto score : SCORE) + score.first = false; + + TIMER.Reset(); + nIterator = 0; + } + + DDOS_Filter::DDOS_Filter(unsigned int nTimespan, std::string strIPAddress) + : rSCORE(nTimespan) + , cSCORE(nTimespan) + , IPADDRESS{std::move(strIPAddress)} + , BANTIME(0) + , TOTALBANS(0) { } + + void DDOS_Filter::Ban(std::string const& strMessage) + { + if(Banned()) + return; + + TIMER.Start(); + TOTALBANS++; + + BANTIME = std::max(TOTALBANS * (rSCORE.Score() + 1) * (cSCORE.Score() + 1), TOTALBANS * 1200u); + + std::cout << "XXXXX DDOS Filter Address = " << IPADDRESS << " cScore = " << cSCORE.Score() << " rScore = " << rSCORE.Score() << + " Banned for " << BANTIME << " Seconds. Violation: " << strMessage << std::endl; + + cSCORE.Flush(); + rSCORE.Flush(); + } + + bool DDOS_Filter::Banned() + { + return (TIMER.Elapsed() < BANTIME); + } +} diff --git a/src/LLP/ddos.h b/src/LLP/ddos.h new file mode 100644 index 0000000..8adbd34 --- /dev/null +++ b/src/LLP/ddos.h @@ -0,0 +1,52 @@ +#ifndef NEXUS_LLP_DDOS_H +#define NEXUS_LLP_DDOS_H + +#include "timer.h" +#include +#include + +namespace LLP +{ + /** Class that tracks DDOS attempts on LLP Servers. + Uses a Timer to calculate Request Score [rScore] and Connection Score [cScore] as a unit of Score / Second. + Pointer stored by Connection class and Server Listener DDOS_MAP. **/ + class DDOS_Score + { + public: + DDOS_Score(int nTimespan); + + int Score() const; + + /** Flush the DDOS Score to 0. **/ + void Flush(); + + DDOS_Score &operator++(int); + DDOS_Score &operator+=(int nScore); + + private: + std::vector< std::pair > SCORE; + Timer TIMER; + int nIterator; + + void Reset(); + }; + + + class DDOS_Filter + { + public: + DDOS_Score rSCORE, cSCORE; + std::string IPADDRESS; + + DDOS_Filter(unsigned int nTimespan, std::string strIPAddress); + + void Ban(std::string const& strMessage = "Score Threshold Ban"); + bool Banned(); + + private: + Timer TIMER; + unsigned int BANTIME, TOTALBANS; + }; +} + +#endif diff --git a/src/LLP/hosts.cpp b/src/LLP/hosts.cpp new file mode 100644 index 0000000..c9c97b9 --- /dev/null +++ b/src/LLP/hosts.cpp @@ -0,0 +1,185 @@ +/*__________________________________________________________________________________________ + + (c) Hash(BEGIN(Satoshi[2010]), END(Sunny[2012])) == Videlicet[2018] ++ + + (c) Copyright The Nexus Developers 2014 - 2018 + + Distributed under the MIT software license, see the accompanying + file COPYING or http://www.opensource.org/licenses/mit-license.php. + + "ad vocem populi" - To the Voice of the People + +____________________________________________________________________________________________*/ + +#include "network.h" +#include "hosts.h" + +#include +#include +#include +#include +#include /* USHRT_MAX */ + +namespace LLP +{ + + /** DNS Query of Domain Names Associated with Seed Nodes **/ + std::vector DNS_Lookup(std::vector DNS_Seed) + { + std::vector vNodes; + for (int nSeed = 0; nSeed < DNS_Seed.size(); nSeed ++ ) + { + printf("%u Host: %s\n", nSeed, DNS_Seed[nSeed].c_str()); + std::vector vaddr; + if (LookupHost(DNS_Seed[nSeed].c_str(), vaddr)) + { + for(CNetAddr& ip : vaddr) + { + CAddress addr = CAddress(CService(ip, GetDefaultPort())); + vNodes.push_back(addr); + + printf("DNS Seed: %s\n", addr.ToStringIP().c_str()); + } + } + } + + return vNodes; + } + + + bool static LookupIntern(const char *pszName, std::vector& vIP, uint32_t nMaxSolutions, bool fAllowLookup) + { + vIP.clear(); + struct addrinfo aiHint; + memset(&aiHint, 0, sizeof(struct addrinfo)); + + aiHint.ai_socktype = SOCK_STREAM; + aiHint.ai_protocol = IPPROTO_TCP; + #ifdef WIN32 + # ifdef USE_IPV6 + aiHint.ai_family = AF_UNSPEC; + aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; + # else + aiHint.ai_family = AF_INET; + aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; + # endif + #else + # ifdef USE_IPV6 + aiHint.ai_family = AF_UNSPEC; + aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST); + # else + aiHint.ai_family = AF_INET; + aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST); + # endif + #endif + struct addrinfo *aiRes = NULL; + int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes); + if (nErr) + return false; + + struct addrinfo *aiTrav = aiRes; + while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) + { + if (aiTrav->ai_family == AF_INET) + { + assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in)); + vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr)); + } + + #ifdef USE_IPV6 + if (aiTrav->ai_family == AF_INET6) + { + assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6)); + vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr)); + } + #endif + + aiTrav = aiTrav->ai_next; + } + + freeaddrinfo(aiRes); + + return (vIP.size() > 0); + } + + bool LookupHost(const char *pszName, std::vector& vIP, uint32_t nMaxSolutions, bool fAllowLookup) + { + if (pszName[0] == 0) + return false; + char psz[256]; + char *pszHost = psz; + //strlcpy(psz, pszName, sizeof(psz)); + std::copy(pszName, pszName + 256, psz); + if (psz[0] == '[' && psz[strlen(psz)-1] == ']') + { + pszHost = psz+1; + psz[strlen(psz)-1] = 0; + } + + return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); + } + + bool LookupHostNumeric(const char *pszName, std::vector& vIP, uint32_t nMaxSolutions) + { + return LookupHost(pszName, vIP, nMaxSolutions, false); + } + + bool Lookup(const char *pszName, std::vector& vAddr, int portDefault, bool fAllowLookup, uint32_t nMaxSolutions) + { + if (pszName[0] == 0) + return false; + int port = portDefault; + char psz[256]; + char *pszHost = psz; + //strlcpy(psz, pszName, sizeof(psz)); + std::copy(pszName, pszName + 256, psz); + char* pszColon = strrchr(psz+1,':'); + char *pszPortEnd = NULL; + int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0; + if (pszColon && pszPortEnd && pszPortEnd[0] == 0) + { + if (psz[0] == '[' && pszColon[-1] == ']') + { + pszHost = psz+1; + pszColon[-1] = 0; + } + else + pszColon[0] = 0; + if (port >= 0 && port <= USHRT_MAX) + port = portParsed; + } + else + { + if (psz[0] == '[' && psz[strlen(psz)-1] == ']') + { + pszHost = psz+1; + psz[strlen(psz)-1] = 0; + } + + } + + std::vector vIP; + bool fRet = LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); + if (!fRet) + return false; + vAddr.resize(vIP.size()); + for (uint32_t i = 0; i < vIP.size(); i++) + vAddr[i] = CService(vIP[i], port); + return true; + } + + bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup) + { + std::vector vService; + bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1); + if (!fRet) + return false; + addr = vService[0]; + return true; + } + + bool LookupNumeric(const char *pszName, CService& addr, int portDefault) + { + return Lookup(pszName, addr, portDefault, false); + } +} diff --git a/src/LLP/hosts.h b/src/LLP/hosts.h new file mode 100644 index 0000000..2cb4db7 --- /dev/null +++ b/src/LLP/hosts.h @@ -0,0 +1,39 @@ +/*__________________________________________________________________________________________ + + (c) Hash(BEGIN(Satoshi[2010]), END(Sunny[2012])) == Videlicet[2018] ++ + + (c) Copyright The Nexus Developers 2014 - 2018 + + Distributed under the MIT software license, see the accompanying + file COPYING or http://www.opensource.org/licenses/mit-license.php. + + "ad vocem populi" - To the Voice of the People + +____________________________________________________________________________________________*/ + +#ifndef NEXUS_LLP_INCLUDE_HOSTS_H +#define NEXUS_LLP_INCLUDE_HOSTS_H + +#include +#include + +namespace LLP +{ + + class CAddress; + class CNetAddr; + class CService; + + /* The DNS Lookup Routine to find the Nodes that are set as DNS seeds. */ + std::vector DNS_Lookup(std::vector DNS_Seed); + + + /* Standard Wrapper Function to Interact with cstdlib DNS functions. */ + bool LookupHost(const char *pszName, std::vector& vIP, uint32_t nMaxSolutions = 0, bool fAllowLookup = true); + bool LookupHostNumeric(const char *pszName, std::vector& vIP, uint32_t nMaxSolutions = 0); + bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); + bool Lookup(const char *pszName, std::vector& vAddr, int portDefault = 0, bool fAllowLookup = true, uint32_t nMaxSolutions = 0); + bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); +} + +#endif diff --git a/src/LLP/network.cpp b/src/LLP/network.cpp new file mode 100644 index 0000000..5790ca4 --- /dev/null +++ b/src/LLP/network.cpp @@ -0,0 +1,549 @@ +/*__________________________________________________________________________________________ + + (c) Hash(BEGIN(Satoshi[2010]), END(Sunny[2012])) == Videlicet[2018] ++ + + (c) Copyright The Nexus Developers 2014 - 2018 + + Distributed under the MIT software license, see the accompanying + file COPYING or http://www.opensource.org/licenses/mit-license.php. + + "ad vocem populi" - To the Voice of the People + +____________________________________________________________________________________________*/ + +#include "network.h" +#include "hosts.h" + +#ifndef WIN32 +#include +#endif + +#include +#include + +namespace LLP +{ + + + CAddress::CAddress() : CService() + { + Init(); + } + + + CAddress::CAddress(CService ipIn, uint64_t nServicesIn) : CService(ipIn) + { + Init(); + nServices = nServicesIn; + } + + + void CAddress::Init() + { + nServices = NODE_NETWORK; + nTime = 100000000; + nLastTry = 0; + } + + + void CNetAddr::Init() + { + memset(ip, 0, 16); + } + + + void CNetAddr::SetIP(const CNetAddr& ipIn) + { + memcpy(ip, ipIn.ip, sizeof(ip)); + } + + + CNetAddr::CNetAddr() + { + Init(); + } + + + CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) + { + memcpy(ip, pchIPv4, 12); + memcpy(ip+12, &ipv4Addr, 4); + } + + + #ifdef USE_IPV6 + CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr) + { + memcpy(ip, &ipv6Addr, 16); + } + #endif + + + CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup) + { + Init(); + std::vector vIP; + if (LookupHost(pszIp, vIP, 1, fAllowLookup)) + *this = vIP[0]; + } + + + CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup) + { + Init(); + std::vector vIP; + if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup)) + *this = vIP[0]; + } + + int CNetAddr::GetByte(int n) const + { + return ip[15-n]; + } + + + bool CNetAddr::IsIPv4() const + { + return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); + } + + + bool CNetAddr::IsRFC1918() const + { + return IsIPv4() && ( + GetByte(3) == 10 || + (GetByte(3) == 192 && GetByte(2) == 168) || + (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); + } + + + bool CNetAddr::IsRFC3927() const + { + return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254); + } + + + bool CNetAddr::IsRFC3849() const + { + return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8; + } + + + bool CNetAddr::IsRFC3964() const + { + return (GetByte(15) == 0x20 && GetByte(14) == 0x02); + } + + + bool CNetAddr::IsRFC6052() const + { + static const uint8_t pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0}; + return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0); + } + + + bool CNetAddr::IsRFC4380() const + { + return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0); + } + + + bool CNetAddr::IsRFC4862() const + { + static const uint8_t pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0}; + return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0); + } + + + bool CNetAddr::IsRFC4193() const + { + return ((GetByte(15) & 0xFE) == 0xFC); + } + + + bool CNetAddr::IsRFC6145() const + { + static const uint8_t pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0}; + return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0); + } + + + bool CNetAddr::IsRFC4843() const + { + return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); + } + + + bool CNetAddr::IsLocal() const + { + // IPv4 loopback + if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) + return true; + + // IPv6 loopback (::1/128) + static const uint8_t pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + if (memcmp(ip, pchLocal, 16) == 0) + return true; + + return false; + } + + + bool CNetAddr::IsMulticast() const + { + return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0) + || (GetByte(15) == 0xFF); + } + + + bool CNetAddr::IsValid() const + { + // Clean up 3-byte shifted addresses caused by garbage in size field + // of addr messages from versions before 0.2.9 checksum. + // Two consecutive addr messages look like this: + // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26... + // so if the first length field is garbled, it reads the second batch + // of addr misaligned by 3 bytes. + if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0) + return false; + + // unspecified IPv6 address (::/128) + uint8_t ipNone[16] = {}; + if (memcmp(ip, ipNone, 16) == 0) + return false; + + // documentation IPv6 address + if (IsRFC3849()) + return false; + + if (IsIPv4()) + { + // INADDR_NONE + uint32_t ipNone = INADDR_NONE; + if (memcmp(ip+12, &ipNone, 4) == 0) + return false; + + // 0 + ipNone = 0; + if (memcmp(ip+12, &ipNone, 4) == 0) + return false; + } + + return true; + } + + + bool CNetAddr::IsRoutable() const + { + return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || IsRFC4193() || IsRFC4843() || IsLocal()); + } + + + std::string CNetAddr::ToStringIP() const + { + if (IsIPv4()) + { + return std::to_string(GetByte(3)) + "." + + std::to_string(GetByte(2)) + "." + + std::to_string(GetByte(1)) + "." + + std::to_string(GetByte(0)); + } + else + { + return std::to_string(GetByte(15) << 8 | GetByte(14)) + ":" + + std::to_string(GetByte(13) << 8 | GetByte(12)) + ":" + + std::to_string(GetByte(11) << 8 | GetByte(10)) + ":" + + std::to_string(GetByte(9) << 8 | GetByte(8)) + ":" + + std::to_string(GetByte(7) << 8 | GetByte(6)) + ":" + + std::to_string(GetByte(5) << 8 | GetByte(4)) + ":" + + std::to_string(GetByte(3) << 8 | GetByte(2)) + ":" + + std::to_string(GetByte(1) << 8 | GetByte(0)); + } + } + + + std::string CNetAddr::ToString() const + { + return ToStringIP(); + } + + + bool operator==(const CNetAddr& a, const CNetAddr& b) + { + return (memcmp(a.ip, b.ip, 16) == 0); + } + + + bool operator!=(const CNetAddr& a, const CNetAddr& b) + { + return (memcmp(a.ip, b.ip, 16) != 0); + } + + + bool operator<(const CNetAddr& a, const CNetAddr& b) + { + return (memcmp(a.ip, b.ip, 16) < 0); + } + + + bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const + { + if (!IsIPv4()) + return false; + memcpy(pipv4Addr, ip+12, 4); + return true; + } + + + #ifdef USE_IPV6 + bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const + { + memcpy(pipv6Addr, ip, 16); + return true; + } + #endif + + + // get canonical identifier of an address' group + // no two connections will be attempted to addresses with the same group + std::vector CNetAddr::GetGroup() const + { + std::vector vchRet; + int nClass = 0; // 0=IPv6, 1=IPv4, 254=local, 255=unroutable + int nStartByte = 0; + int nBits = 16; + + // all local addresses belong to the same group + if (IsLocal()) + { + nClass = 254; + nBits = 0; + } + + // all unroutable addresses belong to the same group + if (!IsRoutable()) + { + nClass = 255; + nBits = 0; + } + // for IPv4 addresses, '1' + the 16 higher-order bits of the IP + // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix + else if (IsIPv4() || IsRFC6145() || IsRFC6052()) + { + nClass = 1; + nStartByte = 12; + } + // for 6to4 tunneled addresses, use the encapsulated IPv4 address + else if (IsRFC3964()) + { + nClass = 1; + nStartByte = 2; + } + // for Teredo-tunneled IPv6 addresses, use the encapsulated IPv4 address + else if (IsRFC4380()) + { + vchRet.push_back(1); + vchRet.push_back(GetByte(3) ^ 0xFF); + vchRet.push_back(GetByte(2) ^ 0xFF); + return vchRet; + } + // for he.net, use /36 groups + else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70) + nBits = 36; + // for the rest of the IPv6 network, use /32 groups + else + nBits = 32; + + vchRet.push_back(nClass); + while (nBits >= 8) + { + vchRet.push_back(GetByte(15 - nStartByte)); + nStartByte++; + nBits -= 8; + } + if (nBits > 0) + vchRet.push_back(GetByte(15 - nStartByte) | ((1 << nBits) - 1)); + + return vchRet; + } + + + //uint64_t CNetAddr::GetHash() const + //{ + // return LLC::SK64(&ip[0], &ip[16]); + //} + + + void CNetAddr::print() const + { + printf("CNetAddr(%s)\n", ToString().c_str()); + } + + + void CService::Init() + { + port = 0; + } + + + CService::CService() + { + Init(); + } + + + CService::CService(const CNetAddr& cip, uint16_t portIn) : CNetAddr(cip), port(portIn) + { + } + + + CService::CService(const struct in_addr& ipv4Addr, uint16_t portIn) : CNetAddr(ipv4Addr), port(portIn) + { + } + + + #ifdef USE_IPV6 + CService::CService(const struct in6_addr& ipv6Addr, uint16_t portIn) : CNetAddr(ipv6Addr), port(portIn) + { + } + #endif + + + CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) + { + assert(addr.sin_family == AF_INET); + } + + + #ifdef USE_IPV6 + CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port)) + { + assert(addr.sin6_family == AF_INET6); + } + #endif + + CService::CService(const char *pszIpPort, bool fAllowLookup) + { + Init(); + CService ip; + if (Lookup(pszIpPort, ip, 0, fAllowLookup)) + *this = ip; + } + + + CService::CService(const char *pszIpPort, int portDefault, bool fAllowLookup) + { + Init(); + CService ip; + if (Lookup(pszIpPort, ip, portDefault, fAllowLookup)) + *this = ip; + } + + + CService::CService(const std::string &strIpPort, bool fAllowLookup) + { + Init(); + CService ip; + if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup)) + *this = ip; + } + + + CService::CService(const std::string &strIpPort, int portDefault, bool fAllowLookup) + { + Init(); + CService ip; + if (Lookup(strIpPort.c_str(), ip, portDefault, fAllowLookup)) + *this = ip; + } + + uint16_t CService::GetPort() const + { + return port; + } + + + bool operator==(const CService& a, const CService& b) + { + return (CNetAddr)a == (CNetAddr)b && a.port == b.port; + } + + + bool operator!=(const CService& a, const CService& b) + { + return (CNetAddr)a != (CNetAddr)b || a.port != b.port; + } + + + bool operator<(const CService& a, const CService& b) + { + return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port); + } + + + bool CService::GetSockAddr(struct sockaddr_in* paddr) const + { + if (!IsIPv4()) + return false; + memset(paddr, 0, sizeof(struct sockaddr_in)); + if (!GetInAddr(&paddr->sin_addr)) + return false; + paddr->sin_family = AF_INET; + paddr->sin_port = htons(port); + return true; + } + + + #ifdef USE_IPV6 + bool CService::GetSockAddr6(struct sockaddr_in6* paddr) const + { + memset(paddr, 0, sizeof(struct sockaddr_in6)); + if (!GetIn6Addr(&paddr->sin6_addr)) + return false; + paddr->sin6_family = AF_INET6; + paddr->sin6_port = htons(port); + return true; + } + #endif + + + std::vector CService::GetKey() const + { + std::vector vKey; + vKey.resize(18); + memcpy(&vKey[0], ip, 16); + vKey[16] = port / 0x100; + vKey[17] = port & 0x0FF; + return vKey; + } + + + std::string CService::ToStringPort() const + { + return std::string(":") + std::to_string(port); + } + + + std::string CService::ToStringIPPort() const + { + return ToStringIP() + ToStringPort(); + } + + + std::string CService::ToString() const + { + return ToStringIPPort(); + } + + + void CService::print() const + { + printf("CService(%s)\n", ToString().c_str()); + } + + + void CService::SetPort(uint16_t portIn) + { + port = portIn; + } +} diff --git a/src/LLP/network.h b/src/LLP/network.h new file mode 100644 index 0000000..2c3aad2 --- /dev/null +++ b/src/LLP/network.h @@ -0,0 +1,276 @@ +/*__________________________________________________________________________________________ + + (c) Hash(BEGIN(Satoshi[2010]), END(Sunny[2012])) == Videlicet[2018] ++ + + (c) Copyright The Nexus Developers 2014 - 2018 + + Distributed under the MIT software license, see the accompanying + file COPYING or http://www.opensource.org/licenses/mit-license.php. + + "ad vocem populi" - To the Voice of the People + +____________________________________________________________________________________________*/ + +#ifndef NEXUS_LLP_INCLUDE_NETWORK_H +#define NEXUS_LLP_INCLUDE_NETWORK_H + +#ifdef WIN32 +#define _WIN32_WINNT 0x0501 +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +//typedef u_int SOCKET; + +#ifdef WIN32 +#define MSG_NOSIGNAL 0 +#define MSG_DONTWAIT 0 +typedef int socklen_t; +#else +#include "errno.h" +#define GetLastError() errno +#define WSAEINVAL EINVAL +#define WSAEALREADY EALREADY +#define WSAEWOULDBLOCK EWOULDBLOCK +#define WSAEMSGSIZE EMSGSIZE +#define WSAEINTR EINTR +#define WSAEINPROGRESS EINPROGRESS +#define WSAEADDRINUSE EADDRINUSE +#define WSAENOTSOCK EBADF +#define INVALID_SOCKET (SOCKET)(~0) +#define SOCKET_ERROR -1 +#endif + +#ifdef WIN32 +// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error +#undef SetPort +#endif + +#ifndef MAINNET_PORT +#define MAINNET_PORT 9323 +#endif + +#ifndef TESTNET_PORT +#define TESTNET_PORT 8313 +#endif + +#ifndef MAINNET_CORE_LLP_PORT +#define MAINNET_CORE_LLP_PORT 9324 +#endif + +#ifndef TESTNET_CORE_LLP_PORT +#define TESTNET_CORE_LLP_PORT 8329 +#endif + +#ifndef MAINNET_MINING_LLP_PORT +#define MAINNET_MINING_LLP_PORT 9325 +#endif + +#ifndef TESTNET_MINING_LLP_PORT +#define TESTNET_MINING_LLP_PORT 8325 +#endif + +namespace LLP +{ + + static const uint8_t pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; + + /** Services flags */ + enum + { + NODE_NETWORK = (1 << 0), + }; + + + /** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ + class CNetAddr + { + protected: + uint8_t ip[16]; // in network byte order + + public: + CNetAddr(); + CNetAddr(const struct in_addr& ipv4Addr); + explicit CNetAddr(const char *pszIp, bool fAllowLookup = false); + explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); + void Init(); + void SetIP(const CNetAddr& ip); + bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) + bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) + bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) + bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) + bool IsRFC3964() const; // IPv6 6to4 tunneling (2002::/16) + bool IsRFC4193() const; // IPv6 unique local (FC00::/15) + bool IsRFC4380() const; // IPv6 Teredo tunneling (2001::/32) + bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) + bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) + bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) + bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) + bool IsLocal() const; + bool IsRoutable() const; + bool IsValid() const; + bool IsMulticast() const; + std::string ToString() const; + std::string ToStringIP() const; + int GetByte(int n) const; + uint64_t GetHash() const; + bool GetInAddr(struct in_addr* pipv4Addr) const; + std::vector GetGroup() const; + void print() const; + + #ifdef USE_IPV6 + CNetAddr(const struct in6_addr& pipv6Addr); + bool GetIn6Addr(struct in6_addr* pipv6Addr) const; + #endif + + friend bool operator==(const CNetAddr& a, const CNetAddr& b); + friend bool operator!=(const CNetAddr& a, const CNetAddr& b); + friend bool operator<(const CNetAddr& a, const CNetAddr& b); + + }; + + + /** A combination of a network address (CNetAddr) and a (TCP) port */ + class CService : public CNetAddr + { + protected: + uint16_t port; // host order + + public: + CService(); + CService(const CNetAddr& ip, uint16_t port); + CService(const struct in_addr& ipv4Addr, uint16_t port); + CService(const struct sockaddr_in& addr); + explicit CService(const char *pszIpPort, int portDefault, bool fAllowLookup = false); + explicit CService(const char *pszIpPort, bool fAllowLookup = false); + explicit CService(const std::string& strIpPort, int portDefault, bool fAllowLookup = false); + explicit CService(const std::string& strIpPort, bool fAllowLookup = false); + void Init(); + void SetPort(uint16_t portIn); + uint16_t GetPort() const; + bool GetSockAddr(struct sockaddr_in* paddr) const; + friend bool operator==(const CService& a, const CService& b); + friend bool operator!=(const CService& a, const CService& b); + friend bool operator<(const CService& a, const CService& b); + std::vector GetKey() const; + std::string ToString() const; + std::string ToStringPort() const; + std::string ToStringIPPort() const; + void print() const; + + #ifdef USE_IPV6 + CService(const struct in6_addr& ipv6Addr, uint16_t port); + bool GetSockAddr6(struct sockaddr_in6* paddr) const; + CService(const struct sockaddr_in6& addr); + #endif + + }; + + + /** A CService with information about it as peer */ + class CAddress : public CService + { + public: + CAddress(); + explicit CAddress(CService ipIn, uint64_t nServicesIn = NODE_NETWORK); + + void Init(); + + + void print() const; + + // TODO: make private (improves encapsulation) + public: + uint64_t nServices; + + // disk and network only + uint32_t nTime; + + // memory only + int64_t nLastTry; + }; + + + /** Extended statistics about a CAddress */ + class CAddrInfo : public CAddress + { + private: + + /* Who Gave us this Address. */ + CNetAddr source; + + + /* The last time this connection was seen. */ + uint32_t nLastSuccess; + + + /* The last time this node was tried. */ + uint32_t nLastAttempt; + + + /* Number of attempts to connect since last try. */ + uint32_t nAttempts; + + + + public: + + void Init() + { + nLastSuccess = 0; + nLastAttempt = 0; + nAttempts = 0; + } + + CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) + { + Init(); + } + + CAddrInfo() : CAddress(), source() + { + Init(); + } + }; + + + /* Proxy Settings for Nexus Core. */ + static CService addrProxy("127.0.0.1", 9050); + + + /* Get the Main Core LLP Port for Nexus. */ + inline uint16_t GetCorePort(const bool testnet = false){ return testnet ? TESTNET_CORE_LLP_PORT : MAINNET_CORE_LLP_PORT; } + + + /* Get the Main Mining LLP Port for Nexus. */ + inline uint16_t GetMiningPort(const bool testnet = false){ return testnet ? TESTNET_MINING_LLP_PORT : MAINNET_MINING_LLP_PORT; } + + + /* Get the Main Message LLP Port for Nexus. */ + inline uint16_t GetDefaultPort(const bool testnet = false){ return testnet ? TESTNET_PORT : MAINNET_PORT; } + + + /** Connect to a socket with given connection timeout flag. **/ + bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = 5000); + +} + +#endif diff --git a/src/LLP/outbound.cpp b/src/LLP/outbound.cpp new file mode 100644 index 0000000..4164a67 --- /dev/null +++ b/src/LLP/outbound.cpp @@ -0,0 +1,59 @@ +#include "outbound.h" +#include "socket.h" + +namespace LLP +{ + /** Outgoing Client Connection Constructor **/ + Outbound::Outbound(std::string ip, std::string port, uint32_t nTimeout) + : IP(ip) + , PORT(port) + , TIMEOUT(nTimeout) + , Connection() { } + + bool Outbound::Connect() + { + try + { + uint16_t port = (uint16_t)atoi(PORT.c_str()); + CNetAddr ip(IP); + CService addr(ip, port); + SOCKET = std::make_shared(); + SOCKET->Connect(addr, TIMEOUT); + + if(Errors()) + { + Disconnect(); + + printf("Failed to Connect to Mining LLP Server...\n"); + return false; + } + + CONNECTED = true; + TIMER.Start(); + + printf("Connected to %s:%s...\n", IP.c_str(), PORT.c_str()); + + return true; + } + catch(...) { } + + CONNECTED = false; + return false; + } + + Packet Outbound::ReadNextPacket(int nTimeout) + { + Packet NULL_PACKET; + while(!PacketComplete()) + { + if(Timeout(nTimeout) || Errors()) + return NULL_PACKET; + + ReadPacket(); + + } + + return INCOMING; + } + +} diff --git a/src/LLP/outbound.h b/src/LLP/outbound.h new file mode 100644 index 0000000..89b1f4f --- /dev/null +++ b/src/LLP/outbound.h @@ -0,0 +1,25 @@ +#ifndef NEXUS_LLP_OUTBOUND_H +#define NEXUS_LLP_OUTBOUND_H + +#include "connection.h" + +namespace LLP +{ + class Outbound : public Connection + { + private: + std::string IP, PORT; + uint32_t TIMEOUT; + + public: + /** Outgoing Client Connection Constructor **/ + Outbound(std::string ip, std::string port, uint32_t nTimeOut = 10); + + bool Connect(); + + Packet ReadNextPacket(int nTimeout = 10); + + }; +} + +#endif diff --git a/src/LLP/packet.cpp b/src/LLP/packet.cpp new file mode 100644 index 0000000..f2e68cb --- /dev/null +++ b/src/LLP/packet.cpp @@ -0,0 +1,60 @@ +#include "packet.h" + +namespace LLP +{ + Packet::Packet() + { + SetNull(); + } + + /** Set the Packet Null Flags. **/ + void Packet::SetNull() + { + HEADER = 255; + LENGTH = 0; + + DATA.clear(); + } + + /** Packet Null Flag. Header = 255. **/ + bool Packet::IsNull() + { + return (HEADER == 255); + } + + /** Determine if a packet is fully read. **/ + bool Packet::Complete() + { + return (Header() && DATA.size() == LENGTH); + } + + /** Determine if header is fully read **/ + bool Packet::Header() + { + return IsNull() ? false : (HEADER < 128 && LENGTH > 0) || + (HEADER >= 128 && HEADER < 255 && LENGTH == 0); + } + + /** Sets the size of the packet from Byte Vector. **/ + void Packet::SetLength(std::vector BYTES) + { + LENGTH = (BYTES[0] << 24) + (BYTES[1] << 16) + (BYTES[2] << 8) + (BYTES[3]); + } + + /** Serializes class into a Byte Vector. Used to write Packet to Sockets. **/ + std::vector Packet::GetBytes() + { + std::vector BYTES(1, HEADER); + + /** Handle for Data Packets. **/ + if (HEADER < 128) + { + BYTES.push_back((LENGTH >> 24)); BYTES.push_back((LENGTH >> 16)); + BYTES.push_back((LENGTH >> 8)); BYTES.push_back(LENGTH); + + BYTES.insert(BYTES.end(), DATA.begin(), DATA.end()); + } + + return BYTES; + } +} diff --git a/src/LLP/packet.h b/src/LLP/packet.h new file mode 100644 index 0000000..347d2a3 --- /dev/null +++ b/src/LLP/packet.h @@ -0,0 +1,43 @@ +#ifndef NEXUS_LLP_PACKET_H +#define NEXUS_LLP_PACKET_H + +#include + +namespace LLP +{ + /** Class to handle sending and receiving of LLP Packets. **/ + class Packet + { + public: + Packet(); + + /** Components of an LLP Packet. + BYTE 0 : Header + BYTE 1 - 5 : Length + BYTE 6 - End : Data **/ + unsigned char HEADER; + unsigned int LENGTH; + std::vector DATA; + + /** Set the Packet Null Flags. **/ + void SetNull(); + + /** Packet Null Flag. Header = 255. **/ + bool IsNull(); + + /** Determine if a packet is fully read. **/ + bool Complete(); + + /** Determine if header is fully read **/ + bool Header(); + + /** Sets the size of the packet from Byte Vector. **/ + void SetLength(std::vector BYTES); + + /** Serializes class into a Byte Vector. Used to write Packet to Sockets. **/ + std::vector GetBytes(); + }; + +} + +#endif diff --git a/src/LLP/pool.cpp b/src/LLP/pool.cpp index 32a042d..77e4611 100644 --- a/src/LLP/pool.cpp +++ b/src/LLP/pool.cpp @@ -1,13 +1,13 @@ #include "pool.h" #include "daemon.h" +#include "ddos.h" #include "../core.h" #include "../util.h" #include "../base58.h" #include "../statscollector.h" #include "../LLD/record.h" #include -#include - +#include namespace LLP { @@ -21,22 +21,17 @@ namespace LLP while(!NEW_BLOCKS.empty()) { - Core::CBlock* BLOCK = NEW_BLOCKS.top(); + NEW_BLOCKS.top(); NEW_BLOCKS.pop(); - - delete BLOCK; } - - for(std::map::iterator IT = MAP_BLOCKS.begin(); IT != MAP_BLOCKS.end(); ++ IT) - delete IT->second; MAP_BLOCKS.clear(); } - void PoolConnection::AddBlock(Core::CBlock* BLOCK) + void PoolConnection::AddBlock(CBlock::Uptr BLOCK) { LOCK(BLOCK_MUTEX); - NEW_BLOCKS.push(BLOCK); + NEW_BLOCKS.push(std::move(BLOCK)); nBlocksWaiting--; } @@ -52,7 +47,7 @@ namespace LLP Packet PACKET = this->INCOMING; /** Check a Block Packet once the Header has been Read. **/ - if(fDDOS) + if(m_bDDOS) { if(PACKET.LENGTH > 136) DDOS->Ban("Max Packet Size Exceeded"); @@ -119,15 +114,15 @@ namespace LLP { LOCK(BLOCK_MUTEX); while(!NEW_BLOCKS.empty()) { - Core::CBlock* BLOCK = NEW_BLOCKS.top(); + CBlock::Sptr BLOCK{std::move(NEW_BLOCKS.top())}; NEW_BLOCKS.pop(); /** Add to the block map. **/ MAP_BLOCKS[BLOCK->GetHash()] = BLOCK; - + /** Construct a response packet by serializing the Block. **/ Packet RESPONSE = GetPacket(BLOCK_DATA); - RESPONSE.DATA = SerializeBlock(BLOCK); + RESPONSE.DATA = SerializeBlock(std::move(BLOCK)); RESPONSE.LENGTH = RESPONSE.DATA.size(); this->WritePacket(RESPONSE); @@ -172,7 +167,7 @@ namespace LLP /** Multiply DDOS Score for Multiple Logins after Successful Login. **/ if(fLoggedIn) { - if(fDDOS) + if(m_bDDOS) DDOS->rSCORE += 10; return true; @@ -186,15 +181,16 @@ namespace LLP if(!cAddress.IsValid() ) { printf("[THREAD] Pool LLP: Bad Account %s\n", ADDRESS.c_str()); - if(fDDOS) + if(m_bDDOS) DDOS->Ban("Invalid Nexus Address on Login"); return false; - } - - std::string ip_address = GetIPAddress(); + } + + std::string ip_address = GetRemoteIPAddress(); + std::cout << "[THREAD] Pool Login: " << ADDRESS << "\t IP:" << ip_address + << "\t (" << Core::STATSCOLLECTOR.GetConnectionCount(ADDRESS) << " connections)" << std::endl; - printf("[THREAD] Pool Login: %s\t IP:%s\t (%d connections)\n", ADDRESS.c_str(), ip_address.c_str(), Core::STATSCOLLECTOR.GetConnectionCount(ADDRESS) ); if(!Core::AccountDB.HasKey(ADDRESS)) { LLD::Account cNewAccount(ADDRESS); @@ -204,7 +200,6 @@ namespace LLP printf("[ACCOUNT] New Account %s\n", ADDRESS.c_str()); printf("\n+++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); } - if(IsBannedAccount(ADDRESS) ) { @@ -219,8 +214,7 @@ namespace LLP DDOS->Ban("Account is Banned"); - fLoggedIn = false; - + fLoggedIn = false; } else { @@ -229,13 +223,10 @@ namespace LLP //PS // QUICK HACK these are google cloud and amazon AWS IP ranges which we should allow // so don't add CHECK to debug.log - if( !boost::starts_with(ip_address, "104.") && !boost::starts_with(ip_address, "130.") - && !boost::starts_with(ip_address, "23.") && !boost::starts_with(ip_address, "54.") && !boost::starts_with(ip_address, "52.")) - printf("[ACCOUNT] Account: CHECK Address: %s IP: %s\n", ADDRESS.c_str(), ip_address.c_str() ); // this allows you to grep the debug.log for CHECK and eyeball the frequency and ip addresses - - } - - + if((ip_address.find("104.") != 0) && (ip_address.find("130.") != 0) + && (ip_address.find("23.") != 0) && (ip_address.find("54.") != 0) && (ip_address.find("52.") != 0)) + std::cout << "[ACCOUNT] Account: CHECK Address: " << ADDRESS << " IP: " << ip_address << std::endl; // this allows you to grep the debug.log for CHECK and eyeball the frequency and ip addresses + } return true; } @@ -245,7 +236,7 @@ namespace LLP if(!fLoggedIn) { /** Amplify rScore for Requests before Logged in [Prevent DDOS this way]. **/ - if(fDDOS) + if(m_bDDOS) DDOS->rSCORE += 10; printf("[THREAD] Pool LLP: Not Logged In. Rejected Request.\n"); @@ -267,8 +258,8 @@ namespace LLP LOCK(BLOCK_MUTEX); nBlockRequests++; - if(fDDOS) - DDOS->rSCORE += 1; + if(m_bDDOS) + DDOS->rSCORE += 1; return true; } @@ -283,7 +274,7 @@ namespace LLP { uint1024 hashPrimeOrigin; hashPrimeOrigin.SetBytes(std::vector(PACKET.DATA.begin(), PACKET.DATA.end() - 8)); - + /** Don't Accept a Share with no Correlated Block. **/ if(!MAP_BLOCKS.count(hashPrimeOrigin)) @@ -292,7 +283,7 @@ namespace LLP printf("[THREAD] Pool LLP: Block Not Found %s\n", hashPrimeOrigin.ToString().substr(0, 30).c_str()); Respond(NEW_BLOCK); - if(fDDOS) + if(m_bDDOS) DDOS->rSCORE += 1; return true; @@ -306,7 +297,7 @@ namespace LLP Respond(NEW_BLOCK); /** Be Lenient on Stale Shares [But Still amplify score above normal 1 per request.] **/ - if(fDDOS) + if(m_bDDOS) DDOS->rSCORE += 2; return true; @@ -326,7 +317,7 @@ namespace LLP Respond(REJECT); /** Give a Heavy Score for Duplicates. [To Amplify the already existing ++ per Request.] **/ - if(fDDOS) + if(m_bDDOS) DDOS->rSCORE += 5; return true; @@ -342,7 +333,7 @@ namespace LLP //Timer GMP_TIMER; //GMP_TIMER.Start(); - double nDifficulty = Core::GmpVerification(CBigNum(hashPrime)); + double nDifficulty = Core::GmpVerification(hashPrime); //GMP_TIMER.Stop(); if(Core::SetBits(nDifficulty) >= Core::nMinimumShare) @@ -389,7 +380,7 @@ namespace LLP printf("[THREAD] Share Below Difficulty %f\n", nDifficulty); /** Give Heavy Score for Below Difficulty Shares. Would require at least 4 per Second to fulfill a score of 20. **/ - if(fDDOS) + if(m_bDDOS) DDOS->rSCORE += 5; Respond(REJECT); @@ -424,7 +415,7 @@ namespace LLP RESPONSE.DATA = uint2bytes64(nPendingPayout); //printf("[THREAD] Pool LLP: Account %s --> Payout Data Requested.\n", ADDRESS.c_str()); - this->WritePacket(RESPONSE); + this->WritePacket(RESPONSE); return true; } @@ -450,7 +441,7 @@ namespace LLP } /** Convert the Header of a Block into a Byte Stream for Reading and Writing Across Sockets. **/ - std::vector PoolConnection::SerializeBlock(Core::CBlock* BLOCK) + std::vector PoolConnection::SerializeBlock(CBlock::Sptr BLOCK) { std::vector HASH = BLOCK->GetHash().GetBytes(); std::vector MINIMUM = uint2bytes(Core::nMinimumShare); diff --git a/src/LLP/pool.h b/src/LLP/pool.h index fce352f..1a24b8c 100644 --- a/src/LLP/pool.h +++ b/src/LLP/pool.h @@ -1,12 +1,15 @@ -#ifndef COINSHIELD_POOLSERVER_H -#define COINSHIELD_POOLSERVER_H +#ifndef NEXUS_POOLSERVER_H +#define NEXUS_POOLSERVER_H #include +#include +#include #include "types.h" +#include "block.h" +#include "connection.h" #include "../hash/uint1024.h" -namespace Core { class CBlock; } namespace LLP { /** Forward Declarations. **/ @@ -16,13 +19,15 @@ namespace LLP /** Template Connection to be used by LLP Server. **/ class PoolConnection : public Connection { - std::map MAP_BLOCKS; - std::stack NEW_BLOCKS; + std::map MAP_BLOCKS; + std::stack NEW_BLOCKS; DaemonHandle* DAEMON; Timer BLOCK_TIMER; bool fLoggedIn = false; + /** Flag to Determine if DDOS is Enabled. **/ + bool m_bDDOS = false; enum { @@ -58,16 +63,14 @@ namespace LLP void Clear(); public: - boost::mutex BLOCK_MUTEX; + + std::mutex BLOCK_MUTEX; PoolConnection() : Connection(), BLOCK_TIMER() {} - PoolConnection( Socket_t SOCKET_IN, DDOS_Filter* DDOS_IN, bool isDDOS) : Connection( SOCKET_IN, DDOS_IN, isDDOS ), BLOCK_TIMER() {} + // PoolConnection( Socket_t SOCKET_IN, DDOS_Filter* DDOS_IN, bool isDDOS) : Connection( SOCKET_IN, DDOS_IN, isDDOS ), BLOCK_TIMER() {} ~PoolConnection() - { - for(std::map::iterator IT = MAP_BLOCKS.begin(); IT != MAP_BLOCKS.end(); ++ IT) - delete IT->second; - + { MAP_BLOCKS.clear(); } @@ -84,13 +87,13 @@ namespace LLP std::string GUID; /** Block Set by Connection if it is Above Difficulty. **/ - Core::CBlock* SUBMISSION_BLOCK = NULL; + CBlock::Sptr SUBMISSION_BLOCK = nullptr; /** Mutex for Modifying Submission Block Pointer. **/ - boost::mutex SUBMISSION_MUTEX; + std::mutex SUBMISSION_MUTEX; /** Add a Block to the Pool Connection Stacks. **/ - void AddBlock(Core::CBlock* BLOCK); + void AddBlock(CBlock::Uptr BLOCK); /** Event Function to Customize Code For Inheriting Class Happening on the LLP Data Threads. **/ void Event(unsigned char EVENT, unsigned int LENGTH = 0); @@ -112,7 +115,7 @@ namespace LLP inline void Respond(unsigned char HEADER) { this->WritePacket(GetPacket(HEADER)); } /** Convert the Header of a Block into a Byte Stream for Reading and Writing Across Sockets. **/ - inline std::vector SerializeBlock(Core::CBlock* BLOCK); + inline std::vector SerializeBlock(CBlock::Sptr BLOCK); }; } diff --git a/src/LLP/server.h b/src/LLP/server.h index 6432748..a087c8e 100644 --- a/src/LLP/server.h +++ b/src/LLP/server.h @@ -1,7 +1,9 @@ #ifndef COINSHIELD_LLP_SERVER_H #define COINSHIELD_LLP_SERVER_H -#include "types.h" +//#include "types.h" +#include "ddos.h" +#include "socket.h" namespace LLP { @@ -17,12 +19,10 @@ namespace LLP Thread_t DATA_THREAD; public: - - /** Service that is used to handle Connections on this Thread. **/ - Service_t IO_SERVICE; /** Variables to track Connection / Request Count. **/ - bool fDDOS; unsigned int nConnections, ID, REQUESTS, TIMEOUT, DDOS_rSCORE, DDOS_cSCORE; + bool fDDOS; + unsigned int nConnections, ID, REQUESTS, TIMEOUT, DDOS_rSCORE, DDOS_cSCORE; /** Vector to store Connections. **/ std::vector< ProtocolType* > CONNECTIONS; @@ -155,15 +155,25 @@ namespace LLP } } - DataThread(unsigned int id, bool isDDOS, unsigned int rScore, unsigned int cScore, unsigned int nTimeout) : - ID(id), fDDOS(isDDOS), DDOS_rSCORE(rScore), DDOS_cSCORE(cScore), TIMEOUT(nTimeout), REQUESTS(0), CONNECTIONS(0), nConnections(0), DATA_THREAD(boost::bind(&DataThread::Thread, this)){ } + DataThread(unsigned int id, bool isDDOS, unsigned int rScore, unsigned int cScore, unsigned int nTimeout) + : ID(id) + , fDDOS(isDDOS) + , DDOS_rSCORE(rScore) + , DDOS_cSCORE(cScore) + , TIMEOUT(nTimeout) + , REQUESTS(0) + , CONNECTIONS(0) + , nConnections(0) + , DATA_THREAD(std::bind(&DataThread::Thread, this)) + { } }; /** Base Class to create a Custom LLP Server. Protocol Type class must inherit Connection, and provide a ProcessPacket method. Optional Events by providing GenericEvent method. **/ - template class Server + template + class Server { /** The DDOS variables. Tracks the Requests and Connections per Second from each connected address. **/ @@ -178,8 +188,13 @@ namespace LLP std::vector< DataThread* > DATA_THREADS; - Server(int nPort, int nMaxThreads, bool isDDOS, int cScore, int rScore, int nTimeout) : - fDDOS(isDDOS), LISTENER(SERVICE), PORT(nPort), MAX_THREADS(nMaxThreads), METER_THREAD(boost::bind(&Server::MeterThread, this)), LISTEN_THREAD(boost::bind(&Server::ListeningThread, this)) + Server(int nPort, int nMaxThreads, bool isDDOS, int cScore, int rScore, int nTimeout) + : fDDOS(isDDOS), + LISTENER(SERVICE), + PORT(nPort), + MAX_THREADS(nMaxThreads), + METER_THREAD(std::bind(&Server::MeterThread, this)), + LISTEN_THREAD(std::bind(&Server::ListeningThread, this)) { for(int index = 0; index < MAX_THREADS; index++) DATA_THREADS.push_back(new DataThread(index, fDDOS, rScore, cScore, nTimeout)); @@ -188,9 +203,6 @@ namespace LLP private: /** Basic Socket Handle Variables. **/ - Service_t SERVICE; - Listener_t LISTENER; - Error_t ERROR_HANDLE; Thread_t LISTEN_THREAD; Thread_t METER_THREAD; @@ -199,7 +211,8 @@ namespace LLP This keeps the load balanced across all server threads. **/ int FindThread() { - int nIndex = 0, nConnections = DATA_THREADS[0]->nConnections; + int nIndex = 0, + nConnections = DATA_THREADS[0]->nConnections; for(int index = 1; index < MAX_THREADS; index++) { if(DATA_THREADS[index]->nConnections < nConnections) @@ -286,12 +299,9 @@ namespace LLP /** DDOS Operations: Only executed when DDOS is enabled. **/ if(fDDOS && DDOS_MAP[ADDRESS]->Banned()) { - SOCKET -> shutdown(boost::asio::ip::tcp::socket::shutdown_both, ERROR_HANDLE); - SOCKET -> close(); - + SOCKET->Close(); continue; - } - + } /** Add new connection if passed all DDOS checks. **/ DATA_THREADS[nThread]->AddConnection(SOCKET, DDOS_MAP[ADDRESS]); diff --git a/src/LLP/socket.cpp b/src/LLP/socket.cpp new file mode 100644 index 0000000..049233d --- /dev/null +++ b/src/LLP/socket.cpp @@ -0,0 +1,218 @@ +/*__________________________________________________________________________________________ + + (c) Hash(BEGIN(Satoshi[2010]), END(Sunny[2012])) == Videlicet[2018] ++ + + (c) Copyright The Nexus Developers 2014 - 2018 + + Distributed under the MIT software license, see the accompanying + file COPYING or http://www.opensource.org/licenses/mit-license.php. + + "ad vocem populi" - To the Voice of the People + +____________________________________________________________________________________________*/ + + +#include "socket.h" +#include + +#ifndef WIN32 +#include +#include +#include +#endif + +#include +#include +#include +#include +#include + + +namespace LLP +{ + + /* Constructor for Address */ + Socket::Socket(CService addrConnect) + { + Connect(addrConnect); + } + + + /* Returns the error of socket if any */ + int Socket::Error() + { + if (nError == WSAEWOULDBLOCK || nError == WSAEMSGSIZE || nError == WSAEINTR || nError == WSAEINPROGRESS) + return 0; + + return nError; + } + + + /* Connects the socket to an external address */ + bool Socket::Connect(CService addrDest, int nTimeout) + { + /* Create the Socket Object (Streaming TCP/IP). */ + nSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + /* Catch failure if socket couldn't be initialized. */ + if (nSocket == INVALID_SOCKET) + return false; + + /* Set the socket address from the CService. */ + struct sockaddr_in sockaddr; + addrDest.GetSockAddr(&sockaddr); + + /* Copy in the new address. */ + addr = CAddress(sockaddr); + + /* Open the socket connection. */ + if (connect(nSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) + { + // WSAEINVAL is here because some legacy version of winsock uses it + if (GetLastError() == WSAEINPROGRESS || GetLastError() == WSAEWOULDBLOCK || GetLastError() == WSAEINVAL) + { + struct timeval timeout; + timeout.tv_sec = nTimeout / 1000; + timeout.tv_usec = (nTimeout % 1000) * 1000; + + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(nSocket, &fdset); + int nRet = select(nSocket + 1, NULL, &fdset, NULL, &timeout); + + /* If the connection attempt timed out with select. */ + if (nRet == 0) + { + printf("***** Node Connection Timeout %s...\n", addrDest.ToString().c_str()); + + Close(); + + return false; + } + + /* If the select failed. */ + if (nRet == SOCKET_ERROR) + { + printf("***** Node Select Failed %s (%i)\n", addrDest.ToString().c_str(), GetLastError()); + + Close(); + + return false; + } + + /* Get socket options. TODO: Remove preprocessors for cross platform sockets. */ + socklen_t nRetSize = sizeof(nRet); + #ifdef WIN32 + if (getsockopt(nSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR) + #else + if (getsockopt(nSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) + #endif + { + printf("***** Node Get Options Failed %s (%i)\n", addrDest.ToString().c_str(), GetLastError()); + Close(); + + return false; + } + + /* If there are no socket options set. TODO: Remove preprocessors for cross platform sockets. */ + if (nRet != 0) + { + printf("***** Node Failed after Select %s (%i)\n", addrDest.ToString().c_str(), nRet); + Close(); + + return false; + } + } + #ifdef WIN32 + else if (GetLastError() != WSAEISCONN) + #else + else + #endif + { + printf("***** Node Connect Failed %s (%i)\n", addrDest.ToString().c_str(), GetLastError()); + Close(); + + return false; + } + } + + return true; + } + + + /* Poll the socket to check for available data */ + int Socket::Available() + { + uint32_t nAvailable = 0; + #ifdef WIN32 + ioctlsocket(nSocket, FIONREAD, (unsigned long *)&nAvailable); + #else + ioctl(nSocket, FIONREAD, &nAvailable); + #endif + + return nAvailable; + } + + + /* Clear resources associated with socket and return to invalid state. */ + void Socket::Close() + { + #ifdef WIN32 + closesocket(nSocket); + #else + close(nSocket); + #endif + nSocket = INVALID_SOCKET; + } + + + /* Read data from the socket buffer non-blocking */ + int Socket::Read(std::vector &vData, const size_t nBytes) + { + std::string pchBuf(nBytes, 0); + int nRead = recv(nSocket, &pchBuf[0], nBytes, MSG_DONTWAIT); + if (nRead < 0) + { + nError = GetLastError(); + //if(config::GetArg("-verbose", 0) >= 2) + printf("xxxxx Node Read Failed %s (%i %s)\n", addr.ToString().c_str(), nError, strerror(nError)); + + return nError; + } + + if(nRead > 0) + std::copy(&pchBuf[0], &pchBuf[0] + nRead, vData.begin()); + + return nRead; + } + + + /* Write data into the socket buffer non-blocking */ + int Socket::Write(std::vector vData, const size_t nBytes) + { + std::string pchBuf(nBytes, 0); + + std::copy(&vData[0], &vData[0] + nBytes, &pchBuf[0]); + + /* If there were any errors, handle them gracefully. */ + int nSent = send(nSocket, pchBuf.c_str(), nBytes, MSG_NOSIGNAL | MSG_DONTWAIT ); + if(nSent < 0) + { + nError = GetLastError(); + //if(config::GetArg("-verbose", 0) >= 2) + printf("xxxxx Node Write Failed %s (%i %s)\n", addr.ToString().c_str(), nError, strerror(nError)); + + return nError; + } + + /* If not all data was sent non-blocking, recurse until it is complete. */ + else if(nSent != vData.size()) + { + vData.erase(vData.begin(), vData.begin() + nSent); + + return Write(vData, vData.size()); + } + + return nSent; + } +} diff --git a/src/LLP/socket.h b/src/LLP/socket.h new file mode 100644 index 0000000..ee5ad33 --- /dev/null +++ b/src/LLP/socket.h @@ -0,0 +1,131 @@ +/*__________________________________________________________________________________________ + + (c) Hash(BEGIN(Satoshi[2010]), END(Sunny[2012])) == Videlicet[2018] ++ + + (c) Copyright The Nexus Developers 2014 - 2018 + + Distributed under the MIT software license, see the accompanying + file COPYING or http://www.opensource.org/licenses/mit-license.php. + + "ad vocem populi" - To the Voice of the People + +____________________________________________________________________________________________*/ + +#ifndef NEXUS_LLP_TEMPLATES_SOCKET_H +#define NEXUS_LLP_TEMPLATES_SOCKET_H + +#include "network.h" +#include +#include + +namespace LLP +{ + class CService; + class CAddress; + + /* Base Template class to handle outgoing / incoming LLP data for both Client and Server. */ + class Socket + { + protected: + + /** The socket file identifier. **/ + int nSocket; + + /** The error codes for socket. **/ + int nError; + + public: + + /** The address of this connection. */ + CAddress addr; + + + /** The default constructor. **/ + Socket() : nSocket(0), nError(0) {} + + + /** The socket constructor. **/ + Socket(int nSocketIn, CAddress addrIn) : nSocket(nSocketIn), nError(0), addr(addrIn) {} + + + /** Constructor for Address + * + * @param[in] addrConnect The address to connect socket to + * + **/ + Socket(CService addrDest); + + + + /** Error + * + * Returns the error of socket if any + * + * @return error code of the socket + * + **/ + int Error(); + + + /** Connect + * + * Connects the socket to an external address + * + * @param[in] addrConnect The address to connect to + * + * @return true if the socket is in a valid state. + * + **/ + bool Connect(CService addrDest, int nTimeout = 5000); + + + /** Available + * + * Poll the socket to check for available data + * + * @return the total bytes available for read + * + **/ + int Available(); + + + /** Close + * + * Clear resources associated with socket and return to invalid state. + * + **/ + void Close(); + + + /** Read + * + * Read data from the socket buffer non-blocking + * + * @param[out] vData The byte vector to read into + * @param[in] nBytes The total bytes to read + * + * @return the total bytes that were read + * + **/ + int Read(std::vector &vData, const size_t nBytes); + + + /** Write + * + * Write data into the socket buffer non-blocking + * + * @param[in] vData The byte vector of data to be written + * @param[in] nBytes The total bytes to write + * + * @return the total bytes that were written + * + **/ + int Write(std::vector vData, const size_t nBytes); + }; + + /** Type Definitions for LLP Functions **/ + typedef Socket Socket_t; + +} + +#endif diff --git a/src/LLP/timer.cpp b/src/LLP/timer.cpp new file mode 100644 index 0000000..4bc195a --- /dev/null +++ b/src/LLP/timer.cpp @@ -0,0 +1,53 @@ +#include "timer.h" +namespace LLP +{ + /* Contructs timer class with stopped set to false. */ + Timer::Timer() : fStopped(false) {} + + /* Capture the start time with a high resolution clock. Sets stopped to false. */ + void Timer::Start() + { + start_time = std::chrono::high_resolution_clock::now(); + fStopped = false; + } + + /* Used as another alias for calling Start() */ + void Timer::Reset() + { + Start(); + } + + /* Capture the end time with a high resolution clock. Sets stopped to true. */ + void Timer::Stop() + { + end_time = std::chrono::high_resolution_clock::now(); + fStopped = true; + } + + /* Return the Total Seconds Elapsed Since Timer Started. */ + uint32_t Timer::Elapsed() + { + if(fStopped) + return std::chrono::duration_cast(end_time - start_time).count(); + + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start_time).count(); + } + + /* Return the Total Milliseconds Elapsed Since Timer Started. */ + uint32_t Timer::ElapsedMilliseconds() + { + if(fStopped) + return std::chrono::duration_cast(end_time - start_time).count(); + + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start_time).count(); + } + + /* Return the Total Microseconds Elapsed since Time Started. */ + uint64_t Timer::ElapsedMicroseconds() + { + if(fStopped) + return std::chrono::duration_cast(end_time - start_time).count(); + + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start_time).count(); + } +} diff --git a/src/LLP/timer.h b/src/LLP/timer.h new file mode 100644 index 0000000..737bf36 --- /dev/null +++ b/src/LLP/timer.h @@ -0,0 +1,88 @@ +#ifndef NEXUS_LLP_TIMER_H +#define NEXUS_LLP_TIMER_H + +#include +#include + +namespace LLP +{ + + /** Timer + * + * Class the tracks the duration of time elapsed in seconds or milliseconds. + * Used for socket timers to determine time outs. + * + **/ + class Timer + { + private: + std::chrono::high_resolution_clock::time_point start_time; + std::chrono::high_resolution_clock::time_point end_time; + bool fStopped; + + public: + + /** Timer + * + * Contructs timer class with stopped set to false. + * + **/ + Timer(); + + + /** Start + * + * Capture the start time with a high resolution clock. Sets stopped to false. + * + **/ + void Start(); + + + /** Reset + * + * Used as another alias for calling Start() + * + **/ + void Reset(); + + + /** Stop + * + * Capture the end time with a high resolution clock. Sets stopped to true. + * + **/ + void Stop(); + + + /** Elapsed + * + * Return the Total Seconds Elapsed Since Timer Started. + * + * @return The Total Seconds Elapsed Since Timer Started. + * + **/ + uint32_t Elapsed(); + + + /** ElapsedMilliseconds + * + * Return the Total Milliseconds Elapsed Since Timer Started. + * + * @return The Total Milliseconds Elapsed Since Timer Started. + * + **/ + uint32_t ElapsedMilliseconds(); + + + /** ElapsedMicroseconds + * + * Return the Total Microseconds Elapsed since Time Started. + * + * @return The Total Microseconds Elapsed since Time Started. + * + **/ + uint64_t ElapsedMicroseconds(); + }; +} + +#endif diff --git a/src/LLP/types.h b/src/LLP/types.h index f3787a1..4c21876 100644 --- a/src/LLP/types.h +++ b/src/LLP/types.h @@ -1,15 +1,11 @@ -#ifndef COINSHIELD_LLP_TYPES_H -#define COINSHIELD_LLP_TYPES_H - -#include +#ifndef NEXUS_LLP_TYPES_H +#define NEXUS_LLP_TYPES_H #include #include -#include -#include -#include -#include -#include +#include +#include +#include #include "../util.h" @@ -28,397 +24,227 @@ namespace LLP /** Type Definitions for LLP Functions **/ - typedef boost::shared_ptr Socket_t; - typedef boost::asio::ip::tcp::acceptor Listener_t; - typedef boost::asio::io_service Service_t; - typedef boost::thread Thread_t; - typedef boost::system::error_code Error_t; - typedef boost::mutex Mutex_t; - + //typedef boost::shared_ptr Socket_t; + typedef std::thread Thread_t; + typedef std::mutex Mutex_t; /** Sleep for a duration in Milliseconds. **/ - inline void Sleep(unsigned int nTime){ boost::this_thread::sleep(boost::posix_time::milliseconds(nTime)); } - - - - /** Class the tracks the duration of time elapsed in seconds or milliseconds. - Used for socket timers to determine time outs. **/ - class Timer - { - private: - boost::posix_time::ptime TIMER_START, TIMER_END; - bool fStopped = false; - - public: - inline void Start() { TIMER_START = boost::posix_time::microsec_clock::local_time(); fStopped = false; } - inline void Reset() { Start(); } - inline void Stop() { TIMER_END = boost::posix_time::microsec_clock::local_time(); fStopped = true; } - - /** Return the Total Seconds Elapsed Since Timer Started. **/ - unsigned int Elapsed() - { - if(fStopped) - return (TIMER_END - TIMER_START).total_seconds(); - - return (boost::posix_time::microsec_clock::local_time() - TIMER_START).total_seconds(); - } - - /** Return the Total Milliseconds Elapsed Since Timer Started. **/ - unsigned int ElapsedMilliseconds() - { - if(fStopped) - return (TIMER_END - TIMER_START).total_milliseconds(); - - return (boost::posix_time::microsec_clock::local_time() - TIMER_START).total_milliseconds(); - } - }; - - - /** Class that tracks DDOS attempts on LLP Servers. - Uses a Timer to calculate Request Score [rScore] and Connection Score [cScore] as a unit of Score / Second. - Pointer stored by Connection class and Server Listener DDOS_MAP. **/ - class DDOS_Score - { - std::vector< std::pair > SCORE; - Timer TIMER; - int nIterator; - Mutex_t MUTEX; - - - /** Reset the Timer and the Score Flags to be Overwritten. **/ - void Reset() - { - for(int i = 0; i < SCORE.size(); i++) - SCORE[i].first = false; - - TIMER.Reset(); - nIterator = 0; - } - - public: - - /** Construct a DDOS Score of Moving Average Timespan. **/ - DDOS_Score(int nTimespan) - { - LOCK(MUTEX); - - for(int i = 0; i < nTimespan; i++) - SCORE.push_back(std::make_pair(true, 0)); - - TIMER.Start(); - nIterator = 0; - } - - - /** Flush the DDOS Score to 0. **/ - void Flush() - { - LOCK(MUTEX); - - Reset(); - for(int i = 0; i < SCORE.size(); i++) - SCORE[i].second = 0; - } - - - /** Access the DDOS Score from the Moving Average. **/ - int Score() - { - LOCK(MUTEX); - - int nMovingAverage = 0; - for(int i = 0; i < SCORE.size(); i++) - nMovingAverage += SCORE[i].second; - - return nMovingAverage / SCORE.size(); - } - - - /** Increase the Score by nScore. Operates on the Moving Average to Increment Score per Second. **/ - DDOS_Score & operator+=(const int& nScore) - { - LOCK(MUTEX); - - int nTime = TIMER.Elapsed(); - - - /** If the Time has been greater than Moving Average Timespan, Set to Add Score on Time Overlap. **/ - if(nTime >= SCORE.size()) - { - Reset(); - nTime = nTime % SCORE.size(); - } - - - /** Iterate as many seconds as needed, flagging that each has been iterated. **/ - for(int i = nIterator; i <= nTime; i++) - { - if(!SCORE[i].first) - { - SCORE[i].first = true; - SCORE[i].second = 0; - } - } - - - /** Update the Moving Average Iterator and Score for that Second Instance. **/ - SCORE[nTime].second += nScore; - nIterator = nTime; - - - return *this; - } - }; - - - /** Filter to Contain DDOS Scores and Handle DDOS Bans. **/ - class DDOS_Filter - { - Timer TIMER; - unsigned int BANTIME, TOTALBANS; - - public: - DDOS_Score rSCORE, cSCORE; - std::string IPADDRESS; - DDOS_Filter(unsigned int nTimespan, std::string strIPAddress) : rSCORE(nTimespan), cSCORE(nTimespan), IPADDRESS(strIPAddress), BANTIME(0), TOTALBANS(0) { } - Mutex_t MUTEX; - - /** Ban a Connection, and Flush its Scores. **/ - void Ban(std::string strMessage = "Score Threshold Ban") - { - LOCK(MUTEX); - - if(Banned()) - return; - - TIMER.Start(); - TOTALBANS++; - - BANTIME = std::max(TOTALBANS * (rSCORE.Score() + 1) * (cSCORE.Score() + 1), TOTALBANS * 1200u); - - printf("XXXXX DDOS Filter Address = %s cScore = %i rScore = %i Banned for %u Seconds. Violation: %s\n", IPADDRESS.c_str(), cSCORE.Score(), rSCORE.Score(), BANTIME, strMessage.c_str()); - - cSCORE.Flush(); - rSCORE.Flush(); - } - - /** Check if Connection is Still Banned. **/ - bool Banned() { return (TIMER.Elapsed() < BANTIME); } - }; - - + void Sleep(unsigned int nMilliseconds) + { + std::this_thread::sleep_for(std::chrono::milliseconds(nMilliseconds)); + } - /** Class to handle sending and receiving of LLP Packets. **/ - class Packet - { - public: - Packet() { SetNull(); } - - /** Components of an LLP Packet. - BYTE 0 : Header - BYTE 1 - 5 : Length - BYTE 6 - End : Data **/ - unsigned char HEADER; - unsigned int LENGTH; - std::vector DATA; - - - /** Set the Packet Null Flags. **/ - inline void SetNull() - { - HEADER = 255; - LENGTH = 0; - - DATA.clear(); - } - - - /** Packet Null Flag. Header = 255. **/ - bool IsNull() { return (HEADER == 255); } - - - /** Determine if a packet is fully read. **/ - bool Complete() { return (Header() && DATA.size() == LENGTH); } - - - /** Determine if header is fully read **/ - bool Header() { return IsNull() ? false : (HEADER < 128 && LENGTH > 0) || (HEADER >= 128 && HEADER < 255 && LENGTH == 0); } - - - /** Sets the size of the packet from Byte Vector. **/ - void SetLength(std::vector BYTES) { LENGTH = (BYTES[0] << 24) + (BYTES[1] << 16) + (BYTES[2] << 8) + (BYTES[3] ); } - - - /** Serializes class into a Byte Vector. Used to write Packet to Sockets. **/ - std::vector GetBytes() - { - std::vector BYTES(1, HEADER); - - /** Handle for Data Packets. **/ - if(HEADER < 128) - { - BYTES.push_back((LENGTH >> 24)); BYTES.push_back((LENGTH >> 16)); - BYTES.push_back((LENGTH >> 8)); BYTES.push_back(LENGTH); - - BYTES.insert(BYTES.end(), DATA.begin(), DATA.end()); - } - - return BYTES; - } - }; - - + ///** Class to handle sending and receiving of LLP Packets. **/ + //class Packet + //{ + //public: + // Packet() { SetNull(); } + // + // /** Components of an LLP Packet. + // BYTE 0 : Header + // BYTE 1 - 5 : Length + // BYTE 6 - End : Data **/ + // unsigned char HEADER; + // unsigned int LENGTH; + // std::vector DATA; + // + // + // /** Set the Packet Null Flags. **/ + // inline void SetNull() + // { + // HEADER = 255; + // LENGTH = 0; + // + // DATA.clear(); + // } + // + // + // /** Packet Null Flag. Header = 255. **/ + // bool IsNull() { return (HEADER == 255); } + // + // + // /** Determine if a packet is fully read. **/ + // bool Complete() { return (Header() && DATA.size() == LENGTH); } + // + // + // /** Determine if header is fully read **/ + // bool Header() { return IsNull() ? false : (HEADER < 128 && LENGTH > 0) || (HEADER >= 128 && HEADER < 255 && LENGTH == 0); } + // + // + // /** Sets the size of the packet from Byte Vector. **/ + // void SetLength(std::vector BYTES) { LENGTH = (BYTES[0] << 24) + (BYTES[1] << 16) + (BYTES[2] << 8) + (BYTES[3] ); } + // + // + // /** Serializes class into a Byte Vector. Used to write Packet to Sockets. **/ + // std::vector GetBytes() + // { + // std::vector BYTES(1, HEADER); + // + // /** Handle for Data Packets. **/ + // if(HEADER < 128) + // { + // BYTES.push_back((LENGTH >> 24)); BYTES.push_back((LENGTH >> 16)); + // BYTES.push_back((LENGTH >> 8)); BYTES.push_back(LENGTH); + // + // BYTES.insert(BYTES.end(), DATA.begin(), DATA.end()); + // } + // + // return BYTES; + // } + //}; + // + // - /** Base Template class to handle outgoing / incoming LLP data for both Client and Server. **/ - class Connection - { - protected: - - /** Basic Connection Variables. **/ - Timer TIMER; - Error_t ERROR_HANDLE; - Socket_t SOCKET; - - - /** - Virtual Event Function to be Overridden allowing Custom Read Events. - Each event fired on Header Complete, and each time data is read to fill packet. - Useful to check Header length to maximum size of packet type for DDOS protection, - sending a keep-alive ping while downloading large files, etc. - - LENGTH == 0: General Events - LENGTH > 0 && PACKET: Read nSize Bytes into Data Packet - **/ - virtual void Event(unsigned char EVENT, unsigned int LENGTH = 0){ } - - /** Virtual Process Function. To be overridden with your own custom packet processing. **/ - virtual bool ProcessPacket() { return true; } - public: - - - /** Incoming Packet Being Built. **/ - Packet INCOMING; - - - /** DDOS Score if a Incoming Server Connection. **/ - DDOS_Filter* DDOS; - - - /** Connected Flag. **/ - bool CONNECTED; - - - /** Flag to Determine if DDOS is Enabled. **/ - bool fDDOS; - - - /** Connection Constructors **/ - Connection() : SOCKET(), DDOS(NULL), INCOMING(), CONNECTED(false), fDDOS(false) { INCOMING.SetNull(); } - Connection( Socket_t SOCKET_IN, DDOS_Filter* DDOS_IN, bool isDDOS ) : SOCKET(SOCKET_IN), fDDOS(isDDOS), DDOS(DDOS_IN), INCOMING(), CONNECTED(false) { TIMER.Start(); } - - - /** Checks for any flags in the Error Handle. **/ - bool Errors(){ return (ERROR_HANDLE == boost::asio::error::eof || ERROR_HANDLE); } - - - /** Determines if nTime seconds have elapsed since last Read / Write. **/ - bool Timeout(unsigned int nTime){ return (TIMER.Elapsed() >= nTime); } - - - /** Determines if Connected or Not. **/ - bool Connected(){ return CONNECTED; } - - - /** Handles two types of packets, requests which are of header >= 128, and data which are of header < 128. **/ - bool PacketComplete(){ return INCOMING.Complete(); } - - - /** Used to reset the packet to Null after it has been processed. This then flags the Connection to read another packet. **/ - void ResetPacket(){ INCOMING.SetNull(); } - - - /** Write a single packet to the TCP stream. **/ - void WritePacket(Packet PACKET) { Write(PACKET.GetBytes()); } - - - /** Non-Blocking Packet reader to build a packet from TCP Connection. - This keeps thread from spending too much time for each Connection. **/ - void ReadPacket() - { - - /** Handle Reading Packet Type Header. **/ - if(SOCKET->available() > 0 && INCOMING.IsNull()) - { - std::vector HEADER(1, 255); - if(Read(HEADER, 1) == 1) - INCOMING.HEADER = HEADER[0]; - - } - - if(!INCOMING.IsNull() && !INCOMING.Complete()) - { - /** Handle Reading Packet Length Header. **/ - if(SOCKET->available() >= 4 && INCOMING.LENGTH == 0) - { - std::vector BYTES(4, 0); - if(Read(BYTES, 4) == 4) - { - INCOMING.SetLength(BYTES); - Event(EVENT_HEADER); - } - } - - /** Handle Reading Packet Data. **/ - unsigned int nAvailable = SOCKET->available(); - if(nAvailable > 0 && INCOMING.LENGTH > 0 && INCOMING.DATA.size() < INCOMING.LENGTH) - { - std::vector DATA( std::min(nAvailable, (unsigned int)(INCOMING.LENGTH - INCOMING.DATA.size())), 0); - unsigned int nRead = Read(DATA, DATA.size()); - - if(nRead == DATA.size()) - { - INCOMING.DATA.insert(INCOMING.DATA.end(), DATA.begin(), DATA.end()); - Event(EVENT_PACKET, nRead); - } - } - } - } - - - /** Disconnect Socket. Cleans up memory usage to prevent "memory runs" from poor memory management. **/ - void Disconnect() - { - if(!CONNECTED) - return; - - try - { - SOCKET -> shutdown(boost::asio::ip::tcp::socket::shutdown_both, ERROR_HANDLE); - SOCKET -> close(); - } - catch(...){} - - CONNECTED = false; - } + ///** Base Template class to handle outgoing / incoming LLP data for both Client and Server. **/ + //class Connection + //{ + //protected: + // + // /** Basic Connection Variables. **/ + // Timer TIMER; + // Error_t ERROR_HANDLE; + // Socket_t SOCKET; + // + // + // /** + // Virtual Event Function to be Overridden allowing Custom Read Events. + // Each event fired on Header Complete, and each time data is read to fill packet. + // Useful to check Header length to maximum size of packet type for DDOS protection, + // sending a keep-alive ping while downloading large files, etc. + // + // LENGTH == 0: General Events + // LENGTH > 0 && PACKET: Read nSize Bytes into Data Packet + // **/ + // virtual void Event(unsigned char EVENT, unsigned int LENGTH = 0){ } + // + // /** Virtual Process Function. To be overridden with your own custom packet processing. **/ + // virtual bool ProcessPacket() { return true; } + //public: + // + // + // /** Incoming Packet Being Built. **/ + // Packet INCOMING; + // + // + // /** DDOS Score if a Incoming Server Connection. **/ + // DDOS_Filter* DDOS; + // + // + // /** Connected Flag. **/ + // bool CONNECTED; + // + // + // /** Flag to Determine if DDOS is Enabled. **/ + // bool fDDOS; + // + // + // /** Connection Constructors **/ + // Connection() : SOCKET(), DDOS(NULL), INCOMING(), CONNECTED(false), fDDOS(false) { INCOMING.SetNull(); } + // Connection( Socket_t SOCKET_IN, DDOS_Filter* DDOS_IN, bool isDDOS ) : SOCKET(SOCKET_IN), fDDOS(isDDOS), DDOS(DDOS_IN), INCOMING(), CONNECTED(false) { TIMER.Start(); } + // + // + // /** Checks for any flags in the Error Handle. **/ + // bool Errors(){ return (ERROR_HANDLE == boost::asio::error::eof || ERROR_HANDLE); } + // + // + // /** Determines if nTime seconds have elapsed since last Read / Write. **/ + // bool Timeout(unsigned int nTime){ return (TIMER.Elapsed() >= nTime); } + // + // + // /** Determines if Connected or Not. **/ + // bool Connected(){ return CONNECTED; } + // + // + // /** Handles two types of packets, requests which are of header >= 128, and data which are of header < 128. **/ + // bool PacketComplete(){ return INCOMING.Complete(); } + // + // + // /** Used to reset the packet to Null after it has been processed. This then flags the Connection to read another packet. **/ + // void ResetPacket(){ INCOMING.SetNull(); } + // + // + // /** Write a single packet to the TCP stream. **/ + // void WritePacket(Packet PACKET) { Write(PACKET.GetBytes()); } + // + // + // /** Non-Blocking Packet reader to build a packet from TCP Connection. + // This keeps thread from spending too much time for each Connection. **/ + // void ReadPacket() + // { + // + // /** Handle Reading Packet Type Header. **/ + // if(SOCKET->available() > 0 && INCOMING.IsNull()) + // { + // std::vector HEADER(1, 255); + // if(Read(HEADER, 1) == 1) + // INCOMING.HEADER = HEADER[0]; + // + // } + // + // if(!INCOMING.IsNull() && !INCOMING.Complete()) + // { + // /** Handle Reading Packet Length Header. **/ + // if(SOCKET->available() >= 4 && INCOMING.LENGTH == 0) + // { + // std::vector BYTES(4, 0); + // if(Read(BYTES, 4) == 4) + // { + // INCOMING.SetLength(BYTES); + // Event(EVENT_HEADER); + // } + // } + // + // /** Handle Reading Packet Data. **/ + // unsigned int nAvailable = SOCKET->available(); + // if(nAvailable > 0 && INCOMING.LENGTH > 0 && INCOMING.DATA.size() < INCOMING.LENGTH) + // { + // std::vector DATA( std::min(nAvailable, (unsigned int)(INCOMING.LENGTH - INCOMING.DATA.size())), 0); + // unsigned int nRead = Read(DATA, DATA.size()); + // + // if(nRead == DATA.size()) + // { + // INCOMING.DATA.insert(INCOMING.DATA.end(), DATA.begin(), DATA.end()); + // Event(EVENT_PACKET, nRead); + // } + // } + // } + // } + // + // + // /** Disconnect Socket. Cleans up memory usage to prevent "memory runs" from poor memory management. **/ + // void Disconnect() + // { + // if(!CONNECTED) + // return; + // + // try + // { + // SOCKET -> shutdown(boost::asio::ip::tcp::socket::shutdown_both, ERROR_HANDLE); + // SOCKET -> close(); + // } + // catch(...){} + // + // CONNECTED = false; + // } - std::string GetIPAddress() - { - boost::system::error_code ec; - return SOCKET->remote_endpoint(ec).address().to_string(); - } - - - private: - - /** Lower level network communications: Read. Interacts with OS sockets. **/ - size_t Read(std::vector &DATA, size_t nBytes) { if(Errors()) return 0; TIMER.Reset(); return boost::asio::read(*SOCKET, boost::asio::buffer(DATA, nBytes), ERROR_HANDLE); } - - - - /** Lower level network communications: Write. Interacts with OS sockets. **/ - void Write(std::vector DATA) { if(Errors()) return; TIMER.Reset(); boost::asio::write(*SOCKET, boost::asio::buffer(DATA, DATA.size()), ERROR_HANDLE); } + // std::string GetIPAddress() + // { + // boost::system::error_code ec; + // return SOCKET->remote_endpoint(ec).address().to_string(); + // } + // + // + //private: + // + // /** Lower level network communications: Read. Interacts with OS sockets. **/ + // size_t Read(std::vector &DATA, size_t nBytes) { if(Errors()) return 0; TIMER.Reset(); return boost::asio::read(*SOCKET, boost::asio::buffer(DATA, nBytes), ERROR_HANDLE); } + // + // + // + // /** Lower level network communications: Write. Interacts with OS sockets. **/ + // void Write(std::vector DATA) { if(Errors()) return; TIMER.Reset(); boost::asio::write(*SOCKET, boost::asio::buffer(DATA, DATA.size()), ERROR_HANDLE); } - }; + //}; diff --git a/src/LLP/webui.h b/src/LLP/webui.h index 06166f0..620543f 100644 --- a/src/LLP/webui.h +++ b/src/LLP/webui.h @@ -2,6 +2,7 @@ #define COINSHIELD_WEBUI_H #include "types.h" +#include "connection.h" namespace LLP { @@ -41,7 +42,7 @@ namespace LLP public: UiConnection() : Connection() {} - UiConnection( Socket_t SOCKET_IN, DDOS_Filter* DDOS_IN, bool isDDOS) : Connection( SOCKET_IN, DDOS_IN, isDDOS ) {} +// UiConnection( Socket_t SOCKET_IN, DDOS_Filter* DDOS_IN, bool isDDOS) : Connection( SOCKET_IN, DDOS_IN, isDDOS ) {} /** Event Function to Customize Code For Inheriting Class Happening on the LLP Data Threads. **/ void Event(unsigned char EVENT, unsigned int LENGTH = 0); diff --git a/src/base58.h b/src/base58.h index 7576837..75b5437 100644 --- a/src/base58.h +++ b/src/base58.h @@ -11,107 +11,232 @@ #include #include -#include "bignum.h" + +#include "hash/templates.h" namespace Core { static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - // Encode a byte sequence as a base58-encoded string - inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) - { - CAutoBN_CTX pctx; - CBigNum bn58 = 58; - CBigNum bn0 = 0; - - // Convert big endian data to little endian - // Extra zero at the end make sure bignum will interpret as a positive number - std::vector vchTmp(pend-pbegin+1, 0); - reverse_copy(pbegin, pend, vchTmp.begin()); + static const int8_t mapBase58[256] = { + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, + -1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1, + 22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1, + -1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46, + 47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, + }; - // Convert little endian data to bignum - CBigNum bn; - bn.setvch(vchTmp); + /** + * Tests if the given character is a whitespace character. The whitespace characters + * are: space, form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal + * tab ('\t'), and vertical tab ('\v'). + * + * This function is locale independent. Under the C locale this function gives the + * same result as std::isspace. + * + * @param[in] c character to test + * @return true if the argument is a whitespace character; otherwise false + */ + constexpr inline bool IsSpace(char c) noexcept + { + return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'; + } - // Convert bignum to std::string - std::string str; - // Expected size increase from base58 conversion is approximately 137% - // use 138% to be safe - str.reserve((pend - pbegin) * 138 / 100 + 1); - CBigNum dv; - CBigNum rem; - while (bn > bn0) - { - if (!BN_div(&dv, &rem, &bn, &bn58, pctx)) - throw bignum_error("EncodeBase58 : BN_div failed"); - bn = dv; - unsigned int c = rem.getulong(); - str += pszBase58[c]; + inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) + { + // Skip & count leading zeroes. + int zeroes = 0; + int length = 0; + while (pbegin != pend && *pbegin == 0) { + pbegin++; + zeroes++; } + // Allocate enough space in big-endian base58 representation. + int size = (pend - pbegin) * 138 / 100 + 1; // log(256) / log(58), rounded up. + std::vector b58(size); + // Process the bytes. + while (pbegin != pend) { + int carry = *pbegin; + int i = 0; + // Apply "b58 = b58 * 256 + ch". + for (std::vector::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) { + carry += 256 * (*it); + *it = carry % 58; + carry /= 58; + } - // Leading zeroes encoded as base58 zeros - for (const unsigned char* p = pbegin; p < pend && *p == 0; p++) - str += pszBase58[0]; - - // Convert little endian std::string to big endian - reverse(str.begin(), str.end()); + assert(carry == 0); + length = i; + pbegin++; + } + // Skip leading zeroes in base58 result. + std::vector::iterator it = b58.begin() + (size - length); + while (it != b58.end() && *it == 0) + it++; + // Translate the result into a string. + std::string str; + str.reserve(zeroes + (b58.end() - it)); + str.assign(zeroes, '1'); + while (it != b58.end()) + str += pszBase58[*(it++)]; return str; } + //// Encode a byte sequence as a base58-encoded string + //inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) + //{ + // CAutoBN_CTX pctx; + // CBigNum bn58 = 58; + // CBigNum bn0 = 0; + + // // Convert big endian data to little endian + // // Extra zero at the end make sure bignum will interpret as a positive number + // std::vector vchTmp(pend-pbegin+1, 0); + // reverse_copy(pbegin, pend, vchTmp.begin()); + + // // Convert little endian data to bignum + // CBigNum bn; + // bn.setvch(vchTmp); + + // // Convert bignum to std::string + // std::string str; + // // Expected size increase from base58 conversion is approximately 137% + // // use 138% to be safe + // str.reserve((pend - pbegin) * 138 / 100 + 1); + // CBigNum dv; + // CBigNum rem; + // while (bn > bn0) + // { + // if (!BN_div(&dv, &rem, &bn, &bn58, pctx)) + // throw bignum_error("EncodeBase58 : BN_div failed"); + // bn = dv; + // unsigned int c = rem.getulong(); + // str += pszBase58[c]; + // } + + // // Leading zeroes encoded as base58 zeros + // for (const unsigned char* p = pbegin; p < pend && *p == 0; p++) + // str += pszBase58[0]; + + // // Convert little endian std::string to big endian + // reverse(str.begin(), str.end()); + // return str; + //} + // Encode a byte vector as a base58-encoded string inline std::string EncodeBase58(const std::vector& vch) { return EncodeBase58(&vch[0], &vch[0] + vch.size()); } - // Decode a base58-encoded string psz into byte vector vchRet - // returns true if decoding is succesful - inline bool DecodeBase58(const char* psz, std::vector& vchRet) + inline bool DecodeBase58(const char* psz, std::vector& vch) { - CAutoBN_CTX pctx; - vchRet.clear(); - CBigNum bn58 = 58; - CBigNum bn = 0; - CBigNum bnChar; - while (isspace(*psz)) + // Skip leading spaces. + while (*psz && IsSpace(*psz)) psz++; - - // Convert big endian string to bignum - for (const char* p = psz; *p; p++) - { - const char* p1 = strchr(pszBase58, *p); - if (p1 == NULL) - { - while (isspace(*p)) - p++; - if (*p != '\0') - return false; - break; + // Skip and count leading '1's. + int zeroes = 0; + int length = 0; + while (*psz == '1') { + zeroes++; + psz++; + } + // Allocate enough space in big-endian base256 representation. + int size = strlen(psz) * 733 / 1000 + 1; // log(58) / log(256), rounded up. + std::vector b256(size); + // Process the characters. + static_assert(sizeof(mapBase58) / sizeof(mapBase58[0]) == 256, "mapBase58.size() should be 256"); // guarantee not out of range + while (*psz && !IsSpace(*psz)) { + // Decode base58 character + int carry = mapBase58[(uint8_t)*psz]; + if (carry == -1) // Invalid b58 character + return false; + int i = 0; + for (std::vector::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) { + carry += 58 * (*it); + *it = carry % 256; + carry /= 256; } - bnChar.setulong(p1 - pszBase58); - if (!BN_mul(&bn, &bn, &bn58, pctx)) - throw bignum_error("DecodeBase58 : BN_mul failed"); - bn += bnChar; + assert(carry == 0); + length = i; + psz++; } - - // Get bignum as little endian data - std::vector vchTmp = bn.getvch(); - - // Trim off sign byte if present - if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80) - vchTmp.erase(vchTmp.end()-1); - - // Restore leading zeros - int nLeadingZeros = 0; - for (const char* p = psz; *p == pszBase58[0]; p++) - nLeadingZeros++; - vchRet.assign(nLeadingZeros + vchTmp.size(), 0); - - // Convert little endian data to big endian - reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size()); + // Skip trailing spaces. + while (IsSpace(*psz)) + psz++; + if (*psz != 0) + return false; + // Skip leading zeroes in b256. + std::vector::iterator it = b256.begin() + (size - length); + while (it != b256.end() && *it == 0) + it++; + // Copy result into output vector. + vch.reserve(zeroes + (b256.end() - it)); + vch.assign(zeroes, 0x00); + while (it != b256.end()) + vch.push_back(*(it++)); return true; } + //// Decode a base58-encoded string psz into byte vector vchRet + //// returns true if decoding is succesful + //inline bool DecodeBase58(const char* psz, std::vector& vchRet) + //{ + // CAutoBN_CTX pctx; + // vchRet.clear(); + // CBigNum bn58 = 58; + // CBigNum bn = 0; + // CBigNum bnChar; + // while (isspace(*psz)) + // psz++; + + // // Convert big endian string to bignum + // for (const char* p = psz; *p; p++) + // { + // const char* p1 = strchr(pszBase58, *p); + // if (p1 == NULL) + // { + // while (isspace(*p)) + // p++; + // if (*p != '\0') + // return false; + // break; + // } + // bnChar.setulong(p1 - pszBase58); + // if (!BN_mul(&bn, &bn, &bn58, pctx)) + // throw bignum_error("DecodeBase58 : BN_mul failed"); + // bn += bnChar; + // } + + // // Get bignum as little endian data + // std::vector vchTmp = bn.getvch(); + + // // Trim off sign byte if present + // if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80) + // vchTmp.erase(vchTmp.end()-1); + + // // Restore leading zeros + // int nLeadingZeros = 0; + // for (const char* p = psz; *p == pszBase58[0]; p++) + // nLeadingZeros++; + // vchRet.assign(nLeadingZeros + vchTmp.size(), 0); + + // // Convert little endian data to big endian + // reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size()); + // return true; + //} + // Decode a base58-encoded string str into byte vector vchRet // returns true if decoding is succesful inline bool DecodeBase58(const std::string& str, std::vector& vchRet) @@ -120,8 +245,6 @@ namespace Core } - - // Encode a byte vector to a base58-encoded string, including checksum inline std::string EncodeBase58Check(const std::vector& vchIn) { diff --git a/src/bignum.h b/src/bignum.h deleted file mode 100644 index e61679d..0000000 --- a/src/bignum.h +++ /dev/null @@ -1,674 +0,0 @@ -/******************************************************************************************* - - Hash(BEGIN(Satoshi[2010]), END(Sunny[2012])) == Videlicet[2014] ++ - - [Learn, Create, but do not Forge] Viz. http://www.opensource.org/licenses/mit-license.php - -*******************************************************************************************/ - -#ifndef COINSHIELD_BIGNUM_H -#define COINSHIELD_BIGNUM_H - -#include -#include -#include -#include -#include - -#include "hash/templates.h" // for uint64 - -/** Errors thrown by the bignum class */ -class bignum_error : public std::runtime_error -{ -public: - explicit bignum_error(const std::string& str) : std::runtime_error(str) {} -}; - - -/** RAII encapsulated BN_CTX (OpenSSL bignum context) */ -class CAutoBN_CTX -{ -protected: - BN_CTX* pctx; - BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } - -public: - CAutoBN_CTX() - { - pctx = BN_CTX_new(); - if (pctx == NULL) - throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); - } - - ~CAutoBN_CTX() - { - if (pctx != NULL) - BN_CTX_free(pctx); - } - - operator BN_CTX*() { return pctx; } - BN_CTX& operator*() { return *pctx; } - BN_CTX** operator&() { return &pctx; } - bool operator!() { return (pctx == NULL); } -}; - - -/** C++ wrapper for BIGNUM (OpenSSL bignum) */ -class CBigNum : public BIGNUM -{ -public: - CBigNum() - { - BN_init(this); - } - - CBigNum(const CBigNum& b) - { - BN_init(this); - if (!BN_copy(this, &b)) - { - BN_clear_free(this); - throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); - } - } - - CBigNum& operator=(const CBigNum& b) - { - if (!BN_copy(this, &b)) - throw bignum_error("CBigNum::operator= : BN_copy failed"); - return (*this); - } - - ~CBigNum() - { - BN_clear_free(this); - } - - //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. - CBigNum(signed char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(short n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(long n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(int64 n) { BN_init(this); setint64(n); } - CBigNum(unsigned char n) { BN_init(this); setulong(n); } - CBigNum(unsigned short n) { BN_init(this); setulong(n); } - CBigNum(unsigned int n) { BN_init(this); setulong(n); } - CBigNum(unsigned long n) { BN_init(this); setulong(n); } - CBigNum(uint64 n) { BN_init(this); setuint64(n); } - explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); } - explicit CBigNum(uint512 n) { BN_init(this); setuint512(n); } - explicit CBigNum(uint576 n) { BN_init(this); setuint576(n); } - explicit CBigNum(uint1024 n) { BN_init(this); setuint1024(n); } - - explicit CBigNum(const std::vector& vch) - { - BN_init(this); - setvch(vch); - } - - void setulong(unsigned long n) - { - if (!BN_set_word(this, n)) - throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); - } - - unsigned long getulong() const - { - return BN_get_word(this); - } - - unsigned int getuint() const - { - return BN_get_word(this); - } - - int getint() const - { - unsigned long n = BN_get_word(this); - if (!BN_is_negative(this)) - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); - else - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); - } - - void setint64(int64 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fNegative = false; - if (n < (int64)0) - { - n = -n; - fNegative = true; - } - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = (fNegative ? 0x80 : 0); - else if (fNegative) - c |= 0x80; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - void setuint64(uint64 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - uint64 getuint64() - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(this, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint64 n = 0; - for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((unsigned char*)&n)[i] = vch[j]; - return n; - } - - void setuint256(uint256 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - unsigned char* pbegin = (unsigned char*)&n; - unsigned char* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - unsigned char c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize >> 0) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - uint256 getuint256() - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(this, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint256 n = 0; - for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((unsigned char*)&n)[i] = vch[j]; - return n; - } - - void setuint512(uint512 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - unsigned char* pbegin = (unsigned char*)&n; - unsigned char* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - unsigned char c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize >> 0) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - uint512 getuint512() - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(this, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint512 n = 0; - for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((unsigned char*)&n)[i] = vch[j]; - return n; - } - - void setuint576(uint576 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - unsigned char* pbegin = (unsigned char*)&n; - unsigned char* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - unsigned char c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize >> 0) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - uint576 getuint576() - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(this, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint576 n = 0; - for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((unsigned char*)&n)[i] = vch[j]; - return n; - } - - void setuint1024(uint1024 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - unsigned char* pbegin = (unsigned char*)&n; - unsigned char* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - unsigned char c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize >> 0) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } - - uint1024 getuint1024() - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(this, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint1024 n = 0; - for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((unsigned char*)&n)[i] = vch[j]; - return n; - } - - void setvch(const std::vector& vch) - { - std::vector vch2(vch.size() + 4); - unsigned int nSize = vch.size(); - // BIGNUM's byte stream format expects 4 bytes of - // big endian size data info at the front - vch2[0] = (nSize >> 24) & 0xff; - vch2[1] = (nSize >> 16) & 0xff; - vch2[2] = (nSize >> 8) & 0xff; - vch2[3] = (nSize >> 0) & 0xff; - // swap data to big endian - reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); - BN_mpi2bn(&vch2[0], vch2.size(), this); - } - - std::vector getvch() const - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize <= 4) - return std::vector(); - std::vector vch(nSize); - BN_bn2mpi(this, &vch[0]); - vch.erase(vch.begin(), vch.begin() + 4); - reverse(vch.begin(), vch.end()); - return vch; - } - - CBigNum& SetCompact(unsigned int nCompact) - { - unsigned int nSize = nCompact >> 24; - std::vector vch(4 + nSize); - vch[3] = nSize; - if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; - if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; - if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; - BN_mpi2bn(&vch[0], vch.size(), this); - return *this; - } - - unsigned int GetCompact() const - { - unsigned int nSize = BN_bn2mpi(this, NULL); - std::vector vch(nSize); - nSize -= 4; - BN_bn2mpi(this, &vch[0]); - unsigned int nCompact = nSize << 24; - if (nSize >= 1) nCompact |= (vch[4] << 16); - if (nSize >= 2) nCompact |= (vch[5] << 8); - if (nSize >= 3) nCompact |= (vch[6] << 0); - return nCompact; - } - - void SetHex(const std::string& str) - { - // skip 0x - const char* psz = str.c_str(); - while (isspace(*psz)) - psz++; - bool fNegative = false; - if (*psz == '-') - { - fNegative = true; - psz++; - } - if (psz[0] == '0' && tolower(psz[1]) == 'x') - psz += 2; - while (isspace(*psz)) - psz++; - - // hex string to bignum - static signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; - *this = 0; - while (isxdigit(*psz)) - { - *this <<= 4; - int n = phexdigit[(unsigned char)*psz++]; - *this += n; - } - if (fNegative) - *this = 0 - *this; - } - - std::string ToString(int nBase=10) const - { - CAutoBN_CTX pctx; - CBigNum bnBase = nBase; - CBigNum bn0 = 0; - std::string str; - CBigNum bn = *this; - BN_set_negative(&bn, false); - CBigNum dv; - CBigNum rem; - if (BN_cmp(&bn, &bn0) == 0) - return "0"; - while (BN_cmp(&bn, &bn0) > 0) - { - if (!BN_div(&dv, &rem, &bn, &bnBase, pctx)) - throw bignum_error("CBigNum::ToString() : BN_div failed"); - bn = dv; - unsigned int c = rem.getulong(); - str += "0123456789abcdef"[c]; - } - if (BN_is_negative(this)) - str += "-"; - reverse(str.begin(), str.end()); - return str; - } - - std::string GetHex() const - { - return ToString(16); - } - - - bool operator!() const - { - return BN_is_zero(this); - } - - CBigNum& operator+=(const CBigNum& b) - { - if (!BN_add(this, this, &b)) - throw bignum_error("CBigNum::operator+= : BN_add failed"); - return *this; - } - - CBigNum& operator-=(const CBigNum& b) - { - *this = *this - b; - return *this; - } - - CBigNum& operator*=(const CBigNum& b) - { - CAutoBN_CTX pctx; - if (!BN_mul(this, this, &b, pctx)) - throw bignum_error("CBigNum::operator*= : BN_mul failed"); - return *this; - } - - CBigNum& operator/=(const CBigNum& b) - { - *this = *this / b; - return *this; - } - - CBigNum& operator%=(const CBigNum& b) - { - *this = *this % b; - return *this; - } - - CBigNum& operator<<=(unsigned int shift) - { - if (!BN_lshift(this, this, shift)) - throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); - return *this; - } - - CBigNum& operator>>=(unsigned int shift) - { - // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number - // if built on ubuntu 9.04 or 9.10, probably depends on version of openssl - CBigNum a = 1; - a <<= shift; - if (BN_cmp(&a, this) > 0) - { - *this = 0; - return *this; - } - - if (!BN_rshift(this, this, shift)) - throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); - return *this; - } - - - CBigNum& operator++() - { - // prefix operator - if (!BN_add(this, this, BN_value_one())) - throw bignum_error("CBigNum::operator++ : BN_add failed"); - return *this; - } - - const CBigNum operator++(int) - { - // postfix operator - const CBigNum ret = *this; - ++(*this); - return ret; - } - - CBigNum& operator--() - { - // prefix operator - CBigNum r; - if (!BN_sub(&r, this, BN_value_one())) - throw bignum_error("CBigNum::operator-- : BN_sub failed"); - *this = r; - return *this; - } - - const CBigNum operator--(int) - { - // postfix operator - const CBigNum ret = *this; - --(*this); - return ret; - } - - - friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b); -}; - - - -inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) -{ - CBigNum r; - if (!BN_add(&r, &a, &b)) - throw bignum_error("CBigNum::operator+ : BN_add failed"); - return r; -} - -inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) -{ - CBigNum r; - if (!BN_sub(&r, &a, &b)) - throw bignum_error("CBigNum::operator- : BN_sub failed"); - return r; -} - -inline const CBigNum operator-(const CBigNum& a) -{ - CBigNum r(a); - BN_set_negative(&r, !BN_is_negative(&r)); - return r; -} - -inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) -{ - CAutoBN_CTX pctx; - CBigNum r; - if (!BN_mul(&r, &a, &b, pctx)) - throw bignum_error("CBigNum::operator* : BN_mul failed"); - return r; -} - -inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) -{ - CAutoBN_CTX pctx; - CBigNum r; - if (!BN_div(&r, NULL, &a, &b, pctx)) - throw bignum_error("CBigNum::operator/ : BN_div failed"); - return r; -} - -inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) -{ - CAutoBN_CTX pctx; - CBigNum r; - if (!BN_mod(&r, &a, &b, pctx)) - throw bignum_error("CBigNum::operator% : BN_div failed"); - return r; -} - -inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) -{ - CBigNum r; - if (!BN_lshift(&r, &a, shift)) - throw bignum_error("CBigNum:operator<< : BN_lshift failed"); - return r; -} - -inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) -{ - CBigNum r = a; - r >>= shift; - return r; -} - -inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); } -inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); } -inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); } -inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); } -inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); } -inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); } - -#endif diff --git a/src/config.cpp b/src/config.cpp index 268269d..033209d 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,11 +1,11 @@ #include "config.h" -#include -#include +#include "json/json.hpp" -#include +using json = nlohmann::json; -namespace pt = boost::property_tree; +#include +#include namespace Core { @@ -18,7 +18,7 @@ namespace Core nDaemonThreads = 10; nPoolThreads = 20; - bDDOS = true; + nDDOS = true; rScore = 20; cScore = 2; nShare = 40000000; @@ -35,30 +35,30 @@ namespace Core void Config::PrintConfig() { - printf("Configuration: \n"); - printf("-------------\n"); - printf("TestNet: %i \n", fTestNet); - printf("Wallet IP: %s \n", strWalletIP.c_str()); - printf("Wallet Port: %i \n", nWalletPort); - printf("Port: %i \n", nPort); - - printf("Daemon Threads: %i \n", nDaemonThreads); - printf("Pool Threads: %i \n", nPoolThreads); - - printf("bDDOS: %i \n", bDDOS); - printf("rScore: %i \n", rScore); - printf("cScore: %i \n", cScore); - printf("Min Share Diff: %i \n", nShare); - printf("Pool Fee: %i \n", nPoolFee); - - printf("Stats DB Server IP: %s \n", strStatsDBServerIP.c_str()); - printf("Stats DB Port: %i \n", nStatsDBServerPort); - printf("Stats DB Username: %s \n", strStatsDBUsername.c_str()); - printf("Stats DB Password: %s \n", strStatsDBPassword.c_str()); - printf("Save Connection Stats Frequency: %i seconds \n", nSaveConnectionStatsFrequency); - printf("Save Connection Stats Series Frequency: %i seconds \n", nSaveConnectionStatsSeriesFrequency); - - printf("-------------\n"); + std::cout << "Configuration: " << std::endl; + std::cout << "-------------" << std::endl; + std::cout << "TestNet: " << fTestNet << std::endl; + std::cout << "Wallet IP: " << strWalletIP << std::endl; + std::cout << "Wallet Port: " << nWalletPort << std::endl; + std::cout << "Port: " << nPort << std::endl; + + std::cout << "Daemon Threads: " << nDaemonThreads << std::endl; + std::cout << "Pool Threads: " << nPoolThreads << std::endl; + + std::cout << "nDDOS: " << nDDOS << std::endl;; + std::cout << "rScore: " << rScore << std::endl; + std::cout << "cScore: " << cScore << std::endl; + std::cout << "Min Share Diff: " << nShare << std::endl; + std::cout << "Pool Fee: " << nPoolFee << std::endl; + + std::cout << "Stats DB Server IP: " << strStatsDBServerIP << std::endl; + std::cout << "Stats DB Port: " << nStatsDBServerPort << std::endl; + std::cout << "Stats DB Username: " << strStatsDBUsername << std::endl; + std::cout << "Stats DB Password: " << strStatsDBPassword << std::endl; + std::cout << "Save Connection Stats Frequency: " << nSaveConnectionStatsFrequency << " seconds" << std::endl; + std::cout << "Save Connection Stats Series Frequency: " << nSaveConnectionStatsSeriesFrequency << " seconds" << std::endl; + + std::cout << "-------------" << std::endl; } @@ -66,32 +66,30 @@ namespace Core { bool bSuccess = true; - printf("Reading config file pool.conf\n"); + std::cout << "Reading config file pool.conf" << std::endl; std::ifstream lConfigFile("pool.conf"); - pt::ptree root; - pt::read_json("pool.conf", root); - - fTestNet = root.get("testnet"); - strWalletIP = root.get("wallet_ip"); - nWalletPort = root.get("wallet_port"); - nPort = root.get("port"); - - nDaemonThreads = root.get("daemon_threads"); - nPoolThreads = root.get("pool_threads"); - bDDOS = root.get("enable_ddos"); - rScore = root.get("ddos_rscore"); - cScore = root.get("ddos_cscore"); - nShare = root.get("min_share"); - nPoolFee = root.get("pool_fee"); - - strStatsDBServerIP = root.get("stats_db_server_ip"); - nStatsDBServerPort = root.get("stats_db_server_port"); - strStatsDBUsername = root.get("stats_db_username"); - strStatsDBPassword = root.get("stats_db_password"); - nSaveConnectionStatsFrequency = root.get("connection_stats_frequency"); - nSaveConnectionStatsSeriesFrequency = root.get("connection_stats_series_frequency"); + json j = json::parse(lConfigFile); + j.at("testnet").get_to(fTestNet); + j.at("wallet_ip").get_to(strWalletIP); + j.at("wallet_port").get_to(nWalletPort); + j.at("port").get_to(nPort); + + j.at("daemon_threads").get_to(nDaemonThreads); + j.at("pool_threads").get_to(nPoolThreads); + j.at("enable_ddos").get_to(nDDOS); + j.at("ddos_rscore").get_to(rScore); + j.at("ddos_cscore").get_to(cScore); + j.at("min_share").get_to(nShare); + j.at("pool_fee").get_to(nPoolFee); + + j.at("stats_db_server_ip").get_to(strStatsDBServerIP); + j.at("stats_db_server_port").get_to(nStatsDBServerPort); + j.at("stats_db_username").get_to(strStatsDBUsername); + j.at("stats_db_password").get_to(strStatsDBPassword); + j.at("connection_stats_frequency").get_to(nSaveConnectionStatsFrequency); + j.at("connection_stats_series_frequency").get_to(nSaveConnectionStatsSeriesFrequency); PrintConfig(); // TODO Need to add exception handling here and set bSuccess appropriately diff --git a/src/core.cpp b/src/core.cpp index b3a94cf..fd421b1 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1,7 +1,7 @@ #include "LLP/pool.h" #include "LLP/server.h" #include "LLP/daemon.h" -#include "LLP/webui.h" +//#include "LLP/webui.h" #include "LLD/record.h" #include "core.h" @@ -24,7 +24,7 @@ namespace Core /** Coinbase Transaction for this Block. **/ Coinbase cGlobalCoinbase; - std::string POOL_VERSION = "1.0.1"; + std::string POOL_VERSION = "1.0.2"; /** Wallet Connection Variables. **/ @@ -33,13 +33,13 @@ namespace Core std::vector DAEMON_CONNECTIONS; LLP::Server* SERVER; - LLP::Server* WEBSERVER; + //LLP::Server* WEBSERVER; LLP::Thread_t MASTER; /** Mutex for Thread Synchronization [std::map is not thread safe]. **/ - boost::mutex PRIMES_MUTEX; + std::mutex PRIMES_MUTEX; /** Map to hold the Prime Clusters Found. **/ diff --git a/src/core.h b/src/core.h index e9b2c5e..adda2bc 100644 --- a/src/core.h +++ b/src/core.h @@ -1,7 +1,8 @@ #ifndef COINSHIELD_LLP_CORE_H #define COINSHIELD_LLP_CORE_H -#include "bignum.h" +#include "hash/uint1024.h" +#include "hash/templates.h" #include "util.h" #ifdef WIN32 #include @@ -10,6 +11,9 @@ #endif #include "config.h" +#include +#include +#include class Coinbase; @@ -58,7 +62,7 @@ namespace Core } inline uint1024 GetHash() const { return SK1024(BEGIN(nVersion), END(nBits)); } - inline CBigNum GetPrime() const { return CBigNum(GetHash() + nNonce); } + inline uint1024 GetPrime() const { return GetHash() + nNonce; } }; /** Pool Configuration **/ @@ -104,25 +108,17 @@ namespace Core /** --------- PRIME.CPP ----------- **/ void InitializePrimes(); + uint1024 FermatTest(uint1024 n); unsigned int SetBits(double nDiff); - unsigned int GetPrimeBits(CBigNum prime, int checks); - unsigned int GetFractionalDifficulty(CBigNum composite); + unsigned int GetFractionalDifficulty(uint1024 composite); double GetDifficulty(unsigned int nBits); - double VerifyPrimeDifficulty(CBigNum prime, int checks); - double CheckPrimeDifficulty(CBigNum prime); - double GmpVerification(CBigNum prime); - - CBigNum FermatTest(CBigNum n, CBigNum a); - bool Miller_Rabin(CBigNum n, int checks); - bool PrimeCheck(CBigNum test, int checks); - - + double GmpVerification(uint1024 prime); /** --------- CORE.CPP ----------- **/ extern std::map PRIMES_MAP; - extern boost::mutex PRIMES_MUTEX; + extern std::mutex PRIMES_MUTEX; extern LLP::Timer nMeterTimer; extern unsigned int nShares; diff --git a/src/hash/uint1024.h b/src/hash/uint1024.h index 263c67e..88421ce 100644 --- a/src/hash/uint1024.h +++ b/src/hash/uint1024.h @@ -1,22 +1,29 @@ /******************************************************************************************* - - Hash(BEGIN(Satoshi[2010]), END(Sunny[2012])) == Videlicet[2014] ++ - - [Learn, Create, but do not Forge] Viz. http://www.opensource.org/licenses/mit-license.php - + + Hash(BEGIN(Satoshi[2010]), END(Sunny[2012])) == Videlicet[2014] ++ + + [Learn and Create] Viz. http://www.opensource.org/licenses/mit-license.php + *******************************************************************************************/ -#ifndef COINSHIELD_UINT1024_H -#define COINSHIELD_UINT1024_H +#ifndef NEXUS_UINT1024_H +#define NEXUS_UINT1024_H #include #include #include #include #include +#include +/** Linux Specific Work Around (For Now). **/ +#if defined(MAC_OSX) || defined(_WIN32) +typedef int64_t int64; +typedef uint64_t uint64; +#else typedef long long int64; typedef unsigned long long uint64; +#endif /** Base class without constructors for uint256, uint512, uint576, uint1024. @@ -282,6 +289,16 @@ class base_uint return (!(a == b)); } + void *data() + { + return reinterpret_cast(&pn); + } + + unsigned int width() + { + return WIDTH; + } + std::string GetHex() const @@ -303,7 +320,7 @@ class base_uint if (psz[0] == '0' && tolower(psz[1]) == 'x') psz += 2; - + static unsigned char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; const char* pbegin = psz; while (phexdigit[(unsigned char)*psz] || *psz == '0') @@ -326,37 +343,37 @@ class base_uint { SetHex(str.c_str()); } - - /** Converts the corresponding unsigned integer into bytes. - Used for serializing in Miner LLP **/ - const std::vector GetBytes() - { - std::vector DATA; - - for(int index = 0; index < WIDTH; index++) - { - std::vector BYTES(4, 0); - BYTES[0] = (pn[index] >> 24); - BYTES[1] = (pn[index] >> 16); - BYTES[2] = (pn[index] >> 8); - BYTES[3] = pn[index]; - - DATA.insert(DATA.end(), BYTES.begin(), BYTES.end()); - } - - return DATA; - } - - /** Creates an unsigned integer from bytes. - Used for de-serializing in Miner LLP **/ - void SetBytes(const std::vector DATA) - { - for(int index = 0; index < WIDTH; index++) - { - std::vector BYTES(DATA.begin() + (index * 4), DATA.begin() + (index * 4) + 4); - pn[index] = (BYTES[0] << 24) + (BYTES[1] << 16) + (BYTES[2] << 8) + (BYTES[3] ); - } - } + + /** Converts the corresponding unsigned integer into bytes. + Used for serializing in Miner LLP **/ + const std::vector GetBytes() + { + std::vector DATA; + + for(int index = 0; index < WIDTH; index++) + { + std::vector BYTES(4, 0); + BYTES[0] = (pn[index] >> 24); + BYTES[1] = (pn[index] >> 16); + BYTES[2] = (pn[index] >> 8); + BYTES[3] = pn[index]; + + DATA.insert(DATA.end(), BYTES.begin(), BYTES.end()); + } + + return DATA; + } + + /** Creates an unsigned integer from bytes. + Used for de-serializing in Miner LLP **/ + void SetBytes(const std::vector DATA) + { + for(int index = 0; index < WIDTH; index++) + { + std::vector BYTES(DATA.begin() + (index * 4), DATA.begin() + (index * 4) + 4); + pn[index] = (BYTES[0] << 24) + (BYTES[1] << 16) + (BYTES[2] << 8) + (BYTES[3] ); + } + } std::string ToString() const { @@ -405,9 +422,9 @@ class base_uint friend class uint256; - friend class uint512; - friend class uint576; - friend class uint1024; + friend class uint512; + friend class uint576; + friend class uint1024; }; typedef base_uint<256> base_uint256; @@ -563,18 +580,18 @@ class uint512 : public base_uint512 pn[i] = 0; return *this; } - - explicit uint512(const std::vector vch) - { - SetBytes(vch); - } + + explicit uint512(const std::vector vch) + { + SetBytes(vch); + } explicit uint512(const std::string& str) { SetHex(str); } - /* + /* explicit uint512(const std::vector& vch) { if (vch.size() == sizeof(pn)) @@ -582,7 +599,7 @@ class uint512 : public base_uint512 else *this = 0; } - */ + */ }; inline bool operator==(const uint512& a, uint64 b) { return (base_uint512)a == b; } @@ -782,69 +799,74 @@ class uint1024 : public base_uint1024 pn[i] = 0; return *this; } - - uint1024(uint256 b) + + uint1024(uint256 b) { for (int i = 0; i < WIDTH; i++) - if(i < b.WIDTH) - pn[i] = b.pn[i]; - else - pn[i] = 0; + if(i < b.WIDTH) + pn[i] = b.pn[i]; + else + pn[i] = 0; } - - uint1024& operator=(uint256 b) + + uint1024& operator=(uint256 b) { for (int i = 0; i < WIDTH; i++) - if(i < b.WIDTH) - pn[i] = b.pn[i]; - else - pn[i] = 0; - - return *this; + if(i < b.WIDTH) + pn[i] = b.pn[i]; + else + pn[i] = 0; + + return *this; } - - uint1024(uint512 b) + + uint1024(uint512 b) { for (int i = 0; i < WIDTH; i++) - if(i < b.WIDTH) - pn[i] = b.pn[i]; - else - pn[i] = 0; + if(i < b.WIDTH) + pn[i] = b.pn[i]; + else + pn[i] = 0; } - - uint1024& operator=(uint512 b) + + uint1024& operator=(uint512 b) { for (int i = 0; i < WIDTH; i++) - if(i < b.WIDTH) - pn[i] = b.pn[i]; - else - pn[i] = 0; - - return *this; - } - - /** This method should only be used to retrieve an uint256 when stored inside an uint1024. - This is necessary for for ambiguous function declaration. */ - uint256 getuint256() const - { - uint256 b; - for (int i = 0; i < b.WIDTH; i++) - b.pn[i] = pn[i]; - - return b; - } - - /** This method should only be used to retrieve an uint512 when stored inside an uint1024. - This is necessary for the inventory system to function with both a 1024 bit block - and 512 bit transaction. */ - uint512 getuint512() const - { - uint512 b; - for (int i = 0; i < b.WIDTH; i++) - b.pn[i] = pn[i]; - - return b; - } + if(i < b.WIDTH) + pn[i] = b.pn[i]; + else + pn[i] = 0; + + return *this; + } + + unsigned int high_bits(unsigned int mask) + { + return pn[WIDTH-1] & mask; + } + + /** This method should only be used to retrieve an uint256 when stored inside an uint1024. + This is necessary for for ambiguous function declaration. */ + uint256 getuint256() const + { + uint256 b; + for (int i = 0; i < b.WIDTH; i++) + b.pn[i] = pn[i]; + + return b; + } + + /** This method should only be used to retrieve an uint512 when stored inside an uint1024. + This is necessary for the inventory system to function with both a 1024 bit block + and 512 bit transaction. */ + uint512 getuint512() const + { + uint512 b; + for (int i = 0; i < b.WIDTH; i++) + b.pn[i] = pn[i]; + + return b; + } explicit uint1024(const std::string& str) { diff --git a/src/json/LICENSE.txt b/src/json/LICENSE.txt index 797d536..d0bb630 100644 --- a/src/json/LICENSE.txt +++ b/src/json/LICENSE.txt @@ -1,24 +1,21 @@ -The MIT License +MIT License -Copyright (c) 2007 - 2009 John W. Wilkinson +Copyright (c) 2013-2018 Niels Lohmann -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/json/json.hpp b/src/json/json.hpp new file mode 100644 index 0000000..1e7cf51 --- /dev/null +++ b/src/json/json.hpp @@ -0,0 +1,20274 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.4.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2018 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 4 +#define NLOHMANN_JSON_VERSION_PATCH 0 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} // namespace nlohmann + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + +// #include + +// #include + + +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template