Madbuda
7 years ago
commit
cd47f66c1e
22 changed files with 6212 additions and 0 deletions
@ -0,0 +1,6 @@ |
|||||
|
*.o |
||||
|
dnsseed* |
||||
|
dnsstats.log |
||||
|
.idea/ |
||||
|
cmake-build-debug/ |
||||
|
dnsseed |
@ -0,0 +1,20 @@ |
|||||
|
CXXFLAGS = -O3 -g0 -march=native |
||||
|
LDFLAGS = $(CXXFLAGS) |
||||
|
|
||||
|
COMMIT_HASH=`git rev-parse --short HEAD 2>/dev/null` |
||||
|
BUILD_DATE=`date +%FT%T%z` |
||||
|
|
||||
|
dnsseed: dns.o bitcoin.o netbase.o protocol.o db.o main.o util.o |
||||
|
g++ -pthread $(LDFLAGS) -o dnsseed dns.o bitcoin.o netbase.o protocol.o db.o main.o util.o -lcrypto |
||||
|
|
||||
|
%.o: %.cpp bitcoin.h netbase.h protocol.h db.h serialize.h uint256.h util.h |
||||
|
g++ -pthread $(CXXFLAGS) -Wno-invalid-offsetof -c -o $@ $< |
||||
|
|
||||
|
dns.o: dns.c |
||||
|
gcc -pthread -std=c99 $(CXXFLAGS) dns.c -c -o dns.o |
||||
|
|
||||
|
%.o: %.cpp |
||||
|
|
||||
|
help: |
||||
|
echo ${COMMIT_HASH} |
||||
|
echo ${BUILD_DATE} |
@ -0,0 +1,60 @@ |
|||||
|
hush-seeder |
||||
|
============== |
||||
|
|
||||
|
Hush-seeder is a crawler for the Hush network, which exposes a list |
||||
|
of reliable nodes via a built-in DNS server. |
||||
|
|
||||
|
Features: |
||||
|
* regularly revisits known nodes to check their availability |
||||
|
* bans nodes after enough failures, or bad behaviour |
||||
|
* keeps statistics over (exponential) windows of 2 hours, 8 hours, |
||||
|
1 day and 1 week, to base decisions on. |
||||
|
* very low memory (a few tens of megabytes) and cpu requirements. |
||||
|
* crawlers run in parallel (by default 24 threads simultaneously). |
||||
|
|
||||
|
REQUIREMENTS |
||||
|
------------ |
||||
|
|
||||
|
$ sudo apt-get install build-essential libboost-all-dev libssl-dev |
||||
|
|
||||
|
USAGE |
||||
|
----- |
||||
|
|
||||
|
Assuming you want to run a dns seed on dnsseed.example.com, you will |
||||
|
need an authorative NS record in example.com's domain record, pointing |
||||
|
to for example vps.example.com: |
||||
|
|
||||
|
$ dig -t NS dnsseed.example.com |
||||
|
|
||||
|
;; ANSWER SECTION |
||||
|
dnsseed.example.com. 86400 IN NS vps.example.com. |
||||
|
|
||||
|
On the system vps.example.com, you can now run dnsseed: |
||||
|
|
||||
|
./dnsseed -h dnsseed.example.com -n vps.example.com |
||||
|
|
||||
|
If you want the DNS server to report SOA records, please provide an |
||||
|
e-mail address (with the @ part replaced by .) using -m. |
||||
|
|
||||
|
COMPILING |
||||
|
--------- |
||||
|
Compiling will require boost and ssl. On debian systems, these are provided |
||||
|
by `libboost-dev` and `libssl-dev` respectively. |
||||
|
|
||||
|
$ make |
||||
|
|
||||
|
This will produce the `dnsseed` binary. |
||||
|
|
||||
|
|
||||
|
RUNNING AS NON-ROOT |
||||
|
------------------- |
||||
|
|
||||
|
Typically, you'll need root privileges to listen to port 53 (name service). |
||||
|
|
||||
|
One solution is using an iptables rule (Linux only) to redirect it to |
||||
|
a non-privileged port: |
||||
|
|
||||
|
$ iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-port 5353 |
||||
|
|
||||
|
If properly configured, this will allow you to run dnsseed in userspace, using |
||||
|
the -p 5353 option. |
@ -0,0 +1,309 @@ |
|||||
|
#include <algorithm> |
||||
|
|
||||
|
#include "db.h" |
||||
|
#include "netbase.h" |
||||
|
#include "protocol.h" |
||||
|
#include "serialize.h" |
||||
|
#include "uint256.h" |
||||
|
|
||||
|
#define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
class CNode { |
||||
|
SOCKET sock; |
||||
|
CDataStream vSend; |
||||
|
CDataStream vRecv; |
||||
|
unsigned int nHeaderStart; |
||||
|
unsigned int nMessageStart; |
||||
|
int nVersion; |
||||
|
string strSubVer; |
||||
|
int nStartingHeight; |
||||
|
vector<CAddress> *vAddr; |
||||
|
int ban; |
||||
|
int64 doneAfter; |
||||
|
CAddress you; |
||||
|
|
||||
|
int GetTimeout() { |
||||
|
if (you.IsTor()) |
||||
|
return 120; |
||||
|
else |
||||
|
return 30; |
||||
|
} |
||||
|
|
||||
|
void BeginMessage(const char *pszCommand) { |
||||
|
if (nHeaderStart != -1) AbortMessage(); |
||||
|
nHeaderStart = vSend.size(); |
||||
|
vSend << CMessageHeader(pszCommand, 0); |
||||
|
nMessageStart = vSend.size(); |
||||
|
// printf("%s: SEND %s\n", ToString(you).c_str(), pszCommand);
|
||||
|
} |
||||
|
|
||||
|
void AbortMessage() { |
||||
|
if (nHeaderStart == -1) return; |
||||
|
vSend.resize(nHeaderStart); |
||||
|
nHeaderStart = -1; |
||||
|
nMessageStart = -1; |
||||
|
} |
||||
|
|
||||
|
void EndMessage() { |
||||
|
if (nHeaderStart == -1) return; |
||||
|
unsigned int nSize = vSend.size() - nMessageStart; |
||||
|
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); |
||||
|
if (vSend.GetVersion() >= 209) { |
||||
|
uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); |
||||
|
unsigned int nChecksum = 0; |
||||
|
memcpy(&nChecksum, &hash, sizeof(nChecksum)); |
||||
|
assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum)); |
||||
|
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum)); |
||||
|
} |
||||
|
nHeaderStart = -1; |
||||
|
nMessageStart = -1; |
||||
|
} |
||||
|
|
||||
|
void Send() { |
||||
|
if (sock == INVALID_SOCKET) return; |
||||
|
if (vSend.empty()) return; |
||||
|
int nBytes = send(sock, &vSend[0], vSend.size(), 0); |
||||
|
if (nBytes > 0) { |
||||
|
vSend.erase(vSend.begin(), vSend.begin() + nBytes); |
||||
|
} else { |
||||
|
close(sock); |
||||
|
sock = INVALID_SOCKET; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void PushVersion() { |
||||
|
int64 nTime = time(NULL); |
||||
|
uint64 nLocalNonce = BITCOIN_SEED_NONCE; |
||||
|
int64 nLocalServices = 0; |
||||
|
CAddress me(CService("0.0.0.0")); |
||||
|
BeginMessage("version"); |
||||
|
int nBestHeight = GetRequireHeight(); |
||||
|
string ver = "/hush-seeder:0.01/"; |
||||
|
vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me << nLocalNonce << ver << nBestHeight; |
||||
|
EndMessage(); |
||||
|
} |
||||
|
|
||||
|
void GotVersion() { |
||||
|
// printf("\n%s: version %i\n", ToString(you).c_str(), nVersion);
|
||||
|
if (vAddr) { |
||||
|
BeginMessage("getaddr"); |
||||
|
EndMessage(); |
||||
|
doneAfter = time(NULL) + GetTimeout(); |
||||
|
} else { |
||||
|
doneAfter = time(NULL) + 1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool ProcessMessage(string strCommand, CDataStream& vRecv) { |
||||
|
// printf("%s: RECV %s\n", ToString(you).c_str(), strCommand.c_str());
|
||||
|
if (strCommand == "version") { |
||||
|
int64 nTime; |
||||
|
CAddress addrMe; |
||||
|
CAddress addrFrom; |
||||
|
uint64 nNonce = 1; |
||||
|
vRecv >> nVersion >> you.nServices >> nTime >> addrMe; |
||||
|
if (nVersion == 10300) nVersion = 300; |
||||
|
if (nVersion >= 106 && !vRecv.empty()) |
||||
|
vRecv >> addrFrom >> nNonce; |
||||
|
if (nVersion >= 106 && !vRecv.empty()) |
||||
|
vRecv >> strSubVer; |
||||
|
if (nVersion >= 209 && !vRecv.empty()) |
||||
|
vRecv >> nStartingHeight; |
||||
|
|
||||
|
if (nVersion >= 209) { |
||||
|
BeginMessage("verack"); |
||||
|
EndMessage(); |
||||
|
} |
||||
|
vSend.SetVersion(min(nVersion, PROTOCOL_VERSION)); |
||||
|
if (nVersion < 209) { |
||||
|
this->vRecv.SetVersion(min(nVersion, PROTOCOL_VERSION)); |
||||
|
GotVersion(); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (strCommand == "verack") { |
||||
|
this->vRecv.SetVersion(min(nVersion, PROTOCOL_VERSION)); |
||||
|
GotVersion(); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (strCommand == "addr" && vAddr) { |
||||
|
vector<CAddress> vAddrNew; |
||||
|
vRecv >> vAddrNew; |
||||
|
// printf("%s: got %i addresses\n", ToString(you).c_str(), (int)vAddrNew.size());
|
||||
|
int64 now = time(NULL); |
||||
|
vector<CAddress>::iterator it = vAddrNew.begin(); |
||||
|
if (vAddrNew.size() > 1) { |
||||
|
if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1; |
||||
|
} |
||||
|
while (it != vAddrNew.end()) { |
||||
|
CAddress &addr = *it; |
||||
|
// printf("%s: got address %s\n", ToString(you).c_str(), addr.ToString().c_str(), (int)(vAddr->size()));
|
||||
|
it++; |
||||
|
if (addr.nTime <= 100000000 || addr.nTime > now + 600) |
||||
|
addr.nTime = now - 5 * 86400; |
||||
|
if (addr.nTime > now - 604800) |
||||
|
vAddr->push_back(addr); |
||||
|
// printf("%s: added address %s (#%i)\n", ToString(you).c_str(), addr.ToString().c_str(), (int)(vAddr->size()));
|
||||
|
if (vAddr->size() > 1000) {doneAfter = 1; return true; } |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
bool ProcessMessages() { |
||||
|
if (vRecv.empty()) return false; |
||||
|
do { |
||||
|
CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart)); |
||||
|
int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader()); |
||||
|
if (vRecv.end() - pstart < nHeaderSize) { |
||||
|
if (vRecv.size() > nHeaderSize) { |
||||
|
vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize); |
||||
|
} |
||||
|
break; |
||||
|
} |
||||
|
vRecv.erase(vRecv.begin(), pstart); |
||||
|
vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize); |
||||
|
CMessageHeader hdr; |
||||
|
vRecv >> hdr; |
||||
|
if (!hdr.IsValid()) { |
||||
|
// printf("%s: BAD (invalid header)\n", ToString(you).c_str());
|
||||
|
ban = 100000; return true; |
||||
|
} |
||||
|
string strCommand = hdr.GetCommand(); |
||||
|
unsigned int nMessageSize = hdr.nMessageSize; |
||||
|
if (nMessageSize > MAX_SIZE) { |
||||
|
// printf("%s: BAD (message too large)\n", ToString(you).c_str());
|
||||
|
ban = 100000; |
||||
|
return true; |
||||
|
} |
||||
|
if (nMessageSize > vRecv.size()) { |
||||
|
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end()); |
||||
|
break; |
||||
|
} |
||||
|
if (vRecv.GetVersion() >= 209) { |
||||
|
uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); |
||||
|
unsigned int nChecksum = 0; |
||||
|
memcpy(&nChecksum, &hash, sizeof(nChecksum)); |
||||
|
if (nChecksum != hdr.nChecksum) continue; |
||||
|
} |
||||
|
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); |
||||
|
vRecv.ignore(nMessageSize); |
||||
|
if (ProcessMessage(strCommand, vMsg)) |
||||
|
return true; |
||||
|
// printf("%s: done processing %s\n", ToString(you).c_str(), strCommand.c_str());
|
||||
|
} while(1); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
CNode(const CService& ip, vector<CAddress>* vAddrIn) : you(ip), nHeaderStart(-1), nMessageStart(-1), vAddr(vAddrIn), ban(0), doneAfter(0), nVersion(0) { |
||||
|
vSend.SetType(SER_NETWORK); |
||||
|
vSend.SetVersion(0); |
||||
|
vRecv.SetType(SER_NETWORK); |
||||
|
vRecv.SetVersion(0); |
||||
|
if (time(NULL) > 1329696000) { |
||||
|
vSend.SetVersion(209); |
||||
|
vRecv.SetVersion(209); |
||||
|
} |
||||
|
} |
||||
|
bool Run() { |
||||
|
bool res = true; |
||||
|
if (!ConnectSocket(you, sock)) return false; |
||||
|
PushVersion(); |
||||
|
Send(); |
||||
|
int64 now; |
||||
|
while (now = time(NULL), ban == 0 && (doneAfter == 0 || doneAfter > now) && sock != INVALID_SOCKET) { |
||||
|
char pchBuf[0x10000]; |
||||
|
fd_set set; |
||||
|
FD_ZERO(&set); |
||||
|
FD_SET(sock,&set); |
||||
|
struct timeval wa; |
||||
|
if (doneAfter) { |
||||
|
wa.tv_sec = doneAfter - now; |
||||
|
wa.tv_usec = 0; |
||||
|
} else { |
||||
|
wa.tv_sec = GetTimeout(); |
||||
|
wa.tv_usec = 0; |
||||
|
} |
||||
|
int ret = select(sock+1, &set, NULL, &set, &wa); |
||||
|
if (ret != 1) { |
||||
|
if (!doneAfter) res = false; |
||||
|
break; |
||||
|
} |
||||
|
int nBytes = recv(sock, pchBuf, sizeof(pchBuf), 0); |
||||
|
int nPos = vRecv.size(); |
||||
|
if (nBytes > 0) { |
||||
|
vRecv.resize(nPos + nBytes); |
||||
|
memcpy(&vRecv[nPos], pchBuf, nBytes); |
||||
|
} else if (nBytes == 0) { |
||||
|
// printf("%s: BAD (connection closed prematurely)\n", ToString(you).c_str());
|
||||
|
res = false; |
||||
|
break; |
||||
|
} else { |
||||
|
// printf("%s: BAD (connection error)\n", ToString(you).c_str());
|
||||
|
res = false; |
||||
|
break; |
||||
|
} |
||||
|
ProcessMessages(); |
||||
|
Send(); |
||||
|
} |
||||
|
if (sock == INVALID_SOCKET) res = false; |
||||
|
close(sock); |
||||
|
sock = INVALID_SOCKET; |
||||
|
return (ban == 0) && res; |
||||
|
} |
||||
|
|
||||
|
int GetBan() { |
||||
|
return ban; |
||||
|
} |
||||
|
|
||||
|
int GetClientVersion() { |
||||
|
return nVersion; |
||||
|
} |
||||
|
|
||||
|
std::string GetClientSubVersion() { |
||||
|
return strSubVer; |
||||
|
} |
||||
|
|
||||
|
int GetStartingHeight() { |
||||
|
return nStartingHeight; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
bool TestNode(const CService &cip, int &ban, int &clientV, std::string &clientSV, int &blocks, vector<CAddress>* vAddr) { |
||||
|
try { |
||||
|
CNode node(cip, vAddr); |
||||
|
bool ret = node.Run(); |
||||
|
if (!ret) { |
||||
|
ban = node.GetBan(); |
||||
|
} else { |
||||
|
ban = 0; |
||||
|
} |
||||
|
clientV = node.GetClientVersion(); |
||||
|
clientSV = node.GetClientSubVersion(); |
||||
|
blocks = node.GetStartingHeight(); |
||||
|
// printf("%s: %s!!!\n", cip.ToString().c_str(), ret ? "GOOD" : "BAD");
|
||||
|
return ret; |
||||
|
} catch(std::ios_base::failure& e) { |
||||
|
ban = 0; |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
int main(void) { |
||||
|
CService ip("bitcoin.sipa.be", 8333, true); |
||||
|
vector<CAddress> vAddr; |
||||
|
vAddr.clear(); |
||||
|
int ban = 0; |
||||
|
bool ret = TestNode(ip, ban, vAddr); |
||||
|
printf("ret=%s ban=%i vAddr.size()=%i\n", ret ? "good" : "bad", ban, (int)vAddr.size()); |
||||
|
} |
||||
|
*/ |
||||
|
|
@ -0,0 +1,8 @@ |
|||||
|
#ifndef _BITCOIN_H_ |
||||
|
#define _BITCOIN_H_ 1 |
||||
|
|
||||
|
#include "protocol.h" |
||||
|
|
||||
|
bool TestNode(const CService &cip, int &ban, int &client, std::string &clientSV, int &blocks, std::vector<CAddress>* vAddr); |
||||
|
|
||||
|
#endif |
@ -0,0 +1,66 @@ |
|||||
|
#!/usr/bin/perl -w |
||||
|
|
||||
|
use strict; |
||||
|
use warnings FATAL => 'all'; |
||||
|
|
||||
|
sub loadFile { |
||||
|
my ($file) = @_; |
||||
|
my %ret; |
||||
|
my $max = 0; |
||||
|
open FILE,$file; |
||||
|
while (<FILE>) { |
||||
|
my ($addr,$p2h,$p8h,$p1d,$p1w,$p1m) = split(/\s+/,$_); |
||||
|
if ($p1m =~ /\A([1-9.]+)%\Z/) { |
||||
|
my $x = $1*0.01; |
||||
|
$max=$x if ($x > $max); |
||||
|
$ret{$addr} = $x; |
||||
|
} |
||||
|
} |
||||
|
for my $k (keys %ret) { |
||||
|
$ret{$k} /= $max; |
||||
|
} |
||||
|
close FILE; |
||||
|
return \%ret; |
||||
|
} |
||||
|
|
||||
|
sub merge { |
||||
|
my ($a,$b) = @_; |
||||
|
return 1-(1-$a)*(1-$b); |
||||
|
} |
||||
|
|
||||
|
sub combine { |
||||
|
my ($f1,$f2) = @_; |
||||
|
my %ret; |
||||
|
for my $k1 (keys %{$f1}) { |
||||
|
if (defined $f2->{$k1}) { |
||||
|
$ret{$k1} = merge($f1->{$k1}, $f2->{$k1}); |
||||
|
} else { |
||||
|
$ret{$k1} = merge($f1->{$k1}, 0); |
||||
|
} |
||||
|
} |
||||
|
for my $k2 (keys %{$f2}) { |
||||
|
if (!defined $f1->{$k2}) { |
||||
|
$ret{$k2} = merge(0, $f2->{$k2}); |
||||
|
} |
||||
|
} |
||||
|
return \%ret; |
||||
|
} |
||||
|
|
||||
|
my $res; |
||||
|
my $n=0; |
||||
|
for my $file (@ARGV) { |
||||
|
my $r = loadFile($file); |
||||
|
if ($res) { |
||||
|
$res = combine($res,$r); |
||||
|
} else { |
||||
|
$res = $r; |
||||
|
} |
||||
|
$n++; |
||||
|
} |
||||
|
|
||||
|
for my $addr (sort { $res->{$b} <=> $res->{$a} } (keys %{$res})) { |
||||
|
if ($addr =~ /\A(\d+)\.(\d+)\.(\d+)\.(\d+):8333/) { |
||||
|
my $a = $1*0x1000000 + $2*0x10000 + $3*0x100 + $4; |
||||
|
printf "0x%08x %s %g%%\n",$a,$addr,(1-((1-$res->{$addr}) ** (1/$n)))*100; |
||||
|
} |
||||
|
} |
@ -0,0 +1,66 @@ |
|||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
|
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
#ifndef _BITCOIN_COMPAT_H |
||||
|
#define _BITCOIN_COMPAT_H 1 |
||||
|
|
||||
|
#ifdef WIN32 |
||||
|
#define _WIN32_WINNT 0x0501 |
||||
|
#define WIN32_LEAN_AND_MEAN 1 |
||||
|
#ifndef NOMINMAX |
||||
|
#define NOMINMAX |
||||
|
#endif |
||||
|
#include <winsock2.h> |
||||
|
#include <mswsock.h> |
||||
|
#include <ws2tcpip.h> |
||||
|
#else |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <sys/fcntl.h> |
||||
|
#include <arpa/inet.h> |
||||
|
#include <netdb.h> |
||||
|
#include <net/if.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <ifaddrs.h> |
||||
|
#endif |
||||
|
|
||||
|
typedef u_int SOCKET; |
||||
|
#ifdef __APPLE__ |
||||
|
#define MSG_NOSIGNAL 0 |
||||
|
#endif |
||||
|
#ifdef WIN32 |
||||
|
#define MSG_NOSIGNAL 0 |
||||
|
#define MSG_DONTWAIT 0 |
||||
|
typedef int socklen_t; |
||||
|
#else |
||||
|
#include "errno.h" |
||||
|
#define WSAGetLastError() 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 |
||||
|
|
||||
|
inline int myclosesocket(SOCKET& hSocket) |
||||
|
{ |
||||
|
if (hSocket == INVALID_SOCKET) |
||||
|
return WSAENOTSOCK; |
||||
|
#ifdef WIN32 |
||||
|
int ret = closesocket(hSocket); |
||||
|
#else |
||||
|
int ret = close(hSocket); |
||||
|
#endif |
||||
|
hSocket = INVALID_SOCKET; |
||||
|
return ret; |
||||
|
} |
||||
|
#define closesocket(s) myclosesocket(s) |
||||
|
|
||||
|
|
||||
|
#endif |
@ -0,0 +1,206 @@ |
|||||
|
#include "db.h" |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
void CAddrInfo::Update(bool good) { |
||||
|
uint32_t now = time(NULL); |
||||
|
if (ourLastTry == 0) |
||||
|
ourLastTry = now - MIN_RETRY; |
||||
|
int age = now - ourLastTry; |
||||
|
lastTry = now; |
||||
|
ourLastTry = now; |
||||
|
total++; |
||||
|
if (good) |
||||
|
{ |
||||
|
success++; |
||||
|
ourLastSuccess = now; |
||||
|
} |
||||
|
stat2H.Update(good, age, 3600*2); |
||||
|
stat8H.Update(good, age, 3600*8); |
||||
|
stat1D.Update(good, age, 3600*24); |
||||
|
stat1W.Update(good, age, 3600*24*7); |
||||
|
stat1M.Update(good, age, 3600*24*30); |
||||
|
int ign = GetIgnoreTime(); |
||||
|
if (ign && (ignoreTill==0 || ignoreTill < ign+now)) ignoreTill = ign+now; |
||||
|
// printf("%s: got %s result: success=%i/%i; 2H:%.2f%%-%.2f%%(%.2f) 8H:%.2f%%-%.2f%%(%.2f) 1D:%.2f%%-%.2f%%(%.2f) 1W:%.2f%%-%.2f%%(%.2f) \n", ToString(ip).c_str(), good ? "good" : "bad", success, total,
|
||||
|
// 100.0 * stat2H.reliability, 100.0 * (stat2H.reliability + 1.0 - stat2H.weight), stat2H.count,
|
||||
|
// 100.0 * stat8H.reliability, 100.0 * (stat8H.reliability + 1.0 - stat8H.weight), stat8H.count,
|
||||
|
// 100.0 * stat1D.reliability, 100.0 * (stat1D.reliability + 1.0 - stat1D.weight), stat1D.count,
|
||||
|
// 100.0 * stat1W.reliability, 100.0 * (stat1W.reliability + 1.0 - stat1W.weight), stat1W.count);
|
||||
|
} |
||||
|
|
||||
|
bool CAddrDb::Get_(CServiceResult &ip, int &wait) { |
||||
|
int64 now = time(NULL); |
||||
|
int cont = 0; |
||||
|
int tot = unkId.size() + ourId.size(); |
||||
|
if (tot == 0) { |
||||
|
wait = 5; |
||||
|
return false; |
||||
|
} |
||||
|
do { |
||||
|
int rnd = rand() % tot; |
||||
|
int ret; |
||||
|
if (rnd < unkId.size()) { |
||||
|
set<int>::iterator it = unkId.end(); it--; |
||||
|
ret = *it; |
||||
|
unkId.erase(it); |
||||
|
} else { |
||||
|
ret = ourId.front(); |
||||
|
if (time(NULL) - idToInfo[ret].ourLastTry < MIN_RETRY) return false; |
||||
|
ourId.pop_front(); |
||||
|
} |
||||
|
if (idToInfo[ret].ignoreTill && idToInfo[ret].ignoreTill < now) { |
||||
|
ourId.push_back(ret); |
||||
|
idToInfo[ret].ourLastTry = now; |
||||
|
} else { |
||||
|
ip.service = idToInfo[ret].ip; |
||||
|
ip.ourLastSuccess = idToInfo[ret].ourLastSuccess; |
||||
|
break; |
||||
|
} |
||||
|
} while(1); |
||||
|
nDirty++; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
int CAddrDb::Lookup_(const CService &ip) { |
||||
|
if (ipToId.count(ip)) |
||||
|
return ipToId[ip]; |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV, int blocks) { |
||||
|
int id = Lookup_(addr); |
||||
|
if (id == -1) return; |
||||
|
unkId.erase(id); |
||||
|
banned.erase(addr); |
||||
|
CAddrInfo &info = idToInfo[id]; |
||||
|
info.clientVersion = clientV; |
||||
|
info.clientSubVersion = clientSV; |
||||
|
info.blocks = blocks; |
||||
|
info.Update(true); |
||||
|
if (info.IsGood() && goodId.count(id)==0) { |
||||
|
goodId.insert(id); |
||||
|
// printf("%s: good; %i good nodes now\n", ToString(addr).c_str(), (int)goodId.size());
|
||||
|
} |
||||
|
nDirty++; |
||||
|
ourId.push_back(id); |
||||
|
} |
||||
|
|
||||
|
void CAddrDb::Bad_(const CService &addr, int ban) |
||||
|
{ |
||||
|
int id = Lookup_(addr); |
||||
|
if (id == -1) return; |
||||
|
unkId.erase(id); |
||||
|
CAddrInfo &info = idToInfo[id]; |
||||
|
info.Update(false); |
||||
|
uint32_t now = time(NULL); |
||||
|
int ter = info.GetBanTime(); |
||||
|
if (ter) { |
||||
|
// printf("%s: terrible\n", ToString(addr).c_str());
|
||||
|
if (ban < ter) ban = ter; |
||||
|
} |
||||
|
if (ban > 0) { |
||||
|
// printf("%s: ban for %i seconds\n", ToString(addr).c_str(), ban);
|
||||
|
banned[info.ip] = ban + now; |
||||
|
ipToId.erase(info.ip); |
||||
|
goodId.erase(id); |
||||
|
idToInfo.erase(id); |
||||
|
} else { |
||||
|
if (/*!info.IsGood() && */ goodId.count(id)==1) { |
||||
|
goodId.erase(id); |
||||
|
// printf("%s: not good; %i good nodes left\n", ToString(addr).c_str(), (int)goodId.size());
|
||||
|
} |
||||
|
ourId.push_back(id); |
||||
|
} |
||||
|
nDirty++; |
||||
|
} |
||||
|
|
||||
|
void CAddrDb::Skipped_(const CService &addr) |
||||
|
{ |
||||
|
int id = Lookup_(addr); |
||||
|
if (id == -1) return; |
||||
|
unkId.erase(id); |
||||
|
ourId.push_back(id); |
||||
|
// printf("%s: skipped\n", ToString(addr).c_str());
|
||||
|
nDirty++; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void CAddrDb::Add_(const CAddress &addr, bool force) { |
||||
|
if (!force && !addr.IsRoutable()) |
||||
|
return; |
||||
|
CService ipp(addr); |
||||
|
if (banned.count(ipp)) { |
||||
|
time_t bantime = banned[ipp]; |
||||
|
if (force || (bantime < time(NULL) && addr.nTime > bantime)) |
||||
|
banned.erase(ipp); |
||||
|
else |
||||
|
return; |
||||
|
} |
||||
|
if (ipToId.count(ipp)) { |
||||
|
CAddrInfo &ai = idToInfo[ipToId[ipp]]; |
||||
|
if (addr.nTime > ai.lastTry || ai.services != addr.nServices) |
||||
|
{ |
||||
|
ai.lastTry = addr.nTime; |
||||
|
ai.services |= addr.nServices; |
||||
|
// printf("%s: updated\n", ToString(addr).c_str());
|
||||
|
} |
||||
|
if (force) { |
||||
|
ai.ignoreTill = 0; |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
CAddrInfo ai; |
||||
|
ai.ip = ipp; |
||||
|
ai.services = addr.nServices; |
||||
|
ai.lastTry = addr.nTime; |
||||
|
ai.ourLastTry = 0; |
||||
|
ai.total = 0; |
||||
|
ai.success = 0; |
||||
|
int id = nId++; |
||||
|
idToInfo[id] = ai; |
||||
|
ipToId[ipp] = id; |
||||
|
// printf("%s: added\n", ToString(ipp).c_str(), ipToId[ipp]);
|
||||
|
unkId.insert(id); |
||||
|
nDirty++; |
||||
|
} |
||||
|
|
||||
|
void CAddrDb::GetIPs_(set<CNetAddr>& ips, uint64_t requestedFlags, int max, const bool* nets) { |
||||
|
if (goodId.size() == 0) { |
||||
|
int id = -1; |
||||
|
if (ourId.size() == 0) { |
||||
|
if (unkId.size() == 0) return; |
||||
|
id = *unkId.begin(); |
||||
|
} else { |
||||
|
id = *ourId.begin(); |
||||
|
} |
||||
|
if (id >= 0 && (idToInfo[id].services & requestedFlags) == requestedFlags) { |
||||
|
ips.insert(idToInfo[id].ip); |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
std::vector<int> goodIdFiltered; |
||||
|
for (std::set<int>::const_iterator it = goodId.begin(); it != goodId.end(); it++) { |
||||
|
if ((idToInfo[*it].services & requestedFlags) == requestedFlags) |
||||
|
goodIdFiltered.push_back(*it); |
||||
|
} |
||||
|
|
||||
|
if (!goodIdFiltered.size()) |
||||
|
return; |
||||
|
|
||||
|
if (max > goodIdFiltered.size() / 2) |
||||
|
max = goodIdFiltered.size() / 2; |
||||
|
if (max < 1) |
||||
|
max = 1; |
||||
|
|
||||
|
set<int> ids; |
||||
|
while (ids.size() < max) { |
||||
|
ids.insert(goodIdFiltered[rand() % goodIdFiltered.size()]); |
||||
|
} |
||||
|
for (set<int>::const_iterator it = ids.begin(); it != ids.end(); it++) { |
||||
|
CService &ip = idToInfo[*it].ip; |
||||
|
if (nets[ip.GetNetwork()]) |
||||
|
ips.insert(ip); |
||||
|
} |
||||
|
} |
@ -0,0 +1,359 @@ |
|||||
|
#include <stdint.h> |
||||
|
#include <math.h> |
||||
|
|
||||
|
#include <set> |
||||
|
#include <map> |
||||
|
#include <vector> |
||||
|
#include <deque> |
||||
|
|
||||
|
#include "netbase.h" |
||||
|
#include "protocol.h" |
||||
|
#include "util.h" |
||||
|
|
||||
|
#define MIN_RETRY 1000 |
||||
|
|
||||
|
#define REQUIRE_VERSION 170002 |
||||
|
|
||||
|
static inline int GetRequireHeight(const bool testnet = fTestNet) |
||||
|
{ |
||||
|
// return testnet ? 500000 : 350000;
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
std::string static inline ToString(const CService &ip) { |
||||
|
std::string str = ip.ToString(); |
||||
|
while (str.size() < 22) str += ' '; |
||||
|
return str; |
||||
|
} |
||||
|
|
||||
|
class CAddrStat { |
||||
|
private: |
||||
|
float weight; |
||||
|
float count; |
||||
|
float reliability; |
||||
|
public: |
||||
|
CAddrStat() : weight(0), count(0), reliability(0) {} |
||||
|
|
||||
|
void Update(bool good, int64 age, double tau) { |
||||
|
double f = exp(-age/tau); |
||||
|
reliability = reliability * f + (good ? (1.0-f) : 0); |
||||
|
count = count * f + 1; |
||||
|
weight = weight * f + (1.0-f); |
||||
|
} |
||||
|
|
||||
|
IMPLEMENT_SERIALIZE ( |
||||
|
READWRITE(weight); |
||||
|
READWRITE(count); |
||||
|
READWRITE(reliability); |
||||
|
) |
||||
|
|
||||
|
friend class CAddrInfo; |
||||
|
}; |
||||
|
|
||||
|
class CAddrReport { |
||||
|
public: |
||||
|
CService ip; |
||||
|
int clientVersion; |
||||
|
int blocks; |
||||
|
double uptime[5]; |
||||
|
std::string clientSubVersion; |
||||
|
int64_t lastSuccess; |
||||
|
bool fGood; |
||||
|
uint64_t services; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
class CAddrInfo { |
||||
|
private: |
||||
|
CService ip; |
||||
|
uint64_t services; |
||||
|
int64 lastTry; |
||||
|
int64 ourLastTry; |
||||
|
int64 ourLastSuccess; |
||||
|
int64 ignoreTill; |
||||
|
CAddrStat stat2H; |
||||
|
CAddrStat stat8H; |
||||
|
CAddrStat stat1D; |
||||
|
CAddrStat stat1W; |
||||
|
CAddrStat stat1M; |
||||
|
int clientVersion; |
||||
|
int blocks; |
||||
|
int total; |
||||
|
int success; |
||||
|
std::string clientSubVersion; |
||||
|
public: |
||||
|
CAddrInfo() : services(0), lastTry(0), ourLastTry(0), ourLastSuccess(0), ignoreTill(0), clientVersion(0), blocks(0), total(0), success(0) {} |
||||
|
|
||||
|
CAddrReport GetReport() const { |
||||
|
CAddrReport ret; |
||||
|
ret.ip = ip; |
||||
|
ret.clientVersion = clientVersion; |
||||
|
ret.clientSubVersion = clientSubVersion; |
||||
|
ret.blocks = blocks; |
||||
|
ret.uptime[0] = stat2H.reliability; |
||||
|
ret.uptime[1] = stat8H.reliability; |
||||
|
ret.uptime[2] = stat1D.reliability; |
||||
|
ret.uptime[3] = stat1W.reliability; |
||||
|
ret.uptime[4] = stat1M.reliability; |
||||
|
ret.lastSuccess = ourLastSuccess; |
||||
|
ret.fGood = IsGood(); |
||||
|
ret.services = services; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool IsGood() const { |
||||
|
if (ip.GetPort() != GetDefaultPort()) return false; |
||||
|
if (!(services & NODE_NETWORK)) return false; |
||||
|
if (!ip.IsRoutable()) return false; |
||||
|
if (clientVersion && clientVersion < REQUIRE_VERSION) return false; |
||||
|
if (blocks && blocks < GetRequireHeight()) return false; |
||||
|
|
||||
|
if (total <= 3 && success * 2 >= total) return true; |
||||
|
|
||||
|
if (stat2H.reliability > 0.85 && stat2H.count > 2) return true; |
||||
|
if (stat8H.reliability > 0.70 && stat8H.count > 4) return true; |
||||
|
if (stat1D.reliability > 0.55 && stat1D.count > 8) return true; |
||||
|
if (stat1W.reliability > 0.45 && stat1W.count > 16) return true; |
||||
|
if (stat1M.reliability > 0.35 && stat1M.count > 32) return true; |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
int GetBanTime() const { |
||||
|
if (IsGood()) return 0; |
||||
|
if (clientVersion && clientVersion < 31900) { return 604800; } |
||||
|
if (stat1M.reliability - stat1M.weight + 1.0 < 0.15 && stat1M.count > 32) { return 30*86400; } |
||||
|
if (stat1W.reliability - stat1W.weight + 1.0 < 0.10 && stat1W.count > 16) { return 7*86400; } |
||||
|
if (stat1D.reliability - stat1D.weight + 1.0 < 0.05 && stat1D.count > 8) { return 1*86400; } |
||||
|
return 0; |
||||
|
} |
||||
|
int GetIgnoreTime() const { |
||||
|
if (IsGood()) return 0; |
||||
|
if (stat1M.reliability - stat1M.weight + 1.0 < 0.20 && stat1M.count > 2) { return 10*86400; } |
||||
|
if (stat1W.reliability - stat1W.weight + 1.0 < 0.16 && stat1W.count > 2) { return 3*86400; } |
||||
|
if (stat1D.reliability - stat1D.weight + 1.0 < 0.12 && stat1D.count > 2) { return 8*3600; } |
||||
|
if (stat8H.reliability - stat8H.weight + 1.0 < 0.08 && stat8H.count > 2) { return 2*3600; } |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void Update(bool good); |
||||
|
|
||||
|
friend class CAddrDb; |
||||
|
|
||||
|
IMPLEMENT_SERIALIZE ( |
||||
|
unsigned char version = 4; |
||||
|
READWRITE(version); |
||||
|
READWRITE(ip); |
||||
|
READWRITE(services); |
||||
|
READWRITE(lastTry); |
||||
|
unsigned char tried = ourLastTry != 0; |
||||
|
READWRITE(tried); |
||||
|
if (tried) { |
||||
|
READWRITE(ourLastTry); |
||||
|
READWRITE(ignoreTill); |
||||
|
READWRITE(stat2H); |
||||
|
READWRITE(stat8H); |
||||
|
READWRITE(stat1D); |
||||
|
READWRITE(stat1W); |
||||
|
if (version >= 1) |
||||
|
READWRITE(stat1M); |
||||
|
else |
||||
|
if (!fWrite) |
||||
|
*((CAddrStat*)(&stat1M)) = stat1W; |
||||
|
READWRITE(total); |
||||
|
READWRITE(success); |
||||
|
READWRITE(clientVersion); |
||||
|
if (version >= 2) |
||||
|
READWRITE(clientSubVersion); |
||||
|
if (version >= 3) |
||||
|
READWRITE(blocks); |
||||
|
if (version >= 4) |
||||
|
READWRITE(ourLastSuccess); |
||||
|
} |
||||
|
) |
||||
|
}; |
||||
|
|
||||
|
class CAddrDbStats { |
||||
|
public: |
||||
|
int nBanned; |
||||
|
int nAvail; |
||||
|
int nTracked; |
||||
|
int nNew; |
||||
|
int nGood; |
||||
|
int nAge; |
||||
|
}; |
||||
|
|
||||
|
struct CServiceResult { |
||||
|
CService service; |
||||
|
bool fGood; |
||||
|
int nBanTime; |
||||
|
int nHeight; |
||||
|
int nClientV; |
||||
|
std::string strClientV; |
||||
|
int64 ourLastSuccess; |
||||
|
}; |
||||
|
|
||||
|
// seen nodes
|
||||
|
// / \ |
||||
|
// (a) banned nodes available nodes--------------
|
||||
|
// / | \ |
||||
|
// tracked nodes (b) unknown nodes (e) active nodes
|
||||
|
// / \ |
||||
|
// (d) good nodes (c) non-good nodes
|
||||
|
|
||||
|
class CAddrDb { |
||||
|
private: |
||||
|
mutable CCriticalSection cs; |
||||
|
int nId; // number of address id's
|
||||
|
std::map<int, CAddrInfo> idToInfo; // map address id to address info (b,c,d,e)
|
||||
|
std::map<CService, int> ipToId; // map ip to id (b,c,d,e)
|
||||
|
std::deque<int> ourId; // sequence of tried nodes, in order we have tried connecting to them (c,d)
|
||||
|
std::set<int> unkId; // set of nodes not yet tried (b)
|
||||
|
std::set<int> goodId; // set of good nodes (d, good e)
|
||||
|
int nDirty; |
||||
|
|
||||
|
protected: |
||||
|
// internal routines that assume proper locks are acquired
|
||||
|
void Add_(const CAddress &addr, bool force); // add an address
|
||||
|
bool Get_(CServiceResult &ip, int& wait); // get an IP to test (must call Good_, Bad_, or Skipped_ on result afterwards)
|
||||
|
bool GetMany_(std::vector<CServiceResult> &ips, int max, int& wait); |
||||
|
void Good_(const CService &ip, int clientV, std::string clientSV, int blocks); // mark an IP as good (must have been returned by Get_)
|
||||
|
void Bad_(const CService &ip, int ban); // mark an IP as bad (and optionally ban it) (must have been returned by Get_)
|
||||
|
void Skipped_(const CService &ip); // mark an IP as skipped (must have been returned by Get_)
|
||||
|
int Lookup_(const CService &ip); // look up id of an IP
|
||||
|
void GetIPs_(std::set<CNetAddr>& ips, uint64_t requestedFlags, int max, const bool *nets); // get a random set of IPs (shared lock only)
|
||||
|
|
||||
|
public: |
||||
|
std::map<CService, time_t> banned; // nodes that are banned, with their unban time (a)
|
||||
|
|
||||
|
void GetStats(CAddrDbStats &stats) { |
||||
|
SHARED_CRITICAL_BLOCK(cs) { |
||||
|
stats.nBanned = banned.size(); |
||||
|
stats.nAvail = idToInfo.size(); |
||||
|
stats.nTracked = ourId.size(); |
||||
|
stats.nGood = goodId.size(); |
||||
|
stats.nNew = unkId.size(); |
||||
|
stats.nAge = time(NULL) - idToInfo[ourId[0]].ourLastTry; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void ResetIgnores() { |
||||
|
for (std::map<int, CAddrInfo>::iterator it = idToInfo.begin(); it != idToInfo.end(); it++) { |
||||
|
(*it).second.ignoreTill = 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::vector<CAddrReport> GetAll() { |
||||
|
std::vector<CAddrReport> ret; |
||||
|
SHARED_CRITICAL_BLOCK(cs) { |
||||
|
for (std::deque<int>::const_iterator it = ourId.begin(); it != ourId.end(); it++) { |
||||
|
const CAddrInfo &info = idToInfo[*it]; |
||||
|
if (info.success > 0) { |
||||
|
ret.push_back(info.GetReport()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
// serialization code
|
||||
|
// format:
|
||||
|
// nVersion (0 for now)
|
||||
|
// n (number of ips in (b,c,d))
|
||||
|
// CAddrInfo[n]
|
||||
|
// banned
|
||||
|
// acquires a shared lock (this does not suffice for read mode, but we assume that only happens at startup, single-threaded)
|
||||
|
// this way, dumping does not interfere with GetIPs_, which is called from the DNS thread
|
||||
|
IMPLEMENT_SERIALIZE (({ |
||||
|
int nVersion = 0; |
||||
|
READWRITE(nVersion); |
||||
|
SHARED_CRITICAL_BLOCK(cs) { |
||||
|
if (fWrite) { |
||||
|
CAddrDb *db = const_cast<CAddrDb*>(this); |
||||
|
int n = ourId.size() + unkId.size(); |
||||
|
READWRITE(n); |
||||
|
for (std::deque<int>::const_iterator it = ourId.begin(); it != ourId.end(); it++) { |
||||
|
std::map<int, CAddrInfo>::iterator ci = db->idToInfo.find(*it); |
||||
|
READWRITE((*ci).second); |
||||
|
} |
||||
|
for (std::set<int>::const_iterator it = unkId.begin(); it != unkId.end(); it++) { |
||||
|
std::map<int, CAddrInfo>::iterator ci = db->idToInfo.find(*it); |
||||
|
READWRITE((*ci).second); |
||||
|
} |
||||
|
} else { |
||||
|
CAddrDb *db = const_cast<CAddrDb*>(this); |
||||
|
db->nId = 0; |
||||
|
int n; |
||||
|
READWRITE(n); |
||||
|
for (int i=0; i<n; i++) { |
||||
|
CAddrInfo info; |
||||
|
READWRITE(info); |
||||
|
if (!info.GetBanTime()) { |
||||
|
int id = db->nId++; |
||||
|
db->idToInfo[id] = info; |
||||
|
db->ipToId[info.ip] = id; |
||||
|
if (info.ourLastTry) { |
||||
|
db->ourId.push_back(id); |
||||
|
if (info.IsGood()) db->goodId.insert(id); |
||||
|
} else { |
||||
|
db->unkId.insert(id); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
db->nDirty++; |
||||
|
} |
||||
|
READWRITE(banned); |
||||
|
} |
||||
|
});) |
||||
|
|
||||
|
void Add(const CAddress &addr, bool fForce = false) { |
||||
|
CRITICAL_BLOCK(cs) |
||||
|
Add_(addr, fForce); |
||||
|
} |
||||
|
void Add(const std::vector<CAddress> &vAddr, bool fForce = false) { |
||||
|
CRITICAL_BLOCK(cs) |
||||
|
for (int i=0; i<vAddr.size(); i++) |
||||
|
Add_(vAddr[i], fForce); |
||||
|
} |
||||
|
void Good(const CService &addr, int clientVersion, std::string clientSubVersion, int blocks) { |
||||
|
CRITICAL_BLOCK(cs) |
||||
|
Good_(addr, clientVersion, clientSubVersion, blocks); |
||||
|
} |
||||
|
void Skipped(const CService &addr) { |
||||
|
CRITICAL_BLOCK(cs) |
||||
|
Skipped_(addr); |
||||
|
} |
||||
|
void Bad(const CService &addr, int ban = 0) { |
||||
|
CRITICAL_BLOCK(cs) |
||||
|
Bad_(addr, ban); |
||||
|
} |
||||
|
bool Get(CServiceResult &ip, int& wait) { |
||||
|
CRITICAL_BLOCK(cs) |
||||
|
return Get_(ip, wait); |
||||
|
} |
||||
|
void GetMany(std::vector<CServiceResult> &ips, int max, int& wait) { |
||||
|
CRITICAL_BLOCK(cs) { |
||||
|
while (max > 0) { |
||||
|
CServiceResult ip = {}; |
||||
|
if (!Get_(ip, wait)) |
||||
|
return; |
||||
|
ips.push_back(ip); |
||||
|
max--; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
void ResultMany(const std::vector<CServiceResult> &ips) { |
||||
|
CRITICAL_BLOCK(cs) { |
||||
|
for (int i=0; i<ips.size(); i++) { |
||||
|
if (ips[i].fGood) { |
||||
|
Good_(ips[i].service, ips[i].nClientV, ips[i].strClientV, ips[i].nHeight); |
||||
|
} else { |
||||
|
Bad_(ips[i].service, ips[i].nBanTime); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
void GetIPs(std::set<CNetAddr>& ips, uint64_t requestedFlags, int max, const bool *nets) { |
||||
|
SHARED_CRITICAL_BLOCK(cs) |
||||
|
GetIPs_(ips, requestedFlags, max, nets); |
||||
|
} |
||||
|
}; |
@ -0,0 +1,457 @@ |
|||||
|
#include <stdbool.h> |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
#include <strings.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <stdint.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <arpa/inet.h> |
||||
|
#include <time.h> |
||||
|
#include <ctype.h> |
||||
|
#include <unistd.h> |
||||
|
|
||||
|
#include "dns.h" |
||||
|
|
||||
|
#define BUFLEN 512 |
||||
|
|
||||
|
#if defined IP_RECVDSTADDR |
||||
|
# define DSTADDR_SOCKOPT IP_RECVDSTADDR |
||||
|
# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_addr))) |
||||
|
# define dstaddr(x) (CMSG_DATA(x)) |
||||
|
#elif defined IPV6_PKTINFO |
||||
|
struct in6_pktinfo |
||||
|
{ |
||||
|
struct in6_addr ipi6_addr; /* src/dst IPv6 address */ |
||||
|
unsigned int ipi6_ifindex; /* send/recv interface index */ |
||||
|
}; |
||||
|
|
||||
|
# define DSTADDR_SOCKOPT IPV6_PKTINFO |
||||
|
# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_pktinfo))) |
||||
|
# define dstaddr(x) (&(((struct in6_pktinfo *)(CMSG_DATA(x)))->ipi6_addr)) |
||||
|
#else |
||||
|
# error "can't determine socket option" |
||||
|
#endif |
||||
|
|
||||
|
union control_data { |
||||
|
struct cmsghdr cmsg; |
||||
|
unsigned char data[DSTADDR_DATASIZE]; |
||||
|
}; |
||||
|
|
||||
|
typedef enum { |
||||
|
CLASS_IN = 1, |
||||
|
QCLASS_ANY = 255 |
||||
|
} dns_class; |
||||
|
|
||||
|
typedef enum { |
||||
|
TYPE_A = 1, |
||||
|
TYPE_NS = 2, |
||||
|
TYPE_CNAME = 5, |
||||
|
TYPE_SOA = 6, |
||||
|
TYPE_MX = 15, |
||||
|
TYPE_AAAA = 28, |
||||
|
TYPE_SRV = 33, |
||||
|
QTYPE_ANY = 255 |
||||
|
} dns_type; |
||||
|
|
||||
|
|
||||
|
// 0: ok
|
||||
|
// -1: premature end of input, forward reference, component > 63 char, invalid character
|
||||
|
// -2: insufficient space in output
|
||||
|
int static parse_name(const unsigned char **inpos, const unsigned char *inend, const unsigned char *inbuf, char *buf, size_t bufsize) { |
||||
|
size_t bufused = 0; |
||||
|
int init = 1; |
||||
|
do { |
||||
|
if (*inpos == inend) |
||||
|
return -1; |
||||
|
// read length of next component
|
||||
|
int octet = *((*inpos)++); |
||||
|
if (octet == 0) { |
||||
|
buf[bufused] = 0; |
||||
|
return 0; |
||||
|
} |
||||
|
// add dot in output
|
||||
|
if (!init) { |
||||
|
if (bufused == bufsize-1) |
||||
|
return -2; |
||||
|
buf[bufused++] = '.'; |
||||
|
} else |
||||
|
init = 0; |
||||
|
// handle references
|
||||
|
if ((octet & 0xC0) == 0xC0) { |
||||
|
if (*inpos == inend) |
||||
|
return -1; |
||||
|
int ref = ((octet - 0xC0) << 8) + *((*inpos)++); |
||||
|
if (ref < 0 || ref >= (*inpos)-inbuf-2) return -1; |
||||
|
const unsigned char *newbuf = inbuf + ref; |
||||
|
return parse_name(&newbuf, (*inpos) - 2, inbuf, buf+bufused, bufsize-bufused); |
||||
|
} |
||||
|
if (octet > 63) return -1; |
||||
|
// copy label
|
||||
|
while (octet) { |
||||
|
if (*inpos == inend) |
||||
|
return -1; |
||||
|
if (bufused == bufsize-1) |
||||
|
return -2; |
||||
|
int c = *((*inpos)++); |
||||
|
if (c == '.') |
||||
|
return -1; |
||||
|
octet--; |
||||
|
buf[bufused++] = c; |
||||
|
} |
||||
|
} while(1); |
||||
|
} |
||||
|
|
||||
|
// 0: k
|
||||
|
// -1: component > 63 characters
|
||||
|
// -2: insufficent space in output
|
||||
|
// -3: two subsequent dots
|
||||
|
int static write_name(unsigned char** outpos, const unsigned char *outend, const char *name, int offset) { |
||||
|
while (*name != 0) { |
||||
|
char *dot = strchr(name, '.'); |
||||
|
const char *fin = dot; |
||||
|
if (!dot) fin = name + strlen(name); |
||||
|
if (fin - name > 63) return -1; |
||||
|
if (fin == name) return -3; |
||||
|
if (outend - *outpos < fin - name + 2) return -2; |
||||
|
*((*outpos)++) = fin - name; |
||||
|
memcpy(*outpos, name, fin - name); |
||||
|
*outpos += fin - name; |
||||
|
if (!dot) break; |
||||
|
name = dot + 1; |
||||
|
} |
||||
|
if (offset < 0) { |
||||
|
// no reference
|
||||
|
if (outend == *outpos) return -2; |
||||
|
*((*outpos)++) = 0; |
||||
|
} else { |
||||
|
if (outend - *outpos < 2) return -2; |
||||
|
*((*outpos)++) = (offset >> 8) | 0xC0; |
||||
|
*((*outpos)++) = offset & 0xFF; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int static write_record(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_type typ, dns_class cls, int ttl) { |
||||
|
unsigned char *oldpos = *outpos; |
||||
|
int error = 0; |
||||
|
// name
|
||||
|
int ret = write_name(outpos, outend, name, offset); |
||||
|
if (ret) { error = ret; goto error; } |
||||
|
if (outend - *outpos < 8) { error = -4; goto error; } |
||||
|
// type
|
||||
|
*((*outpos)++) = typ >> 8; *((*outpos)++) = typ & 0xFF; |
||||
|
// class
|
||||
|
*((*outpos)++) = cls >> 8; *((*outpos)++) = cls & 0xFF; |
||||
|
// ttl
|
||||
|
*((*outpos)++) = (ttl >> 24) & 0xFF; *((*outpos)++) = (ttl >> 16) & 0xFF; *((*outpos)++) = (ttl >> 8) & 0xFF; *((*outpos)++) = ttl & 0xFF; |
||||
|
return 0; |
||||
|
error: |
||||
|
*outpos = oldpos; |
||||
|
return error; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int static write_record_a(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const addr_t *ip) { |
||||
|
if (ip->v != 4) |
||||
|
return -6; |
||||
|
unsigned char *oldpos = *outpos; |
||||
|
int error = 0; |
||||
|
int ret = write_record(outpos, outend, name, offset, TYPE_A, cls, ttl); |
||||
|
if (ret) return ret; |
||||
|
if (outend - *outpos < 6) { error = -5; goto error; } |
||||
|
// rdlength
|
||||
|
*((*outpos)++) = 0; *((*outpos)++) = 4; |
||||
|
// rdata
|
||||
|
for (int i=0; i<4; i++) |
||||
|
*((*outpos)++) = ip->data.v4[i]; |
||||
|
return 0; |
||||
|
error: |
||||
|
*outpos = oldpos; |
||||
|
return error; |
||||
|
} |
||||
|
|
||||
|
int static write_record_aaaa(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const addr_t *ip) { |
||||
|
if (ip->v != 6) |
||||
|
return -6; |
||||
|
unsigned char *oldpos = *outpos; |
||||
|
int error = 0; |
||||
|
int ret = write_record(outpos, outend, name, offset, TYPE_AAAA, cls, ttl); |
||||
|
if (ret) return ret; |
||||
|
if (outend - *outpos < 6) { error = -5; goto error; } |
||||
|
// rdlength
|
||||
|
*((*outpos)++) = 0; *((*outpos)++) = 16; |
||||
|
// rdata
|
||||
|
for (int i=0; i<16; i++) |
||||
|
*((*outpos)++) = ip->data.v6[i]; |
||||
|
return 0; |
||||
|
error: |
||||
|
*outpos = oldpos; |
||||
|
return error; |
||||
|
} |
||||
|
|
||||
|
int static write_record_ns(unsigned char** outpos, const unsigned char *outend, char *name, int offset, dns_class cls, int ttl, const char *ns) { |
||||
|
unsigned char *oldpos = *outpos; |
||||
|
int ret = write_record(outpos, outend, name, offset, TYPE_NS, cls, ttl); |
||||
|
if (ret) return ret; |
||||
|
int error = 0; |
||||
|
if (outend - *outpos < 2) { error = -5; goto error; } |
||||
|
(*outpos) += 2; |
||||
|
unsigned char *curpos = *outpos; |
||||
|
ret = write_name(outpos, outend, ns, -1); |
||||
|
if (ret) { error = ret; goto error; } |
||||
|
curpos[-2] = (*outpos - curpos) >> 8; |
||||
|
curpos[-1] = (*outpos - curpos) & 0xFF; |
||||
|
return 0; |
||||
|
error: |
||||
|
*outpos = oldpos; |
||||
|
return error; |
||||
|
} |
||||
|
|
||||
|
int static write_record_soa(unsigned char** outpos, const unsigned char *outend, char *name, int offset, dns_class cls, int ttl, const char* mname, const char *rname, |
||||
|
uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) { |
||||
|
unsigned char *oldpos = *outpos; |
||||
|
int ret = write_record(outpos, outend, name, offset, TYPE_SOA, cls, ttl); |
||||
|
if (ret) return ret; |
||||
|
int error = 0; |
||||
|
if (outend - *outpos < 2) { error = -5; goto error; } |
||||
|
(*outpos) += 2; |
||||
|
unsigned char *curpos = *outpos; |
||||
|
ret = write_name(outpos, outend, mname, -1); |
||||
|
if (ret) { error = ret; goto error; } |
||||
|
ret = write_name(outpos, outend, rname, -1); |
||||
|
if (ret) { error = ret; goto error; } |
||||
|
if (outend - *outpos < 20) { error = -5; goto error; } |
||||
|
*((*outpos)++) = (serial >> 24) & 0xFF; *((*outpos)++) = (serial >> 16) & 0xFF; *((*outpos)++) = (serial >> 8) & 0xFF; *((*outpos)++) = serial & 0xFF; |
||||
|
*((*outpos)++) = (refresh >> 24) & 0xFF; *((*outpos)++) = (refresh >> 16) & 0xFF; *((*outpos)++) = (refresh >> 8) & 0xFF; *((*outpos)++) = refresh & 0xFF; |
||||
|
*((*outpos)++) = (retry >> 24) & 0xFF; *((*outpos)++) = (retry >> 16) & 0xFF; *((*outpos)++) = (retry >> 8) & 0xFF; *((*outpos)++) = retry & 0xFF; |
||||
|
*((*outpos)++) = (expire >> 24) & 0xFF; *((*outpos)++) = (expire >> 16) & 0xFF; *((*outpos)++) = (expire >> 8) & 0xFF; *((*outpos)++) = expire & 0xFF; |
||||
|
*((*outpos)++) = (minimum >> 24) & 0xFF; *((*outpos)++) = (minimum >> 16) & 0xFF; *((*outpos)++) = (minimum >> 8) & 0xFF; *((*outpos)++) = minimum & 0xFF; |
||||
|
curpos[-2] = (*outpos - curpos) >> 8; |
||||
|
curpos[-1] = (*outpos - curpos) & 0xFF; |
||||
|
return 0; |
||||
|
error: |
||||
|
*outpos = oldpos; |
||||
|
return error; |
||||
|
} |
||||
|
|
||||
|
ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insize, unsigned char* outbuf) { |
||||
|
int error = 0; |
||||
|
if (insize < 12) // DNS header
|
||||
|
return -1; |
||||
|
// copy id
|
||||
|
outbuf[0] = inbuf[0]; |
||||
|
outbuf[1] = inbuf[1]; |
||||
|
// copy flags;
|
||||
|
outbuf[2] = inbuf[2]; |
||||
|
outbuf[3] = inbuf[3]; |
||||
|
// clear error
|
||||
|
outbuf[3] &= ~15; |
||||
|
// check qr
|
||||
|
if (inbuf[2] & 128) { /* printf("Got response?\n"); */ error = 1; goto error; } |
||||
|
// check opcode
|
||||
|
if (((inbuf[2] & 120) >> 3) != 0) { /* printf("Opcode nonzero?\n"); */ error = 4; goto error; } |
||||
|
// unset TC
|
||||
|
outbuf[2] &= ~2; |
||||
|
// unset RA
|
||||
|
outbuf[3] &= ~128; |
||||
|
// check questions
|
||||
|
int nquestion = (inbuf[4] << 8) + inbuf[5]; |
||||
|
if (nquestion == 0) { /* printf("No questions?\n"); */ error = 0; goto error; } |
||||
|
if (nquestion > 1) { /* printf("Multiple questions %i?\n", nquestion); */ error = 4; goto error; } |
||||
|
const unsigned char *inpos = inbuf + 12; |
||||
|
const unsigned char *inend = inbuf + insize; |
||||
|
char name[256]; |
||||
|
int offset = inpos - inbuf; |
||||
|
int ret = parse_name(&inpos, inend, inbuf, name, 256); |
||||
|
if (ret == -1) { error = 1; goto error; } |
||||
|
if (ret == -2) { error = 5; goto error; } |
||||
|
int namel = strlen(name), hostl = strlen(opt->host); |
||||
|
if (strcasecmp(name, opt->host) && (namel<hostl+2 || name[namel-hostl-1]!='.' || strcasecmp(name+namel-hostl,opt->host))) { error = 5; goto error; } |
||||
|
if (inend - inpos < 4) { error = 1; goto error; } |
||||
|
// copy question to output
|
||||
|
memcpy(outbuf+12, inbuf+12, inpos+4 - (inbuf+12)); |
||||
|
// set counts
|
||||
|
outbuf[4] = 0; outbuf[5] = 1; |
||||
|
outbuf[6] = 0; outbuf[7] = 0; |
||||
|
outbuf[8] = 0; outbuf[9] = 0; |
||||
|
outbuf[10] = 0; outbuf[11] = 0; |
||||
|
// set qr
|
||||
|
outbuf[2] |= 128; |
||||
|
|
||||
|
int typ = (inpos[0] << 8) + inpos[1]; |
||||
|
int cls = (inpos[2] << 8) + inpos[3]; |
||||
|
inpos += 4; |
||||
|
|
||||
|
unsigned char *outpos = outbuf+(inpos-inbuf); |
||||
|
unsigned char *outend = outbuf + BUFLEN; |
||||
|
|
||||
|
// printf("DNS: Request host='%s' type=%i class=%i\n", name, typ, cls);
|
||||
|
|
||||
|
// calculate max size of authority section
|
||||
|
|
||||
|
int max_auth_size = 0; |
||||
|
|
||||
|
if (!((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY))) { |
||||
|
// authority section will be necessary, either NS or SOA
|
||||
|
unsigned char *newpos = outpos; |
||||
|
write_record_ns(&newpos, outend, "", offset, CLASS_IN, 0, opt->ns); |
||||
|
max_auth_size = newpos - outpos; |
||||
|
|
||||
|
newpos = outpos; |
||||
|
write_record_soa(&newpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800); |
||||
|
if (max_auth_size < newpos - outpos) |
||||
|
max_auth_size = newpos - outpos; |
||||
|
// printf("Authority section will claim %i bytes max\n", max_auth_size);
|
||||
|
} |
||||
|
|
||||
|
// Answer section
|
||||
|
|
||||
|
int have_ns = 0; |
||||
|
|
||||
|
// NS records
|
||||
|
if ((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) { |
||||
|
int ret2 = write_record_ns(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns); |
||||
|
// printf("wrote NS record: %i\n", ret2);
|
||||
|
if (!ret2) { outbuf[7]++; have_ns++; } |
||||
|
} |
||||
|
|
||||
|
// SOA records
|
||||
|
if ((typ == TYPE_SOA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY) && opt->mbox) { |
||||
|
int ret2 = write_record_soa(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800); |
||||
|
// printf("wrote SOA record: %i\n", ret2);
|
||||
|
if (!ret2) { outbuf[7]++; } |
||||
|
} |
||||
|
|
||||
|
// A/AAAA records
|
||||
|
if ((typ == TYPE_A || typ == TYPE_AAAA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) { |
||||
|
addr_t addr[32]; |
||||
|
int naddr = opt->cb((void*)opt, name, addr, 32, typ == TYPE_A || typ == QTYPE_ANY, typ == TYPE_AAAA || typ == QTYPE_ANY); |
||||
|
int n = 0; |
||||
|
while (n < naddr) { |
||||
|
int ret = 1; |
||||
|
if (addr[n].v == 4) |
||||
|
ret = write_record_a(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]); |
||||
|
else if (addr[n].v == 6) |
||||
|
ret = write_record_aaaa(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]); |
||||
|
// printf("wrote A record: %i\n", ret);
|
||||
|
if (!ret) { |
||||
|
n++; |
||||
|
outbuf[7]++; |
||||
|
} else |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Authority section
|
||||
|
if (!have_ns && outbuf[7]) { |
||||
|
int ret2 = write_record_ns(&outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns); |
||||
|
// printf("wrote NS record: %i\n", ret2);
|
||||
|
if (!ret2) { |
||||
|
outbuf[9]++; |
||||
|
} |
||||
|
} |
||||
|
else if (!outbuf[7]) { |
||||
|
// Didn't include any answers, so reply with SOA as this is a negative
|
||||
|
// response. If we replied with NS above we'd create a bad horizontal
|
||||
|
// referral loop, as the NS response indicates where the resolver should
|
||||
|
// try next.
|
||||
|
int ret2 = write_record_soa(&outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800); |
||||
|
// printf("wrote SOA record: %i\n", ret2);
|
||||
|
if (!ret2) { outbuf[9]++; } |
||||
|
} |
||||
|
|
||||
|
// set AA
|
||||
|
outbuf[2] |= 4; |
||||
|
|
||||
|
return outpos - outbuf; |
||||
|
error: |
||||
|
// set error
|
||||
|
outbuf[3] |= error & 0xF; |
||||
|
// set counts
|
||||
|
outbuf[4] = 0; outbuf[5] = 0; |
||||
|
outbuf[6] = 0; outbuf[7] = 0; |
||||
|
outbuf[8] = 0; outbuf[9] = 0; |
||||
|
outbuf[10] = 0; outbuf[11] = 0; |
||||
|
return 12; |
||||
|
} |
||||
|
|
||||
|
static int listenSocket = -1; |
||||
|
|
||||
|
int dnsserver(dns_opt_t *opt) { |
||||
|
struct sockaddr_in6 si_other; |
||||
|
int senderSocket = -1; |
||||
|
senderSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
||||
|
if (senderSocket == -1) |
||||
|
return -3; |
||||
|
|
||||
|
int replySocket; |
||||
|
if (listenSocket == -1) { |
||||
|
struct sockaddr_in6 si_me; |
||||
|
if ((listenSocket=socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP))==-1) { |
||||
|
listenSocket = -1; |
||||
|
return -1; |
||||
|
} |
||||
|
replySocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
||||
|
if (replySocket == -1) |
||||
|
{ |
||||
|
close(listenSocket); |
||||
|
return -1; |
||||
|
} |
||||
|
int sockopt = 1; |
||||
|
setsockopt(listenSocket, IPPROTO_IPV6, DSTADDR_SOCKOPT, &sockopt, sizeof sockopt); |
||||
|
memset((char *) &si_me, 0, sizeof(si_me)); |
||||
|
si_me.sin6_family = AF_INET6; |
||||
|
si_me.sin6_port = htons(opt->port); |
||||
|
si_me.sin6_addr = in6addr_any; |
||||
|
if (bind(listenSocket, (struct sockaddr*)&si_me, sizeof(si_me))==-1) |
||||
|
return -2; |
||||
|
} |
||||
|
|
||||
|
unsigned char inbuf[BUFLEN], outbuf[BUFLEN]; |
||||
|
struct iovec iov[1] = { |
||||
|
{ |
||||
|
.iov_base = inbuf, |
||||
|
.iov_len = sizeof(inbuf), |
||||
|
}, |
||||
|
}; |
||||
|
union control_data cmsg; |
||||
|
struct msghdr msg = { |
||||
|
.msg_name = &si_other, |
||||
|
.msg_namelen = sizeof(si_other), |
||||
|
.msg_iov = iov, |
||||
|
.msg_iovlen = 1, |
||||
|
.msg_control = &cmsg, |
||||
|
.msg_controllen = sizeof(cmsg), |
||||
|
}; |
||||
|
for (; 1; ++(opt->nRequests)) |
||||
|
{ |
||||
|
ssize_t insize = recvmsg(listenSocket, &msg, 0); |
||||
|
// unsigned char *addr = (unsigned char*)&si_other.sin_addr.s_addr;
|
||||
|
// printf("DNS: Request %llu from %i.%i.%i.%i:%i of %i bytes\n", (unsigned long long)(opt->nRequests), addr[0], addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize);
|
||||
|
if (insize <= 0) |
||||
|
continue; |
||||
|
|
||||
|
ssize_t ret = dnshandle(opt, inbuf, insize, outbuf); |
||||
|
if (ret <= 0) |
||||
|
continue; |
||||
|
|
||||
|
bool handled = false; |
||||
|
for (struct cmsghdr*hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) |
||||
|
{ |
||||
|
if (hdr->cmsg_level == IPPROTO_IP && hdr->cmsg_type == DSTADDR_SOCKOPT) |
||||
|
{ |
||||
|
msg.msg_iov[0].iov_base = outbuf; |
||||
|
msg.msg_iov[0].iov_len = ret; |
||||
|
sendmsg(listenSocket, &msg, 0); |
||||
|
msg.msg_iov[0].iov_base = inbuf; |
||||
|
msg.msg_iov[0].iov_len = sizeof(inbuf); |
||||
|
handled = true; |
||||
|
} |
||||
|
} |
||||
|
if (!handled) |
||||
|
sendto(listenSocket, outbuf, ret, 0, (struct sockaddr*)&si_other, sizeof(si_other)); |
||||
|
} |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
#ifndef _DNS_H_ |
||||
|
#define _DNS_H_ 1 |
||||
|
|
||||
|
#include <stdint.h> |
||||
|
|
||||
|
typedef struct { |
||||
|
int v; |
||||
|
union { |
||||
|
unsigned char v4[4]; |
||||
|
unsigned char v6[16]; |
||||
|
} data; |
||||
|
} addr_t; |
||||
|
|
||||
|
typedef struct { |
||||
|
int port; |
||||
|
int datattl; |
||||
|
int nsttl; |
||||
|
const char *host; |
||||
|
const char *ns; |
||||
|
const char *mbox; |
||||
|
int (*cb)(void *opt, char *requested_hostname, addr_t *addr, int max, int ipv4, int ipv6); |
||||
|
// stats
|
||||
|
uint64_t nRequests; |
||||
|
} dns_opt_t; |
||||
|
|
||||
|
extern int dnsserver(dns_opt_t *opt); |
||||
|
|
||||
|
#endif |
@ -0,0 +1,509 @@ |
|||||
|
#include <algorithm> |
||||
|
|
||||
|
#define __STDC_FORMAT_MACROS |
||||
|
#include <inttypes.h> |
||||
|
#include <pthread.h> |
||||
|
#include <signal.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <getopt.h> |
||||
|
|
||||
|
#include "bitcoin.h" |
||||
|
#include "db.h" |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
bool fTestNet = false; |
||||
|
|
||||
|
class CDnsSeedOpts { |
||||
|
public: |
||||
|
int nThreads; |
||||
|
int nPort; |
||||
|
int nDnsThreads; |
||||
|
int fUseTestNet; |
||||
|
int fWipeBan; |
||||
|
int fWipeIgnore; |
||||
|
const char *mbox; |
||||
|
const char *ns; |
||||
|
const char *host; |
||||
|
const char *tor; |
||||
|
const char *ipv4_proxy; |
||||
|
const char *ipv6_proxy; |
||||
|
std::set<uint64_t> filter_whitelist; |
||||
|
|
||||
|
CDnsSeedOpts() : nThreads(96), nDnsThreads(4), nPort(53), mbox(NULL), ns(NULL), host(NULL), tor(NULL), fUseTestNet(false), fWipeBan(false), fWipeIgnore(false), ipv4_proxy(NULL), ipv6_proxy(NULL) {} |
||||
|
|
||||
|
void ParseCommandLine(int argc, char **argv) { |
||||
|
static const char *help = "Bitcoin-seeder\n" |
||||
|
"Usage: %s -h <host> -n <ns> [-m <mbox>] [-t <threads>] [-p <port>]\n" |
||||
|
"\n" |
||||
|
"Options:\n" |
||||
|
"-h <host> Hostname of the DNS seed\n" |
||||
|
"-n <ns> Hostname of the nameserver\n" |
||||
|
"-m <mbox> E-Mail address reported in SOA records\n" |
||||
|
"-t <threads> Number of crawlers to run in parallel (default 96)\n" |
||||
|
"-d <threads> Number of DNS server threads (default 4)\n" |
||||
|
"-p <port> UDP port to listen on (default 53)\n" |
||||
|
"-o <ip:port> Tor proxy IP/Port\n" |
||||
|
"-i <ip:port> IPV4 SOCKS5 proxy IP/Port\n" |
||||
|
"-k <ip:port> IPV6 SOCKS5 proxy IP/Port\n" |
||||
|
"-w f1,f2,... Allow these flag combinations as filters\n" |
||||
|
"--testnet Use testnet\n" |
||||
|
"--wipeban Wipe list of banned nodes\n" |
||||
|
"--wipeignore Wipe list of ignored nodes\n" |
||||
|
"-?, --help Show this text\n" |
||||
|
"\n"; |
||||
|
bool showHelp = false; |
||||
|
|
||||
|
while(1) { |
||||
|
static struct option long_options[] = { |
||||
|
{"host", required_argument, 0, 'h'}, |
||||
|
{"ns", required_argument, 0, 'n'}, |
||||
|
{"mbox", required_argument, 0, 'm'}, |
||||
|
{"threads", required_argument, 0, 't'}, |
||||
|
{"dnsthreads", required_argument, 0, 'd'}, |
||||
|
{"port", required_argument, 0, 'p'}, |
||||
|
{"onion", required_argument, 0, 'o'}, |
||||
|
{"proxyipv4", required_argument, 0, 'i'}, |
||||
|
{"proxyipv6", required_argument, 0, 'k'}, |
||||
|
{"filter", required_argument, 0, 'w'}, |
||||
|
{"testnet", no_argument, &fUseTestNet, 1}, |
||||
|
{"wipeban", no_argument, &fWipeBan, 1}, |
||||
|
{"wipeignore", no_argument, &fWipeBan, 1}, |
||||
|
{"help", no_argument, 0, 'h'}, |
||||
|
{0, 0, 0, 0} |
||||
|
}; |
||||
|
int option_index = 0; |
||||
|
int c = getopt_long(argc, argv, "h:n:m:t:p:d:o:i:k:w:", long_options, &option_index); |
||||
|
if (c == -1) break; |
||||
|
switch (c) { |
||||
|
case 'h': { |
||||
|
host = optarg; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case 'm': { |
||||
|
mbox = optarg; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case 'n': { |
||||
|
ns = optarg; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case 't': { |
||||
|
int n = strtol(optarg, NULL, 10); |
||||
|
if (n > 0 && n < 1000) nThreads = n; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case 'd': { |
||||
|
int n = strtol(optarg, NULL, 10); |
||||
|
if (n > 0 && n < 1000) nDnsThreads = n; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case 'p': { |
||||
|
int p = strtol(optarg, NULL, 10); |
||||
|
if (p > 0 && p < 65536) nPort = p; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case 'o': { |
||||
|
tor = optarg; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case 'i': { |
||||
|
ipv4_proxy = optarg; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case 'k': { |
||||
|
ipv6_proxy = optarg; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case 'w': { |
||||
|
char* ptr = optarg; |
||||
|
while (*ptr != 0) { |
||||
|
unsigned long l = strtoul(ptr, &ptr, 0); |
||||
|
if (*ptr == ',') { |
||||
|
ptr++; |
||||
|
} else if (*ptr != 0) { |
||||
|
break; |
||||
|
} |
||||
|
filter_whitelist.insert(l); |
||||
|
} |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case '?': { |
||||
|
showHelp = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (filter_whitelist.empty()) { |
||||
|
filter_whitelist.insert(1); |
||||
|
filter_whitelist.insert(5); |
||||
|
filter_whitelist.insert(9); |
||||
|
filter_whitelist.insert(13); |
||||
|
} |
||||
|
if (host != NULL && ns == NULL) showHelp = true; |
||||
|
if (showHelp) fprintf(stderr, help, argv[0]); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
extern "C" { |
||||
|
#include "dns.h" |
||||
|
} |
||||
|
|
||||
|
CAddrDb db; |
||||
|
|
||||
|
extern "C" void* ThreadCrawler(void* data) { |
||||
|
int *nThreads=(int*)data; |
||||
|
do { |
||||
|
std::vector<CServiceResult> ips; |
||||
|
int wait = 5; |
||||
|
db.GetMany(ips, 16, wait); |
||||
|
int64 now = time(NULL); |
||||
|
if (ips.empty()) { |
||||
|
wait *= 1000; |
||||
|
wait += rand() % (500 * *nThreads); |
||||
|
Sleep(wait); |
||||
|
continue; |
||||
|
} |
||||
|
vector<CAddress> addr; |
||||
|
for (int i=0; i<ips.size(); i++) { |
||||
|
CServiceResult &res = ips[i]; |
||||
|
res.nBanTime = 0; |
||||
|
res.nClientV = 0; |
||||
|
res.nHeight = 0; |
||||
|
res.strClientV = ""; |
||||
|
bool getaddr = res.ourLastSuccess + 86400 < now; |
||||
|
res.fGood = TestNode(res.service,res.nBanTime,res.nClientV,res.strClientV,res.nHeight,getaddr ? &addr : NULL); |
||||
|
} |
||||
|
db.ResultMany(ips); |
||||
|
db.Add(addr); |
||||
|
} while(1); |
||||
|
} |
||||
|
|
||||
|
extern "C" int GetIPList(void *thread, char *requestedHostname, addr_t *addr, int max, int ipv4, int ipv6); |
||||
|
|
||||
|
class CDnsThread { |
||||
|
public: |
||||
|
dns_opt_t dns_opt; // must be first
|
||||
|
const int id; |
||||
|
std::map<uint64_t, vector<addr_t> > cache; |
||||
|
int nIPv4, nIPv6; |
||||
|
std::map<uint64_t, time_t> cacheTime; |
||||
|
unsigned int cacheHits; |
||||
|
uint64_t dbQueries; |
||||
|
std::set<uint64_t> filterWhitelist; |
||||
|
|
||||
|
void cacheHit(uint64_t requestedFlags, bool force = false) { |
||||
|
static bool nets[NET_MAX] = {}; |
||||
|
if (!nets[NET_IPV4]) { |
||||
|
nets[NET_IPV4] = true; |
||||
|
nets[NET_IPV6] = true; |
||||
|
} |
||||
|
time_t now = time(NULL); |
||||
|
cacheHits++; |
||||
|
if (force || cacheHits > (cache[requestedFlags].size()*cache[requestedFlags].size()/400) || (cacheHits*cacheHits > cache[requestedFlags].size() / 20 && (now - cacheTime[requestedFlags] > 5))) { |
||||
|
set<CNetAddr> ips; |
||||
|
db.GetIPs(ips, requestedFlags, 1000, nets); |
||||
|
dbQueries++; |
||||
|
cache[requestedFlags].clear(); |
||||
|
nIPv4 = 0; |
||||
|
nIPv6 = 0; |
||||
|
cache[requestedFlags].reserve(ips.size()); |
||||
|
for (set<CNetAddr>::iterator it = ips.begin(); it != ips.end(); it++) { |
||||
|
struct in_addr addr; |
||||
|
struct in6_addr addr6; |
||||
|
if ((*it).GetInAddr(&addr)) { |
||||
|
addr_t a; |
||||
|
a.v = 4; |
||||
|
memcpy(&a.data.v4, &addr, 4); |
||||
|
cache[requestedFlags].push_back(a); |
||||
|
nIPv4++; |
||||
|
} else if ((*it).GetIn6Addr(&addr6)) { |
||||
|
addr_t a; |
||||
|
a.v = 6; |
||||
|
memcpy(&a.data.v6, &addr6, 16); |
||||
|
cache[requestedFlags].push_back(a); |
||||
|
nIPv6++; |
||||
|
} |
||||
|
} |
||||
|
cacheHits = 0; |
||||
|
cacheTime[requestedFlags] = now; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
CDnsThread(CDnsSeedOpts* opts, int idIn) : id(idIn) { |
||||
|
dns_opt.host = opts->host; |
||||
|
dns_opt.ns = opts->ns; |
||||
|
dns_opt.mbox = opts->mbox; |
||||
|
dns_opt.datattl = 3600; |
||||
|
dns_opt.nsttl = 40000; |
||||
|
dns_opt.cb = GetIPList; |
||||
|
dns_opt.port = opts->nPort; |
||||
|
dns_opt.nRequests = 0; |
||||
|
cache.clear(); |
||||
|
cacheTime.clear(); |
||||
|
cacheHits = 0; |
||||
|
dbQueries = 0; |
||||
|
nIPv4 = 0; |
||||
|
nIPv6 = 0; |
||||
|
filterWhitelist = opts->filter_whitelist; |
||||
|
} |
||||
|
|
||||
|
void run() { |
||||
|
dnsserver(&dns_opt); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
extern "C" int GetIPList(void *data, char *requestedHostname, addr_t* addr, int max, int ipv4, int ipv6) { |
||||
|
CDnsThread *thread = (CDnsThread*)data; |
||||
|
|
||||
|
uint64_t requestedFlags = 0; |
||||
|
int hostlen = strlen(requestedHostname); |
||||
|
if (hostlen > 1 && requestedHostname[0] == 'x' && requestedHostname[1] != '0') { |
||||
|
char *pEnd; |
||||
|
uint64_t flags = (uint64_t)strtoull(requestedHostname+1, &pEnd, 16); |
||||
|
if (*pEnd == '.' && pEnd <= requestedHostname+17 && std::find(thread->filterWhitelist.begin(), thread->filterWhitelist.end(), flags) != thread->filterWhitelist.end()) |
||||
|
requestedFlags = flags; |
||||
|
else |
||||
|
return 0; |
||||
|
} |
||||
|
else if (strcasecmp(requestedHostname, thread->dns_opt.host)) |
||||
|
return 0; |
||||
|
thread->cacheHit(requestedFlags); |
||||
|
unsigned int size = thread->cache[requestedFlags].size(); |
||||
|
unsigned int maxmax = (ipv4 ? thread->nIPv4 : 0) + (ipv6 ? thread->nIPv6 : 0); |
||||
|
if (max > size) |
||||
|
max = size; |
||||
|
if (max > maxmax) |
||||
|
max = maxmax; |
||||
|
int i=0; |
||||
|
while (i<max) { |
||||
|
int j = i + (rand() % (size - i)); |
||||
|
do { |
||||
|
bool ok = (ipv4 && thread->cache[requestedFlags][j].v == 4) || |
||||
|
(ipv6 && thread->cache[requestedFlags][j].v == 6); |
||||
|
if (ok) break; |
||||
|
j++; |
||||
|
if (j==size) |
||||
|
j=i; |
||||
|
} while(1); |
||||
|
addr[i] = thread->cache[requestedFlags][j]; |
||||
|
thread->cache[requestedFlags][j] = thread->cache[requestedFlags][i]; |
||||
|
thread->cache[requestedFlags][i] = addr[i]; |
||||
|
i++; |
||||
|
} |
||||
|
return max; |
||||
|
} |
||||
|
|
||||
|
vector<CDnsThread*> dnsThread; |
||||
|
|
||||
|
extern "C" void* ThreadDNS(void* arg) { |
||||
|
CDnsThread *thread = (CDnsThread*)arg; |
||||
|
thread->run(); |
||||
|
} |
||||
|
|
||||
|
int StatCompare(const CAddrReport& a, const CAddrReport& b) { |
||||
|
if (a.uptime[4] == b.uptime[4]) { |
||||
|
if (a.uptime[3] == b.uptime[3]) { |
||||
|
return a.clientVersion > b.clientVersion; |
||||
|
} else { |
||||
|
return a.uptime[3] > b.uptime[3]; |
||||
|
} |
||||
|
} else { |
||||
|
return a.uptime[4] > b.uptime[4]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
extern "C" void* ThreadDumper(void*) { |
||||
|
int count = 0; |
||||
|
do { |
||||
|
Sleep(100000 << count); // First 100s, than 200s, 400s, 800s, 1600s, and then 3200s forever
|
||||
|
if (count < 5) |
||||
|
count++; |
||||
|
{ |
||||
|
vector<CAddrReport> v = db.GetAll(); |
||||
|
sort(v.begin(), v.end(), StatCompare); |
||||
|
FILE *f = fopen("dnsseed.dat.new","w+"); |
||||
|
if (f) { |
||||
|
{ |
||||
|
CAutoFile cf(f); |
||||
|
cf << db; |
||||
|
} |
||||
|
rename("dnsseed.dat.new", "dnsseed.dat"); |
||||
|
} |
||||
|
FILE *d = fopen("dnsseed.dump", "w"); |
||||
|
fprintf(d, "# address good lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) %%(30d) blocks svcs version\n"); |
||||
|
double stat[5]={0,0,0,0,0}; |
||||
|
for (vector<CAddrReport>::const_iterator it = v.begin(); it < v.end(); it++) { |
||||
|
CAddrReport rep = *it; |
||||
|
fprintf(d, "%-47s %4d %11"PRId64" %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08"PRIx64" %5i \"%s\"\n", rep.ip.ToString().c_str(), (int)rep.fGood, rep.lastSuccess, 100.0*rep.uptime[0], 100.0*rep.uptime[1], 100.0*rep.uptime[2], 100.0*rep.uptime[3], 100.0*rep.uptime[4], rep.blocks, rep.services, rep.clientVersion, rep.clientSubVersion.c_str()); |
||||
|
stat[0] += rep.uptime[0]; |
||||
|
stat[1] += rep.uptime[1]; |
||||
|
stat[2] += rep.uptime[2]; |
||||
|
stat[3] += rep.uptime[3]; |
||||
|
stat[4] += rep.uptime[4]; |
||||
|
} |
||||
|
fclose(d); |
||||
|
FILE *ff = fopen("dnsstats.log", "a"); |
||||
|
fprintf(ff, "%llu %g %g %g %g %g\n", (unsigned long long)(time(NULL)), stat[0], stat[1], stat[2], stat[3], stat[4]); |
||||
|
fclose(ff); |
||||
|
} |
||||
|
} while(1); |
||||
|
} |
||||
|
|
||||
|
extern "C" void* ThreadStats(void*) { |
||||
|
bool first = true; |
||||
|
do { |
||||
|
char c[256]; |
||||
|
time_t tim = time(NULL); |
||||
|
struct tm *tmp = localtime(&tim); |
||||
|
strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp); |
||||
|
CAddrDbStats stats; |
||||
|
db.GetStats(stats); |
||||
|
if (first) |
||||
|
{ |
||||
|
first = false; |
||||
|
printf("\n\n\n\x1b[3A"); |
||||
|
} |
||||
|
else |
||||
|
printf("\x1b[2K\x1b[u"); |
||||
|
printf("\x1b[s"); |
||||
|
uint64_t requests = 0; |
||||
|
uint64_t queries = 0; |
||||
|
for (unsigned int i=0; i<dnsThread.size(); i++) { |
||||
|
requests += dnsThread[i]->dns_opt.nRequests; |
||||
|
queries += dnsThread[i]->dbQueries; |
||||
|
} |
||||
|
printf("%s %i/%i available (%i tried in %is, %i new, %i active), %i banned; %llu DNS requests, %llu db queries", c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, stats.nBanned, (unsigned long long)requests, (unsigned long long)queries); |
||||
|
Sleep(1000); |
||||
|
} while(1); |
||||
|
} |
||||
|
|
||||
|
static const string mainnet_seeds[] = {"mainnet.myhush.org", "us.madmining.club", ""}; |
||||
|
static const string testnet_seeds[] = {"testnet.myhush.org", ""}; |
||||
|
static const string *seeds = mainnet_seeds; |
||||
|
|
||||
|
extern "C" void* ThreadSeeder(void*) { |
||||
|
//if (!fTestNet){
|
||||
|
// db.Add(CService("kjy2eqzk4zwi5zd3.onion", 8333), true);
|
||||
|
//}
|
||||
|
do { |
||||
|
for (int i=0; seeds[i] != ""; i++) { |
||||
|
vector<CNetAddr> ips; |
||||
|
LookupHost(seeds[i].c_str(), ips); |
||||
|
for (vector<CNetAddr>::iterator it = ips.begin(); it != ips.end(); it++) { |
||||
|
db.Add(CService(*it, GetDefaultPort()), true); |
||||
|
} |
||||
|
} |
||||
|
Sleep(1800000); |
||||
|
} while(1); |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char **argv) { |
||||
|
signal(SIGPIPE, SIG_IGN); |
||||
|
setbuf(stdout, NULL); |
||||
|
CDnsSeedOpts opts; |
||||
|
opts.ParseCommandLine(argc, argv); |
||||
|
printf("Supporting whitelisted filters: "); |
||||
|
for (std::set<uint64_t>::const_iterator it = opts.filter_whitelist.begin(); it != opts.filter_whitelist.end(); it++) { |
||||
|
if (it != opts.filter_whitelist.begin()) { |
||||
|
printf(","); |
||||
|
} |
||||
|
printf("0x%lx", (unsigned long)*it); |
||||
|
} |
||||
|
printf("\n"); |
||||
|
if (opts.tor) { |
||||
|
CService service(opts.tor, 9050); |
||||
|
if (service.IsValid()) { |
||||
|
printf("Using Tor proxy at %s\n", service.ToStringIPPort().c_str()); |
||||
|
SetProxy(NET_TOR, service); |
||||
|
} |
||||
|
} |
||||
|
if (opts.ipv4_proxy) { |
||||
|
CService service(opts.ipv4_proxy, 9050); |
||||
|
if (service.IsValid()) { |
||||
|
printf("Using IPv4 proxy at %s\n", service.ToStringIPPort().c_str()); |
||||
|
SetProxy(NET_IPV4, service); |
||||
|
} |
||||
|
} |
||||
|
if (opts.ipv6_proxy) { |
||||
|
CService service(opts.ipv6_proxy, 9050); |
||||
|
if (service.IsValid()) { |
||||
|
printf("Using IPv6 proxy at %s\n", service.ToStringIPPort().c_str()); |
||||
|
SetProxy(NET_IPV6, service); |
||||
|
} |
||||
|
} |
||||
|
bool fDNS = true; |
||||
|
if (opts.fUseTestNet) { |
||||
|
printf("Using testnet.\n"); |
||||
|
pchMessageStart[0] = 0xFA; |
||||
|
pchMessageStart[1] = 0x1A; |
||||
|
pchMessageStart[2] = 0x24; |
||||
|
pchMessageStart[3] = 0xB6; |
||||
|
seeds = testnet_seeds; |
||||
|
fTestNet = true; |
||||
|
} |
||||
|
if (!opts.ns) { |
||||
|
printf("No nameserver set. Not starting DNS server.\n"); |
||||
|
fDNS = false; |
||||
|
} |
||||
|
if (fDNS && !opts.host) { |
||||
|
fprintf(stderr, "No hostname set. Please use -h.\n"); |
||||
|
exit(1); |
||||
|
} |
||||
|
if (fDNS && !opts.mbox) { |
||||
|
fprintf(stderr, "No e-mail address set. Please use -m.\n"); |
||||
|
exit(1); |
||||
|
} |
||||
|
FILE *f = fopen("dnsseed.dat","r"); |
||||
|
if (f) { |
||||
|
printf("Loading dnsseed.dat..."); |
||||
|
CAutoFile cf(f); |
||||
|
cf >> db; |
||||
|
if (opts.fWipeBan) |
||||
|
db.banned.clear(); |
||||
|
if (opts.fWipeIgnore) |
||||
|
db.ResetIgnores(); |
||||
|
printf("done\n"); |
||||
|
} |
||||
|
pthread_t threadDns, threadSeed, threadDump, threadStats; |
||||
|
if (fDNS) { |
||||
|
printf("Starting %i DNS threads for %s on %s (port %i)...", opts.nDnsThreads, opts.host, opts.ns, opts.nPort); |
||||
|
dnsThread.clear(); |
||||
|
for (int i=0; i<opts.nDnsThreads; i++) { |
||||
|
dnsThread.push_back(new CDnsThread(&opts, i)); |
||||
|
pthread_create(&threadDns, NULL, ThreadDNS, dnsThread[i]); |
||||
|
printf("."); |
||||
|
Sleep(20); |
||||
|
} |
||||
|
printf("done\n"); |
||||
|
} |
||||
|
printf("Starting seeder..."); |
||||
|
pthread_create(&threadSeed, NULL, ThreadSeeder, NULL); |
||||
|
printf("done\n"); |
||||
|
printf("Starting %i crawler threads...", opts.nThreads); |
||||
|
pthread_attr_t attr_crawler; |
||||
|
pthread_attr_init(&attr_crawler); |
||||
|
pthread_attr_setstacksize(&attr_crawler, 0x20000); |
||||
|
for (int i=0; i<opts.nThreads; i++) { |
||||
|
pthread_t thread; |
||||
|
pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads); |
||||
|
} |
||||
|
pthread_attr_destroy(&attr_crawler); |
||||
|
printf("done\n"); |
||||
|
pthread_create(&threadStats, NULL, ThreadStats, NULL); |
||||
|
pthread_create(&threadDump, NULL, ThreadDumper, NULL); |
||||
|
void* res; |
||||
|
pthread_join(threadDump, &res); |
||||
|
return 0; |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,148 @@ |
|||||
|
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
#ifndef BITCOIN_NETBASE_H |
||||
|
#define BITCOIN_NETBASE_H |
||||
|
|
||||
|
#include <string> |
||||
|
#include <vector> |
||||
|
|
||||
|
#include "serialize.h" |
||||
|
#include "compat.h" |
||||
|
|
||||
|
extern int nConnectTimeout; |
||||
|
|
||||
|
#ifdef WIN32 |
||||
|
// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error
|
||||
|
#undef SetPort |
||||
|
#endif |
||||
|
|
||||
|
enum Network |
||||
|
{ |
||||
|
NET_UNROUTABLE, |
||||
|
NET_IPV4, |
||||
|
NET_IPV6, |
||||
|
NET_TOR, |
||||
|
NET_I2P, |
||||
|
|
||||
|
NET_MAX, |
||||
|
}; |
||||
|
|
||||
|
extern int nConnectTimeout; |
||||
|
extern bool fNameLookup; |
||||
|
|
||||
|
/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ |
||||
|
class CNetAddr |
||||
|
{ |
||||
|
protected: |
||||
|
unsigned char 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 SetSpecial(const std::string &strName); // for Tor and I2P addresses
|
||||
|
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
|
||||
|
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/I2P)
|
||||
|
bool IsReserved() const; // Against Hetzners Abusal/Netscan Bot
|
||||
|
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 tunnelling (2002::/16)
|
||||
|
bool IsRFC4193() const; // IPv6 unique local (FC00::/15)
|
||||
|
bool IsRFC4380() const; // IPv6 Teredo tunnelling (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 IsTor() const; |
||||
|
bool IsI2P() const; |
||||
|
bool IsLocal() const; |
||||
|
bool IsRoutable() const; |
||||
|
bool IsValid() const; |
||||
|
bool IsMulticast() const; |
||||
|
enum Network GetNetwork() const; |
||||
|
std::string ToString() const; |
||||
|
std::string ToStringIP() const; |
||||
|
unsigned int GetByte(int n) const; |
||||
|
uint64 GetHash() const; |
||||
|
bool GetInAddr(struct in_addr* pipv4Addr) const; |
||||
|
std::vector<unsigned char> GetGroup() const; |
||||
|
int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; |
||||
|
void print() const; |
||||
|
|
||||
|
CNetAddr(const struct in6_addr& pipv6Addr); |
||||
|
bool GetIn6Addr(struct in6_addr* pipv6Addr) const; |
||||
|
|
||||
|
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); |
||||
|
|
||||
|
IMPLEMENT_SERIALIZE |
||||
|
( |
||||
|
READWRITE(FLATDATA(ip)); |
||||
|
) |
||||
|
}; |
||||
|
|
||||
|
/** A combination of a network address (CNetAddr) and a (TCP) port */ |
||||
|
class CService : public CNetAddr |
||||
|
{ |
||||
|
protected: |
||||
|
unsigned short port; // host order
|
||||
|
|
||||
|
public: |
||||
|
CService(); |
||||
|
CService(const CNetAddr& ip, unsigned short port); |
||||
|
CService(const struct in_addr& ipv4Addr, unsigned short 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(unsigned short portIn); |
||||
|
unsigned short GetPort() const; |
||||
|
bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const; |
||||
|
bool SetSockAddr(const struct sockaddr* paddr); |
||||
|
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<unsigned char> GetKey() const; |
||||
|
std::string ToString() const; |
||||
|
std::string ToStringPort() const; |
||||
|
std::string ToStringIPPort() const; |
||||
|
void print() const; |
||||
|
|
||||
|
CService(const struct in6_addr& ipv6Addr, unsigned short port); |
||||
|
CService(const struct sockaddr_in6& addr); |
||||
|
|
||||
|
IMPLEMENT_SERIALIZE |
||||
|
( |
||||
|
CService* pthis = const_cast<CService*>(this); |
||||
|
READWRITE(FLATDATA(ip)); |
||||
|
unsigned short portN = htons(port); |
||||
|
READWRITE(portN); |
||||
|
if (fRead) |
||||
|
pthis->port = ntohs(portN); |
||||
|
) |
||||
|
}; |
||||
|
|
||||
|
enum Network ParseNetwork(std::string net); |
||||
|
void SplitHostPort(std::string in, int &portOut, std::string &hostOut); |
||||
|
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5); |
||||
|
bool GetProxy(enum Network net, CService &addrProxy); |
||||
|
bool IsProxy(const CNetAddr &addr); |
||||
|
bool SetNameProxy(CService addrProxy, int nSocksVersion = 5); |
||||
|
bool GetNameProxy(); |
||||
|
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); |
||||
|
bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0); |
||||
|
bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); |
||||
|
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0); |
||||
|
bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); |
||||
|
bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); |
||||
|
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); |
||||
|
|
||||
|
#endif |
@ -0,0 +1,159 @@ |
|||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
|
// Copyright (c) 2011 The Bitcoin developers
|
||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
|
||||
|
#include <vector> |
||||
|
#include <stdexcept> |
||||
|
|
||||
|
#include "protocol.h" |
||||
|
#include "util.h" |
||||
|
#include "netbase.h" |
||||
|
|
||||
|
|
||||
|
#ifndef WIN32 |
||||
|
# include <arpa/inet.h> |
||||
|
#endif |
||||
|
|
||||
|
static const char* ppszTypeName[] = |
||||
|
{ |
||||
|
"ERROR", |
||||
|
"tx", |
||||
|
"block", |
||||
|
}; |
||||
|
|
||||
|
unsigned char pchMessageStart[4] = { 0x24, 0xE9, 0x27, 0x64 }; |
||||
|
|
||||
|
CMessageHeader::CMessageHeader() |
||||
|
{ |
||||
|
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); |
||||
|
memset(pchCommand, 0, sizeof(pchCommand)); |
||||
|
pchCommand[1] = 1; |
||||
|
nMessageSize = -1; |
||||
|
nChecksum = 0; |
||||
|
} |
||||
|
|
||||
|
CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) |
||||
|
{ |
||||
|
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); |
||||
|
strncpy(pchCommand, pszCommand, COMMAND_SIZE); |
||||
|
nMessageSize = nMessageSizeIn; |
||||
|
nChecksum = 0; |
||||
|
} |
||||
|
|
||||
|
std::string CMessageHeader::GetCommand() const |
||||
|
{ |
||||
|
if (pchCommand[COMMAND_SIZE-1] == 0) |
||||
|
return std::string(pchCommand, pchCommand + strlen(pchCommand)); |
||||
|
else |
||||
|
return std::string(pchCommand, pchCommand + COMMAND_SIZE); |
||||
|
} |
||||
|
|
||||
|
bool CMessageHeader::IsValid() const |
||||
|
{ |
||||
|
// Check start string
|
||||
|
if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0) |
||||
|
return false; |
||||
|
|
||||
|
// Check the command string for errors
|
||||
|
for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++) |
||||
|
{ |
||||
|
if (*p1 == 0) |
||||
|
{ |
||||
|
// Must be all zeros after the first zero
|
||||
|
for (; p1 < pchCommand + COMMAND_SIZE; p1++) |
||||
|
if (*p1 != 0) |
||||
|
return false; |
||||
|
} |
||||
|
else if (*p1 < ' ' || *p1 > 0x7E) |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// Message size
|
||||
|
if (nMessageSize > MAX_SIZE) |
||||
|
{ |
||||
|
printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
CAddress::CAddress() : CService() |
||||
|
{ |
||||
|
Init(); |
||||
|
} |
||||
|
|
||||
|
CAddress::CAddress(CService ipIn, uint64 nServicesIn) : CService(ipIn) |
||||
|
{ |
||||
|
Init(); |
||||
|
nServices = nServicesIn; |
||||
|
} |
||||
|
|
||||
|
void CAddress::Init() |
||||
|
{ |
||||
|
nServices = NODE_NETWORK; |
||||
|
nTime = 100000000; |
||||
|
} |
||||
|
|
||||
|
void CAddress::print() const |
||||
|
{ |
||||
|
printf("CAddress(%s)\n", ToString().c_str()); |
||||
|
} |
||||
|
|
||||
|
CInv::CInv() |
||||
|
{ |
||||
|
type = 0; |
||||
|
hash = 0; |
||||
|
} |
||||
|
|
||||
|
CInv::CInv(int typeIn, const uint256& hashIn) |
||||
|
{ |
||||
|
type = typeIn; |
||||
|
hash = hashIn; |
||||
|
} |
||||
|
|
||||
|
CInv::CInv(const std::string& strType, const uint256& hashIn) |
||||
|
{ |
||||
|
int i; |
||||
|
for (i = 1; i < ARRAYLEN(ppszTypeName); i++) |
||||
|
{ |
||||
|
if (strType == ppszTypeName[i]) |
||||
|
{ |
||||
|
type = i; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
if (i == ARRAYLEN(ppszTypeName)) |
||||
|
throw std::out_of_range("CInv::CInv(string, uint256) : unknown type"); |
||||
|
hash = hashIn; |
||||
|
} |
||||
|
|
||||
|
bool operator<(const CInv& a, const CInv& b) |
||||
|
{ |
||||
|
return (a.type < b.type || (a.type == b.type && a.hash < b.hash)); |
||||
|
} |
||||
|
|
||||
|
bool CInv::IsKnownType() const |
||||
|
{ |
||||
|
return (type >= 1 && type < ARRAYLEN(ppszTypeName)); |
||||
|
} |
||||
|
|
||||
|
const char* CInv::GetCommand() const |
||||
|
{ |
||||
|
if (!IsKnownType()) |
||||
|
throw std::out_of_range("CInv::GetCommand() : unknown type"); |
||||
|
return ppszTypeName[type]; |
||||
|
} |
||||
|
|
||||
|
std::string CInv::ToString() const |
||||
|
{ |
||||
|
return "CInv()"; |
||||
|
} |
||||
|
|
||||
|
void CInv::print() const |
||||
|
{ |
||||
|
printf("CInv\n"); |
||||
|
} |
@ -0,0 +1,123 @@ |
|||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
|
// Copyright (c) 2011 The Bitcoin developers
|
||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
|
||||
|
#ifndef __cplusplus |
||||
|
# error This header can only be compiled as C++. |
||||
|
#endif |
||||
|
|
||||
|
#ifndef __INCLUDED_PROTOCOL_H__ |
||||
|
#define __INCLUDED_PROTOCOL_H__ |
||||
|
|
||||
|
#include "netbase.h" |
||||
|
#include "serialize.h" |
||||
|
#include <string> |
||||
|
#include "uint256.h" |
||||
|
|
||||
|
extern bool fTestNet; |
||||
|
static inline unsigned short GetDefaultPort(const bool testnet = fTestNet) |
||||
|
{ |
||||
|
return testnet ? 18888 : 8888; |
||||
|
} |
||||
|
|
||||
|
//
|
||||
|
// Message header
|
||||
|
// (4) message start
|
||||
|
// (12) command
|
||||
|
// (4) size
|
||||
|
// (4) checksum
|
||||
|
|
||||
|
extern unsigned char pchMessageStart[4]; |
||||
|
|
||||
|
class CMessageHeader |
||||
|
{ |
||||
|
public: |
||||
|
CMessageHeader(); |
||||
|
CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn); |
||||
|
|
||||
|
std::string GetCommand() const; |
||||
|
bool IsValid() const; |
||||
|
|
||||
|
IMPLEMENT_SERIALIZE |
||||
|
( |
||||
|
READWRITE(FLATDATA(pchMessageStart)); |
||||
|
READWRITE(FLATDATA(pchCommand)); |
||||
|
READWRITE(nMessageSize); |
||||
|
if (nVersion >= 209) |
||||
|
READWRITE(nChecksum); |
||||
|
) |
||||
|
|
||||
|
// TODO: make private (improves encapsulation)
|
||||
|
public: |
||||
|
enum { COMMAND_SIZE=12 }; |
||||
|
char pchMessageStart[sizeof(::pchMessageStart)]; |
||||
|
char pchCommand[COMMAND_SIZE]; |
||||
|
unsigned int nMessageSize; |
||||
|
unsigned int nChecksum; |
||||
|
}; |
||||
|
|
||||
|
enum |
||||
|
{ |
||||
|
NODE_NETWORK = (1 << 0), |
||||
|
}; |
||||
|
|
||||
|
class CAddress : public CService |
||||
|
{ |
||||
|
public: |
||||
|
CAddress(); |
||||
|
CAddress(CService ipIn, uint64 nServicesIn=NODE_NETWORK); |
||||
|
|
||||
|
void Init(); |
||||
|
|
||||
|
IMPLEMENT_SERIALIZE |
||||
|
( |
||||
|
CAddress* pthis = const_cast<CAddress*>(this); |
||||
|
CService* pip = (CService*)pthis; |
||||
|
if (fRead) |
||||
|
pthis->Init(); |
||||
|
if (nType & SER_DISK) |
||||
|
READWRITE(nVersion); |
||||
|
if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH))) |
||||
|
READWRITE(nTime); |
||||
|
READWRITE(nServices); |
||||
|
READWRITE(*pip); |
||||
|
) |
||||
|
|
||||
|
void print() const; |
||||
|
|
||||
|
// TODO: make private (improves encapsulation)
|
||||
|
public: |
||||
|
uint64 nServices; |
||||
|
|
||||
|
// disk and network only
|
||||
|
unsigned int nTime; |
||||
|
}; |
||||
|
|
||||
|
class CInv |
||||
|
{ |
||||
|
public: |
||||
|
CInv(); |
||||
|
CInv(int typeIn, const uint256& hashIn); |
||||
|
CInv(const std::string& strType, const uint256& hashIn); |
||||
|
|
||||
|
IMPLEMENT_SERIALIZE |
||||
|
( |
||||
|
READWRITE(type); |
||||
|
READWRITE(hash); |
||||
|
) |
||||
|
|
||||
|
friend bool operator<(const CInv& a, const CInv& b); |
||||
|
|
||||
|
bool IsKnownType() const; |
||||
|
const char* GetCommand() const; |
||||
|
std::string ToString() const; |
||||
|
void print() const; |
||||
|
|
||||
|
// TODO: make private (improves encapsulation)
|
||||
|
public: |
||||
|
int type; |
||||
|
uint256 hash; |
||||
|
}; |
||||
|
|
||||
|
#endif // __INCLUDED_PROTOCOL_H__
|
File diff suppressed because it is too large
@ -0,0 +1,90 @@ |
|||||
|
/*
|
||||
|
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
||||
|
* |
||||
|
* Permission to use, copy, modify, and distribute this software for any |
||||
|
* purpose with or without fee is hereby granted, provided that the above |
||||
|
* copyright notice and this permission notice appear in all copies. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
#ifndef BITCOIN_STRLCPY_H |
||||
|
#define BITCOIN_STRLCPY_H |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/*
|
||||
|
* Copy src to string dst of size siz. At most siz-1 characters |
||||
|
* will be copied. Always NUL terminates (unless siz == 0). |
||||
|
* Returns strlen(src); if retval >= siz, truncation occurred. |
||||
|
*/ |
||||
|
inline size_t strlcpy(char *dst, const char *src, size_t siz) |
||||
|
{ |
||||
|
char *d = dst; |
||||
|
const char *s = src; |
||||
|
size_t n = siz; |
||||
|
|
||||
|
/* Copy as many bytes as will fit */ |
||||
|
if (n != 0) |
||||
|
{ |
||||
|
while (--n != 0) |
||||
|
{ |
||||
|
if ((*d++ = *s++) == '\0') |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Not enough room in dst, add NUL and traverse rest of src */ |
||||
|
if (n == 0) |
||||
|
{ |
||||
|
if (siz != 0) |
||||
|
*d = '\0'; /* NUL-terminate dst */ |
||||
|
while (*s++) |
||||
|
; |
||||
|
} |
||||
|
|
||||
|
return(s - src - 1); /* count does not include NUL */ |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
* Appends src to string dst of size siz (unlike strncat, siz is the |
||||
|
* full size of dst, not space left). At most siz-1 characters |
||||
|
* will be copied. Always NUL terminates (unless siz <= strlen(dst)). |
||||
|
* Returns strlen(src) + MIN(siz, strlen(initial dst)). |
||||
|
* If retval >= siz, truncation occurred. |
||||
|
*/ |
||||
|
inline size_t strlcat(char *dst, const char *src, size_t siz) |
||||
|
{ |
||||
|
char *d = dst; |
||||
|
const char *s = src; |
||||
|
size_t n = siz; |
||||
|
size_t dlen; |
||||
|
|
||||
|
/* Find the end of dst and adjust bytes left but don't go past end */ |
||||
|
while (n-- != 0 && *d != '\0') |
||||
|
d++; |
||||
|
dlen = d - dst; |
||||
|
n = siz - dlen; |
||||
|
|
||||
|
if (n == 0) |
||||
|
return(dlen + strlen(s)); |
||||
|
while (*s != '\0') |
||||
|
{ |
||||
|
if (n != 1) |
||||
|
{ |
||||
|
*d++ = *s; |
||||
|
n--; |
||||
|
} |
||||
|
s++; |
||||
|
} |
||||
|
*d = '\0'; |
||||
|
|
||||
|
return(dlen + (s - src)); /* count does not include NUL */ |
||||
|
} |
||||
|
#endif |
@ -0,0 +1,68 @@ |
|||||
|
#!/usr/bin/perl |
||||
|
|
||||
|
use warnings FATAL => 'all'; |
||||
|
use threads; |
||||
|
use threads::shared; |
||||
|
use bytes; |
||||
|
use IO::Socket; |
||||
|
use strict; |
||||
|
|
||||
|
my @dom = ("seed","bitcoin","sipa","be"); |
||||
|
|
||||
|
my $run :shared = 1; |
||||
|
|
||||
|
sub go { |
||||
|
my ($idx) = @_; |
||||
|
|
||||
|
my $runs = 0; |
||||
|
|
||||
|
my $sock = IO::Socket::INET->new( |
||||
|
Proto => 'udp', |
||||
|
PeerPort => 53, |
||||
|
PeerAddr => "vps.sipa.be", |
||||
|
) or die "Could not create socket: $!\n"; |
||||
|
|
||||
|
while($run) { |
||||
|
|
||||
|
my $id = int(rand(65536)); |
||||
|
my $qr = 0; |
||||
|
my $opcode = 0; |
||||
|
my $aa = 0; |
||||
|
my $tc = 0; |
||||
|
my $rd = 0; |
||||
|
my $ra = 0; |
||||
|
my $z = 0; |
||||
|
my $rcode = 0; |
||||
|
my $qdcount = 1; |
||||
|
my $ancount = 0; |
||||
|
my $nscount = 0; |
||||
|
my $arcount = 0; |
||||
|
my $header = pack('nnnnnn',$id,1*$qr + 2*$opcode + 32*$aa + 64*$tc + 128*$rd + 256*$ra + 512*$z + 4096*$rcode, $qdcount, $ancount, $nscount, $arcount); |
||||
|
my $qtype = 1; # A record |
||||
|
my $qclass = 1; # IN class |
||||
|
my $query = (join("", map { chr(length($_)) . $_ } (@dom,""))) . pack('nn',$qtype,$qclass); |
||||
|
my $msg = $header . $query; |
||||
|
$sock->send($msg); |
||||
|
my $resp; |
||||
|
$runs++ if ($sock->recv($resp, 512, 0)); |
||||
|
|
||||
|
# $sock->close(); |
||||
|
} |
||||
|
return $runs; |
||||
|
} |
||||
|
|
||||
|
my @threads; |
||||
|
|
||||
|
for my $i (0..500) { |
||||
|
$threads[$i] = threads->create(\&go, $i); |
||||
|
} |
||||
|
|
||||
|
sleep 10; |
||||
|
|
||||
|
$run=0; |
||||
|
my $runs = 0; |
||||
|
foreach my $thr (@threads) { |
||||
|
$runs += $thr->join(); |
||||
|
} |
||||
|
|
||||
|
print "$runs runs\n"; |
@ -0,0 +1,766 @@ |
|||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
|
// Copyright (c) 2011 The Bitcoin developers
|
||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
#ifndef BITCOIN_UINT256_H |
||||
|
#define BITCOIN_UINT256_H |
||||
|
|
||||
|
#include "serialize.h" |
||||
|
|
||||
|
#include <limits.h> |
||||
|
#include <string> |
||||
|
#include <vector> |
||||
|
|
||||
|
#if defined(_MSC_VER) || defined(__BORLANDC__) |
||||
|
typedef __int64 int64; |
||||
|
typedef unsigned __int64 uint64; |
||||
|
#else |
||||
|
typedef long long int64; |
||||
|
typedef unsigned long long uint64; |
||||
|
#endif |
||||
|
#if defined(_MSC_VER) && _MSC_VER < 1300 |
||||
|
#define for if (false) ; else for |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
inline int Testuint256AdHoc(std::vector<std::string> vArg); |
||||
|
|
||||
|
|
||||
|
|
||||
|
// We have to keep a separate base class without constructors
|
||||
|
// so the compiler will let us use it in a union
|
||||
|
template<unsigned int BITS> |
||||
|
class base_uint |
||||
|
{ |
||||
|
protected: |
||||
|
enum { WIDTH=BITS/32 }; |
||||
|
unsigned int pn[WIDTH]; |
||||
|
public: |
||||
|
|
||||
|
bool operator!() const |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
if (pn[i] != 0) |
||||
|
return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
const base_uint operator~() const |
||||
|
{ |
||||
|
base_uint ret; |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
ret.pn[i] = ~pn[i]; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
const base_uint operator-() const |
||||
|
{ |
||||
|
base_uint ret; |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
ret.pn[i] = ~pn[i]; |
||||
|
ret++; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
base_uint& operator=(uint64 b) |
||||
|
{ |
||||
|
pn[0] = (unsigned int)b; |
||||
|
pn[1] = (unsigned int)(b >> 32); |
||||
|
for (int i = 2; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator^=(const base_uint& b) |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] ^= b.pn[i]; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator&=(const base_uint& b) |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] &= b.pn[i]; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator|=(const base_uint& b) |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] |= b.pn[i]; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator^=(uint64 b) |
||||
|
{ |
||||
|
pn[0] ^= (unsigned int)b; |
||||
|
pn[1] ^= (unsigned int)(b >> 32); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator&=(uint64 b) |
||||
|
{ |
||||
|
pn[0] &= (unsigned int)b; |
||||
|
pn[1] &= (unsigned int)(b >> 32); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator|=(uint64 b) |
||||
|
{ |
||||
|
pn[0] |= (unsigned int)b; |
||||
|
pn[1] |= (unsigned int)(b >> 32); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator<<=(unsigned int shift) |
||||
|
{ |
||||
|
base_uint a(*this); |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
int k = shift / 32; |
||||
|
shift = shift % 32; |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
{ |
||||
|
if (i+k+1 < WIDTH && shift != 0) |
||||
|
pn[i+k+1] |= (a.pn[i] >> (32-shift)); |
||||
|
if (i+k < WIDTH) |
||||
|
pn[i+k] |= (a.pn[i] << shift); |
||||
|
} |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator>>=(unsigned int shift) |
||||
|
{ |
||||
|
base_uint a(*this); |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
int k = shift / 32; |
||||
|
shift = shift % 32; |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
{ |
||||
|
if (i-k-1 >= 0 && shift != 0) |
||||
|
pn[i-k-1] |= (a.pn[i] << (32-shift)); |
||||
|
if (i-k >= 0) |
||||
|
pn[i-k] |= (a.pn[i] >> shift); |
||||
|
} |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator+=(const base_uint& b) |
||||
|
{ |
||||
|
uint64 carry = 0; |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
{ |
||||
|
uint64 n = carry + pn[i] + b.pn[i]; |
||||
|
pn[i] = n & 0xffffffff; |
||||
|
carry = n >> 32; |
||||
|
} |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator-=(const base_uint& b) |
||||
|
{ |
||||
|
*this += -b; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator+=(uint64 b64) |
||||
|
{ |
||||
|
base_uint b; |
||||
|
b = b64; |
||||
|
*this += b; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator-=(uint64 b64) |
||||
|
{ |
||||
|
base_uint b; |
||||
|
b = b64; |
||||
|
*this += -b; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
base_uint& operator++() |
||||
|
{ |
||||
|
// prefix operator
|
||||
|
int i = 0; |
||||
|
while (++pn[i] == 0 && i < WIDTH-1) |
||||
|
i++; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
const base_uint operator++(int) |
||||
|
{ |
||||
|
// postfix operator
|
||||
|
const base_uint ret = *this; |
||||
|
++(*this); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
base_uint& operator--() |
||||
|
{ |
||||
|
// prefix operator
|
||||
|
int i = 0; |
||||
|
while (--pn[i] == -1 && i < WIDTH-1) |
||||
|
i++; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
const base_uint operator--(int) |
||||
|
{ |
||||
|
// postfix operator
|
||||
|
const base_uint ret = *this; |
||||
|
--(*this); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
friend inline bool operator<(const base_uint& a, const base_uint& b) |
||||
|
{ |
||||
|
for (int i = base_uint::WIDTH-1; i >= 0; i--) |
||||
|
{ |
||||
|
if (a.pn[i] < b.pn[i]) |
||||
|
return true; |
||||
|
else if (a.pn[i] > b.pn[i]) |
||||
|
return false; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
friend inline bool operator<=(const base_uint& a, const base_uint& b) |
||||
|
{ |
||||
|
for (int i = base_uint::WIDTH-1; i >= 0; i--) |
||||
|
{ |
||||
|
if (a.pn[i] < b.pn[i]) |
||||
|
return true; |
||||
|
else if (a.pn[i] > b.pn[i]) |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
friend inline bool operator>(const base_uint& a, const base_uint& b) |
||||
|
{ |
||||
|
for (int i = base_uint::WIDTH-1; i >= 0; i--) |
||||
|
{ |
||||
|
if (a.pn[i] > b.pn[i]) |
||||
|
return true; |
||||
|
else if (a.pn[i] < b.pn[i]) |
||||
|
return false; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
friend inline bool operator>=(const base_uint& a, const base_uint& b) |
||||
|
{ |
||||
|
for (int i = base_uint::WIDTH-1; i >= 0; i--) |
||||
|
{ |
||||
|
if (a.pn[i] > b.pn[i]) |
||||
|
return true; |
||||
|
else if (a.pn[i] < b.pn[i]) |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
friend inline bool operator==(const base_uint& a, const base_uint& b) |
||||
|
{ |
||||
|
for (int i = 0; i < base_uint::WIDTH; i++) |
||||
|
if (a.pn[i] != b.pn[i]) |
||||
|
return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
friend inline bool operator==(const base_uint& a, uint64 b) |
||||
|
{ |
||||
|
if (a.pn[0] != (unsigned int)b) |
||||
|
return false; |
||||
|
if (a.pn[1] != (unsigned int)(b >> 32)) |
||||
|
return false; |
||||
|
for (int i = 2; i < base_uint::WIDTH; i++) |
||||
|
if (a.pn[i] != 0) |
||||
|
return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
friend inline bool operator!=(const base_uint& a, const base_uint& b) |
||||
|
{ |
||||
|
return (!(a == b)); |
||||
|
} |
||||
|
|
||||
|
friend inline bool operator!=(const base_uint& a, uint64 b) |
||||
|
{ |
||||
|
return (!(a == b)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
std::string GetHex() const |
||||
|
{ |
||||
|
char psz[sizeof(pn)*2 + 1]; |
||||
|
for (int i = 0; i < sizeof(pn); i++) |
||||
|
sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]); |
||||
|
return std::string(psz, psz + sizeof(pn)*2); |
||||
|
} |
||||
|
|
||||
|
void SetHex(const char* psz) |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
|
||||
|
// skip leading spaces
|
||||
|
while (isspace(*psz)) |
||||
|
psz++; |
||||
|
|
||||
|
// skip 0x
|
||||
|
if (psz[0] == '0' && tolower(psz[1]) == 'x') |
||||
|
psz += 2; |
||||
|
|
||||
|
// hex string to uint
|
||||
|
static 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[*psz] || *psz == '0') |
||||
|
psz++; |
||||
|
psz--; |
||||
|
unsigned char* p1 = (unsigned char*)pn; |
||||
|
unsigned char* pend = p1 + WIDTH * 4; |
||||
|
while (psz >= pbegin && p1 < pend) |
||||
|
{ |
||||
|
*p1 = phexdigit[(unsigned char)*psz--]; |
||||
|
if (psz >= pbegin) |
||||
|
{ |
||||
|
*p1 |= (phexdigit[(unsigned char)*psz--] << 4); |
||||
|
p1++; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void SetHex(const std::string& str) |
||||
|
{ |
||||
|
SetHex(str.c_str()); |
||||
|
} |
||||
|
|
||||
|
std::string ToString() const |
||||
|
{ |
||||
|
return (GetHex()); |
||||
|
} |
||||
|
|
||||
|
unsigned char* begin() |
||||
|
{ |
||||
|
return (unsigned char*)&pn[0]; |
||||
|
} |
||||
|
|
||||
|
unsigned char* end() |
||||
|
{ |
||||
|
return (unsigned char*)&pn[WIDTH]; |
||||
|
} |
||||
|
|
||||
|
unsigned int size() |
||||
|
{ |
||||
|
return sizeof(pn); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const |
||||
|
{ |
||||
|
return sizeof(pn); |
||||
|
} |
||||
|
|
||||
|
template<typename Stream> |
||||
|
void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const |
||||
|
{ |
||||
|
s.write((char*)pn, sizeof(pn)); |
||||
|
} |
||||
|
|
||||
|
template<typename Stream> |
||||
|
void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) |
||||
|
{ |
||||
|
s.read((char*)pn, sizeof(pn)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
friend class uint160; |
||||
|
friend class uint256; |
||||
|
friend inline int Testuint256AdHoc(std::vector<std::string> vArg); |
||||
|
}; |
||||
|
|
||||
|
typedef base_uint<160> base_uint160; |
||||
|
typedef base_uint<256> base_uint256; |
||||
|
|
||||
|
|
||||
|
|
||||
|
//
|
||||
|
// uint160 and uint256 could be implemented as templates, but to keep
|
||||
|
// compile errors and debugging cleaner, they're copy and pasted.
|
||||
|
//
|
||||
|
|
||||
|
|
||||
|
|
||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||
|
//
|
||||
|
// uint160
|
||||
|
//
|
||||
|
|
||||
|
class uint160 : public base_uint160 |
||||
|
{ |
||||
|
public: |
||||
|
typedef base_uint160 basetype; |
||||
|
|
||||
|
uint160() |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
} |
||||
|
|
||||
|
uint160(const basetype& b) |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] = b.pn[i]; |
||||
|
} |
||||
|
|
||||
|
uint160& operator=(const basetype& b) |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] = b.pn[i]; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
uint160(uint64 b) |
||||
|
{ |
||||
|
pn[0] = (unsigned int)b; |
||||
|
pn[1] = (unsigned int)(b >> 32); |
||||
|
for (int i = 2; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
} |
||||
|
|
||||
|
uint160& operator=(uint64 b) |
||||
|
{ |
||||
|
pn[0] = (unsigned int)b; |
||||
|
pn[1] = (unsigned int)(b >> 32); |
||||
|
for (int i = 2; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
explicit uint160(const std::string& str) |
||||
|
{ |
||||
|
SetHex(str); |
||||
|
} |
||||
|
|
||||
|
explicit uint160(const std::vector<unsigned char>& vch) |
||||
|
{ |
||||
|
if (vch.size() == sizeof(pn)) |
||||
|
memcpy(pn, &vch[0], sizeof(pn)); |
||||
|
else |
||||
|
*this = 0; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; } |
||||
|
inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; } |
||||
|
inline const uint160 operator<<(const base_uint160& a, unsigned int shift) { return uint160(a) <<= shift; } |
||||
|
inline const uint160 operator>>(const base_uint160& a, unsigned int shift) { return uint160(a) >>= shift; } |
||||
|
inline const uint160 operator<<(const uint160& a, unsigned int shift) { return uint160(a) <<= shift; } |
||||
|
inline const uint160 operator>>(const uint160& a, unsigned int shift) { return uint160(a) >>= shift; } |
||||
|
|
||||
|
inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } |
||||
|
inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } |
||||
|
inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } |
||||
|
inline const uint160 operator+(const base_uint160& a, const base_uint160& b) { return uint160(a) += b; } |
||||
|
inline const uint160 operator-(const base_uint160& a, const base_uint160& b) { return uint160(a) -= b; } |
||||
|
|
||||
|
inline bool operator<(const base_uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } |
||||
|
inline bool operator<=(const base_uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } |
||||
|
inline bool operator>(const base_uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } |
||||
|
inline bool operator>=(const base_uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } |
||||
|
inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } |
||||
|
inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } |
||||
|
inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } |
||||
|
inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } |
||||
|
inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } |
||||
|
inline const uint160 operator+(const base_uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } |
||||
|
inline const uint160 operator-(const base_uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } |
||||
|
|
||||
|
inline bool operator<(const uint160& a, const base_uint160& b) { return (base_uint160)a < (base_uint160)b; } |
||||
|
inline bool operator<=(const uint160& a, const base_uint160& b) { return (base_uint160)a <= (base_uint160)b; } |
||||
|
inline bool operator>(const uint160& a, const base_uint160& b) { return (base_uint160)a > (base_uint160)b; } |
||||
|
inline bool operator>=(const uint160& a, const base_uint160& b) { return (base_uint160)a >= (base_uint160)b; } |
||||
|
inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } |
||||
|
inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } |
||||
|
inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } |
||||
|
inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } |
||||
|
inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } |
||||
|
inline const uint160 operator+(const uint160& a, const base_uint160& b) { return (base_uint160)a + (base_uint160)b; } |
||||
|
inline const uint160 operator-(const uint160& a, const base_uint160& b) { return (base_uint160)a - (base_uint160)b; } |
||||
|
|
||||
|
inline bool operator<(const uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } |
||||
|
inline bool operator<=(const uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } |
||||
|
inline bool operator>(const uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } |
||||
|
inline bool operator>=(const uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } |
||||
|
inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } |
||||
|
inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } |
||||
|
inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } |
||||
|
inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } |
||||
|
inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } |
||||
|
inline const uint160 operator+(const uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } |
||||
|
inline const uint160 operator-(const uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||
|
//
|
||||
|
// uint256
|
||||
|
//
|
||||
|
|
||||
|
class uint256 : public base_uint256 |
||||
|
{ |
||||
|
public: |
||||
|
typedef base_uint256 basetype; |
||||
|
|
||||
|
uint256() |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
} |
||||
|
|
||||
|
uint256(const basetype& b) |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] = b.pn[i]; |
||||
|
} |
||||
|
|
||||
|
uint256& operator=(const basetype& b) |
||||
|
{ |
||||
|
for (int i = 0; i < WIDTH; i++) |
||||
|
pn[i] = b.pn[i]; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
uint256(uint64 b) |
||||
|
{ |
||||
|
pn[0] = (unsigned int)b; |
||||
|
pn[1] = (unsigned int)(b >> 32); |
||||
|
for (int i = 2; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
} |
||||
|
|
||||
|
uint256& operator=(uint64 b) |
||||
|
{ |
||||
|
pn[0] = (unsigned int)b; |
||||
|
pn[1] = (unsigned int)(b >> 32); |
||||
|
for (int i = 2; i < WIDTH; i++) |
||||
|
pn[i] = 0; |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
explicit uint256(const std::string& str) |
||||
|
{ |
||||
|
SetHex(str); |
||||
|
} |
||||
|
|
||||
|
explicit uint256(const std::vector<unsigned char>& vch) |
||||
|
{ |
||||
|
if (vch.size() == sizeof(pn)) |
||||
|
memcpy(pn, &vch[0], sizeof(pn)); |
||||
|
else |
||||
|
*this = 0; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
inline bool operator==(const uint256& a, uint64 b) { return (base_uint256)a == b; } |
||||
|
inline bool operator!=(const uint256& a, uint64 b) { return (base_uint256)a != b; } |
||||
|
inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; } |
||||
|
inline const uint256 operator>>(const base_uint256& a, unsigned int shift) { return uint256(a) >>= shift; } |
||||
|
inline const uint256 operator<<(const uint256& a, unsigned int shift) { return uint256(a) <<= shift; } |
||||
|
inline const uint256 operator>>(const uint256& a, unsigned int shift) { return uint256(a) >>= shift; } |
||||
|
|
||||
|
inline const uint256 operator^(const base_uint256& a, const base_uint256& b) { return uint256(a) ^= b; } |
||||
|
inline const uint256 operator&(const base_uint256& a, const base_uint256& b) { return uint256(a) &= b; } |
||||
|
inline const uint256 operator|(const base_uint256& a, const base_uint256& b) { return uint256(a) |= b; } |
||||
|
inline const uint256 operator+(const base_uint256& a, const base_uint256& b) { return uint256(a) += b; } |
||||
|
inline const uint256 operator-(const base_uint256& a, const base_uint256& b) { return uint256(a) -= b; } |
||||
|
|
||||
|
inline bool operator<(const base_uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } |
||||
|
inline bool operator<=(const base_uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } |
||||
|
inline bool operator>(const base_uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } |
||||
|
inline bool operator>=(const base_uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } |
||||
|
inline bool operator==(const base_uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } |
||||
|
inline bool operator!=(const base_uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } |
||||
|
inline const uint256 operator^(const base_uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } |
||||
|
inline const uint256 operator&(const base_uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } |
||||
|
inline const uint256 operator|(const base_uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } |
||||
|
inline const uint256 operator+(const base_uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } |
||||
|
inline const uint256 operator-(const base_uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } |
||||
|
|
||||
|
inline bool operator<(const uint256& a, const base_uint256& b) { return (base_uint256)a < (base_uint256)b; } |
||||
|
inline bool operator<=(const uint256& a, const base_uint256& b) { return (base_uint256)a <= (base_uint256)b; } |
||||
|
inline bool operator>(const uint256& a, const base_uint256& b) { return (base_uint256)a > (base_uint256)b; } |
||||
|
inline bool operator>=(const uint256& a, const base_uint256& b) { return (base_uint256)a >= (base_uint256)b; } |
||||
|
inline bool operator==(const uint256& a, const base_uint256& b) { return (base_uint256)a == (base_uint256)b; } |
||||
|
inline bool operator!=(const uint256& a, const base_uint256& b) { return (base_uint256)a != (base_uint256)b; } |
||||
|
inline const uint256 operator^(const uint256& a, const base_uint256& b) { return (base_uint256)a ^ (base_uint256)b; } |
||||
|
inline const uint256 operator&(const uint256& a, const base_uint256& b) { return (base_uint256)a & (base_uint256)b; } |
||||
|
inline const uint256 operator|(const uint256& a, const base_uint256& b) { return (base_uint256)a | (base_uint256)b; } |
||||
|
inline const uint256 operator+(const uint256& a, const base_uint256& b) { return (base_uint256)a + (base_uint256)b; } |
||||
|
inline const uint256 operator-(const uint256& a, const base_uint256& b) { return (base_uint256)a - (base_uint256)b; } |
||||
|
|
||||
|
inline bool operator<(const uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } |
||||
|
inline bool operator<=(const uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } |
||||
|
inline bool operator>(const uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } |
||||
|
inline bool operator>=(const uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } |
||||
|
inline bool operator==(const uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } |
||||
|
inline bool operator!=(const uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } |
||||
|
inline const uint256 operator^(const uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } |
||||
|
inline const uint256 operator&(const uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } |
||||
|
inline const uint256 operator|(const uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } |
||||
|
inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } |
||||
|
inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
inline int Testuint256AdHoc(std::vector<std::string> vArg) |
||||
|
{ |
||||
|
uint256 g(0); |
||||
|
|
||||
|
|
||||
|
printf("%s\n", g.ToString().c_str()); |
||||
|
g--; printf("g--\n"); |
||||
|
printf("%s\n", g.ToString().c_str()); |
||||
|
g--; printf("g--\n"); |
||||
|
printf("%s\n", g.ToString().c_str()); |
||||
|
g++; printf("g++\n"); |
||||
|
printf("%s\n", g.ToString().c_str()); |
||||
|
g++; printf("g++\n"); |
||||
|
printf("%s\n", g.ToString().c_str()); |
||||
|
g++; printf("g++\n"); |
||||
|
printf("%s\n", g.ToString().c_str()); |
||||
|
g++; printf("g++\n"); |
||||
|
printf("%s\n", g.ToString().c_str()); |
||||
|
|
||||
|
|
||||
|
|
||||
|
uint256 a(7); |
||||
|
printf("a=7\n"); |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
|
||||
|
uint256 b; |
||||
|
printf("b undefined\n"); |
||||
|
printf("%s\n", b.ToString().c_str()); |
||||
|
int c = 3; |
||||
|
|
||||
|
a = c; |
||||
|
a.pn[3] = 15; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
uint256 k(c); |
||||
|
|
||||
|
a = 5; |
||||
|
a.pn[3] = 15; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
b = 1; |
||||
|
b <<= 52; |
||||
|
|
||||
|
a |= b; |
||||
|
|
||||
|
a ^= 0x500; |
||||
|
|
||||
|
printf("a %s\n", a.ToString().c_str()); |
||||
|
|
||||
|
a = a | b | (uint256)0x1000; |
||||
|
|
||||
|
|
||||
|
printf("a %s\n", a.ToString().c_str()); |
||||
|
printf("b %s\n", b.ToString().c_str()); |
||||
|
|
||||
|
a = 0xfffffffe; |
||||
|
a.pn[4] = 9; |
||||
|
|
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
a++; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
a++; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
a++; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
a++; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
|
||||
|
a--; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
a--; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
a--; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
uint256 d = a--; |
||||
|
printf("%s\n", d.ToString().c_str()); |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
a--; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
a--; |
||||
|
printf("%s\n", a.ToString().c_str()); |
||||
|
|
||||
|
d = a; |
||||
|
|
||||
|
printf("%s\n", d.ToString().c_str()); |
||||
|
for (int i = uint256::WIDTH-1; i >= 0; i--) printf("%08x", d.pn[i]); printf("\n"); |
||||
|
|
||||
|
uint256 neg = d; |
||||
|
neg = ~neg; |
||||
|
printf("%s\n", neg.ToString().c_str()); |
||||
|
|
||||
|
|
||||
|
uint256 e = uint256("0xABCDEF123abcdef12345678909832180000011111111"); |
||||
|
printf("\n"); |
||||
|
printf("%s\n", e.ToString().c_str()); |
||||
|
|
||||
|
|
||||
|
printf("\n"); |
||||
|
uint256 x1 = uint256("0xABCDEF123abcdef12345678909832180000011111111"); |
||||
|
uint256 x2; |
||||
|
printf("%s\n", x1.ToString().c_str()); |
||||
|
for (int i = 0; i < 270; i += 4) |
||||
|
{ |
||||
|
x2 = x1 << i; |
||||
|
printf("%s\n", x2.ToString().c_str()); |
||||
|
} |
||||
|
|
||||
|
printf("\n"); |
||||
|
printf("%s\n", x1.ToString().c_str()); |
||||
|
for (int i = 0; i < 270; i += 4) |
||||
|
{ |
||||
|
x2 = x1; |
||||
|
x2 >>= i; |
||||
|
printf("%s\n", x2.ToString().c_str()); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
for (int i = 0; i < 100; i++) |
||||
|
{ |
||||
|
uint256 k = (~uint256(0) >> i); |
||||
|
printf("%s\n", k.ToString().c_str()); |
||||
|
} |
||||
|
|
||||
|
for (int i = 0; i < 100; i++) |
||||
|
{ |
||||
|
uint256 k = (~uint256(0) << i); |
||||
|
printf("%s\n", k.ToString().c_str()); |
||||
|
} |
||||
|
|
||||
|
return (0); |
||||
|
} |
||||
|
|
||||
|
#endif |
@ -0,0 +1,218 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include "util.h" |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
string vstrprintf(const std::string &format, va_list ap) |
||||
|
{ |
||||
|
char buffer[50000]; |
||||
|
char* p = buffer; |
||||
|
int limit = sizeof(buffer); |
||||
|
int ret; |
||||
|
loop |
||||
|
{ |
||||
|
va_list arg_ptr; |
||||
|
va_copy(arg_ptr, ap); |
||||
|
ret = vsnprintf(p, limit, format.c_str(), arg_ptr); |
||||
|
va_end(arg_ptr); |
||||
|
if (ret >= 0 && ret < limit) |
||||
|
break; |
||||
|
if (p != buffer) |
||||
|
delete[] p; |
||||
|
limit *= 2; |
||||
|
p = new char[limit]; |
||||
|
if (p == NULL) |
||||
|
throw std::bad_alloc(); |
||||
|
} |
||||
|
string str(p, p+ret); |
||||
|
if (p != buffer) |
||||
|
delete[] p; |
||||
|
return str; |
||||
|
} |
||||
|
|
||||
|
string EncodeBase32(const unsigned char* pch, size_t len) |
||||
|
{ |
||||
|
static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; |
||||
|
|
||||
|
string strRet=""; |
||||
|
strRet.reserve((len+4)/5*8); |
||||
|
|
||||
|
int mode=0, left=0; |
||||
|
const unsigned char *pchEnd = pch+len; |
||||
|
|
||||
|
while (pch<pchEnd) |
||||
|
{ |
||||
|
int enc = *(pch++); |
||||
|
switch (mode) |
||||
|
{ |
||||
|
case 0: // we have no bits
|
||||
|
strRet += pbase32[enc >> 3]; |
||||
|
left = (enc & 7) << 2; |
||||
|
mode = 1; |
||||
|
break; |
||||
|
|
||||
|
case 1: // we have three bits
|
||||
|
strRet += pbase32[left | (enc >> 6)]; |
||||
|
strRet += pbase32[(enc >> 1) & 31]; |
||||
|
left = (enc & 1) << 4; |
||||
|
mode = 2; |
||||
|
break; |
||||
|
|
||||
|
case 2: // we have one bit
|
||||
|
strRet += pbase32[left | (enc >> 4)]; |
||||
|
left = (enc & 15) << 1; |
||||
|
mode = 3; |
||||
|
break; |
||||
|
|
||||
|
case 3: // we have four bits
|
||||
|
strRet += pbase32[left | (enc >> 7)]; |
||||
|
strRet += pbase32[(enc >> 2) & 31]; |
||||
|
left = (enc & 3) << 3; |
||||
|
mode = 4; |
||||
|
break; |
||||
|
|
||||
|
case 4: // we have two bits
|
||||
|
strRet += pbase32[left | (enc >> 5)]; |
||||
|
strRet += pbase32[enc & 31]; |
||||
|
mode = 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static const int nPadding[5] = {0, 6, 4, 3, 1}; |
||||
|
if (mode) |
||||
|
{ |
||||
|
strRet += pbase32[left]; |
||||
|
for (int n=0; n<nPadding[mode]; n++) |
||||
|
strRet += '='; |
||||
|
} |
||||
|
|
||||
|
return strRet; |
||||
|
} |
||||
|
|
||||
|
string EncodeBase32(const string& str) |
||||
|
{ |
||||
|
return EncodeBase32((const unsigned char*)str.c_str(), str.size()); |
||||
|
} |
||||
|
|
||||
|
vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) |
||||
|
{ |
||||
|
static const int decode32_table[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, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, |
||||
|
-1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
||||
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, |
||||
|
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, |
||||
|
23, 24, 25, -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 |
||||
|
}; |
||||
|
|
||||
|
if (pfInvalid) |
||||
|
*pfInvalid = false; |
||||
|
|
||||
|
vector<unsigned char> vchRet; |
||||
|
vchRet.reserve((strlen(p))*5/8); |
||||
|
|
||||
|
int mode = 0; |
||||
|
int left = 0; |
||||
|
|
||||
|
while (1) |
||||
|
{ |
||||
|
int dec = decode32_table[(unsigned char)*p]; |
||||
|
if (dec == -1) break; |
||||
|
p++; |
||||
|
switch (mode) |
||||
|
{ |
||||
|
case 0: // we have no bits and get 5
|
||||
|
left = dec; |
||||
|
mode = 1; |
||||
|
break; |
||||
|
|
||||
|
case 1: // we have 5 bits and keep 2
|
||||
|
vchRet.push_back((left<<3) | (dec>>2)); |
||||
|
left = dec & 3; |
||||
|
mode = 2; |
||||
|
break; |
||||
|
|
||||
|
case 2: // we have 2 bits and keep 7
|
||||
|
left = left << 5 | dec; |
||||
|
mode = 3; |
||||
|
break; |
||||
|
|
||||
|
case 3: // we have 7 bits and keep 4
|
||||
|
vchRet.push_back((left<<1) | (dec>>4)); |
||||
|
left = dec & 15; |
||||
|
mode = 4; |
||||
|
break; |
||||
|
|
||||
|
case 4: // we have 4 bits, and keep 1
|
||||
|
vchRet.push_back((left<<4) | (dec>>1)); |
||||
|
left = dec & 1; |
||||
|
mode = 5; |
||||
|
break; |
||||
|
|
||||
|
case 5: // we have 1 bit, and keep 6
|
||||
|
left = left << 5 | dec; |
||||
|
mode = 6; |
||||
|
break; |
||||
|
|
||||
|
case 6: // we have 6 bits, and keep 3
|
||||
|
vchRet.push_back((left<<2) | (dec>>3)); |
||||
|
left = dec & 7; |
||||
|
mode = 7; |
||||
|
break; |
||||
|
|
||||
|
case 7: // we have 3 bits, and keep 0
|
||||
|
vchRet.push_back((left<<5) | dec); |
||||
|
mode = 0; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (pfInvalid) |
||||
|
switch (mode) |
||||
|
{ |
||||
|
case 0: // 8n base32 characters processed: ok
|
||||
|
break; |
||||
|
|
||||
|
case 1: // 8n+1 base32 characters processed: impossible
|
||||
|
case 3: // +3
|
||||
|
case 6: // +6
|
||||
|
*pfInvalid = true; |
||||
|
break; |
||||
|
|
||||
|
case 2: // 8n+2 base32 characters processed: require '======'
|
||||
|
if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1) |
||||
|
*pfInvalid = true; |
||||
|
break; |
||||
|
|
||||
|
case 4: // 8n+4 base32 characters processed: require '===='
|
||||
|
if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1) |
||||
|
*pfInvalid = true; |
||||
|
break; |
||||
|
|
||||
|
case 5: // 8n+5 base32 characters processed: require '==='
|
||||
|
if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1) |
||||
|
*pfInvalid = true; |
||||
|
break; |
||||
|
|
||||
|
case 7: // 8n+7 base32 characters processed: require '='
|
||||
|
if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1) |
||||
|
*pfInvalid = true; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
return vchRet; |
||||
|
} |
||||
|
|
||||
|
string DecodeBase32(const string& str) |
||||
|
{ |
||||
|
vector<unsigned char> vchRet = DecodeBase32(str.c_str()); |
||||
|
return string((const char*)&vchRet[0], vchRet.size()); |
||||
|
} |
@ -0,0 +1,106 @@ |
|||||
|
#ifndef _UTIL_H_ |
||||
|
#define _UTIL_H_ 1 |
||||
|
|
||||
|
#include <pthread.h> |
||||
|
#include <errno.h> |
||||
|
#include <openssl/sha.h> |
||||
|
#include <stdarg.h> |
||||
|
|
||||
|
#include "uint256.h" |
||||
|
|
||||
|
#define loop for (;;) |
||||
|
#define BEGIN(a) ((char*)&(a)) |
||||
|
#define END(a) ((char*)&((&(a))[1])) |
||||
|
#define UBEGIN(a) ((unsigned char*)&(a)) |
||||
|
#define UEND(a) ((unsigned char*)&((&(a))[1])) |
||||
|
#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) |
||||
|
|
||||
|
#define WSAGetLastError() 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 |
||||
|
|
||||
|
// Wrapper to automatically initialize mutex
|
||||
|
class CCriticalSection |
||||
|
{ |
||||
|
protected: |
||||
|
pthread_rwlock_t mutex; |
||||
|
public: |
||||
|
explicit CCriticalSection() { pthread_rwlock_init(&mutex, NULL); } |
||||
|
~CCriticalSection() { pthread_rwlock_destroy(&mutex); } |
||||
|
void Enter(bool fShared = false) { |
||||
|
if (fShared) { |
||||
|
pthread_rwlock_rdlock(&mutex); |
||||
|
} else { |
||||
|
pthread_rwlock_wrlock(&mutex); |
||||
|
} |
||||
|
} |
||||
|
void Leave() { pthread_rwlock_unlock(&mutex); } |
||||
|
}; |
||||
|
|
||||
|
// Automatically leave critical section when leaving block, needed for exception safety
|
||||
|
class CCriticalBlock |
||||
|
{ |
||||
|
protected: |
||||
|
CCriticalSection* pcs; |
||||
|
public: |
||||
|
CCriticalBlock(CCriticalSection& cs, bool fShared = false) : pcs(&cs) { pcs->Enter(fShared); } |
||||
|
operator bool() const { return true; } |
||||
|
~CCriticalBlock() { pcs->Leave(); } |
||||
|
}; |
||||
|
|
||||
|
#define CRITICAL_BLOCK(cs) \ |
||||
|
if (CCriticalBlock criticalblock = CCriticalBlock(cs)) |
||||
|
|
||||
|
#define SHARED_CRITICAL_BLOCK(cs) \ |
||||
|
if (CCriticalBlock criticalblock = CCriticalBlock(cs, true)) |
||||
|
|
||||
|
template<typename T1> inline uint256 Hash(const T1 pbegin, const T1 pend) |
||||
|
{ |
||||
|
static unsigned char pblank[1]; |
||||
|
uint256 hash1; |
||||
|
SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); |
||||
|
uint256 hash2; |
||||
|
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); |
||||
|
return hash2; |
||||
|
} |
||||
|
|
||||
|
void static inline Sleep(int nMilliSec) { |
||||
|
struct timespec wa; |
||||
|
wa.tv_sec = nMilliSec/1000; |
||||
|
wa.tv_nsec = (nMilliSec % 1000) * 1000000; |
||||
|
nanosleep(&wa, NULL); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
std::string vstrprintf(const std::string &format, va_list ap); |
||||
|
|
||||
|
std::string static inline strprintf(const std::string &format, ...) { |
||||
|
va_list arg_ptr; |
||||
|
va_start(arg_ptr, format); |
||||
|
std::string ret = vstrprintf(format, arg_ptr); |
||||
|
va_end(arg_ptr); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool static inline error(std::string err, ...) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
bool static inline my_printf(std::string err, ...) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL); |
||||
|
std::string DecodeBase32(const std::string& str); |
||||
|
std::string EncodeBase32(const unsigned char* pch, size_t len); |
||||
|
std::string EncodeBase32(const std::string& str); |
||||
|
|
||||
|
#endif |
Loading…
Reference in new issue