Comit of novacoin-seeder sources. Novacoin-seeder is the bitcoin-seeder adaptation.
--- /dev/null
+Copyright (c) 2011-2012 Pieter Wuille and contributers
+Copyright (c) 2009-2012 Bitcoin Developers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+CXXFLAGS = -O3 -g0 -march=native
+LDFLAGS = $(CXXFLAGS)
+
+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++ -DUSE_IPV6 -pthread $(CXXFLAGS) -Wno-invalid-offsetof -c -o $@ $<
+
+dns.o: dns.c
+ gcc -pthread -std=c99 $(CXXFLAGS) dns.c -c -o dns.o
+
+%.o: %.cpp
--- /dev/null
+novacoin-seeder
+==============
+
+NovaCoin-seeder is a crawler for the NovaCoin 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).
+
+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-mailadres (with the @ part replaced by .) using -m.
+
+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.
--- /dev/null
+#include <algorithm>
+
+#include "db.h"
+#include "netbase.h"
+#include "protocol.h"
+#include "serialize.h"
+#include "uint256.h"
+
+#define BITCOIN_SEED_NONCE 0x0539a019ca550825
+#define REQUIRE_HEIGHT 0
+#define MIN_VERSION 40000
+
+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 60;
+ else
+ return 10;
+ }
+
+ 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 = REQUIRE_HEIGHT;
+ string ver = "/novacoin-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);
+ BeginMessage("getaddr");
+ EndMessage();
+ doneAfter = time(NULL) + GetTimeout();
+ }
+
+ 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") {
+ 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 (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());
+}
+*/
+
--- /dev/null
+#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
--- /dev/null
+#!/usr/bin/perl -w
+
+use strict;
+
+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;
+ }
+}
--- /dev/null
+// 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 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
--- /dev/null
+#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++;
+ 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_(CService &ip, int &wait) {
+ int64 now = time(NULL);
+ int cont = 0;
+ int tot = unkId.size();
+ do {
+ deque<int>::iterator it = ourId.begin();
+ while (it < ourId.end()) {
+ if (now - idToInfo[*it].ourLastTry > MIN_RETRY) {
+ tot++;
+ it++;
+ } else {
+ break;
+ }
+ }
+ if (tot == 0) {
+ if (ourId.size() > 0) {
+ wait = MIN_RETRY - (now - idToInfo[ourId.front()].ourLastTry);
+ } else {
+ wait = 5;
+ }
+ return false;
+ }
+ int rnd = rand() % tot;
+ int ret;
+ if (rnd < unkId.size()) {
+ if (rnd*10 < unkId.size()) {
+ // once every 10 attempts, restart with the oldest unknown IP
+ set<int>::iterator it = unkId.begin();
+ ret = *it;
+ } else {
+ // 90% of the time try the last learned IP
+ set<int>::reverse_iterator it = unkId.rbegin();
+ ret = *it;
+ }
+ unkId.erase(ret);
+ } 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 = idToInfo[ret].ip;
+ 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, 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) {
+ ips.insert(idToInfo[id].ip);
+ }
+ return;
+ }
+ if (max > goodId.size() / 2)
+ max = goodId.size() / 2;
+ if (max < 1)
+ max = 1;
+ int low = *goodId.begin();
+ int high = *goodId.rbegin();
+ set<int> ids;
+ while (ids.size() < max) {
+ int range = high-low+1;
+ int pos = low + (rand() % range);
+ int id = *(goodId.lower_bound(pos));
+ ids.insert(id);
+ }
+ for (set<int>::const_iterator it = ids.begin(); it != ids.end(); it++) {
+ CService &ip = idToInfo[*it].ip;
+ if (nets[ip.GetNetwork()])
+ ips.insert(ip);
+ }
+}
--- /dev/null
+#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
+
+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;
+};
+
+
+class CAddrInfo {
+private:
+ CService ip;
+ uint64_t services;
+ int64 lastTry;
+ int64 ourLastTry;
+ 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), 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;
+ return ret;
+ }
+
+ bool IsGood() const {
+ if (ip.GetPort() != ::nP2Port) return false;
+ if (!(services & NODE_NETWORK)) return false;
+ if (!ip.IsRoutable()) return false;
+ if (clientVersion && clientVersion < 32400) 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; }
+ return 0;
+ }
+ int GetIgnoreTime() const {
+ if (IsGood()) return 0;
+ if (stat1M.reliability - stat1M.weight + 1.0 < 0.08 && stat1D.count > 48) { return 8*3600; }
+ if (stat1W.reliability - stat1W.weight + 1.0 < 0.12 && stat8H.count > 24) { return 4*3600; }
+ if (stat1D.reliability - stat1D.weight + 1.0 < 0.16 && stat1D.count > 12) { return 2*3600; }
+ if (stat8H.reliability - stat8H.weight + 1.0 < 0.20 && stat8H.count > 6) { return 1*3600; }
+ return 0;
+ }
+
+ void Update(bool good);
+
+ friend class CAddrDb;
+
+ IMPLEMENT_SERIALIZE (
+ unsigned char version = 3;
+ 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);
+ }
+ )
+};
+
+class CAddrDbStats {
+public:
+ int nBanned;
+ int nAvail;
+ int nTracked;
+ int nNew;
+ int nGood;
+ int nAge;
+};
+
+// 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_(CService &ip, int& wait); // get an IP to test (must call Good_, Bad_, or Skipped_ on result afterwards)
+ 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, 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(CService &ip, int& wait) {
+ CRITICAL_BLOCK(cs)
+ return Get_(ip, wait);
+ }
+ void GetIPs(std::set<CNetAddr>& ips, int max, const bool *nets) {
+ SHARED_CRITICAL_BLOCK(cs)
+ GetIPs_(ips, max, nets);
+ }
+};
--- /dev/null
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.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 in_addr)))
+# define dstaddr(x) (CMSG_DATA(x))
+#elif defined IP_PKTINFO
+struct in_pktinfo {
+ unsigned int ipi_ifindex; /* Interface index */
+ struct in_addr ipi_spec_dst; /* Local address */
+ struct in_addr ipi_addr; /* Header Destination address */
+};
+
+# define DSTADDR_SOCKOPT IP_PKTINFO
+# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in_pktinfo)))
+# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_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) return -1;
+ const unsigned char *newbuf = inbuf + ref;
+ return parse_name(&newbuf, *inpos, 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; }
+ // check Z
+ if (((inbuf[3] & 112) >> 4) != 0) { /* printf("Z nonzero?\n"); */ error = 1; 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 (strcmp(name, opt->host) && (namel<hostl+2 || name[namel-hostl-1]!='.' || strcmp(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 size of authority section
+
+ int auth_size = 0;
+
+ if (!((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY))) {
+ // authority section will be necessary
+ unsigned char *oldpos = outpos;
+ write_record_ns(&oldpos, outend, "", offset, CLASS_IN, 0, opt->ns);
+ auth_size = oldpos - outpos;
+// printf("Authority section will claim %i bytes\n", 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 - 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 - 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, 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 - auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]);
+ else if (addr[n].v == 6)
+ ret = write_record_aaaa(&outpos, outend - 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) {
+ 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]++;
+ }
+ }
+
+ // 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_in si_other;
+ int senderSocket = -1;
+ senderSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (senderSocket == -1)
+ return -3;
+
+ int replySocket;
+ if (listenSocket == -1) {
+ struct sockaddr_in si_me;
+ if ((listenSocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
+ listenSocket = -1;
+ return -1;
+ }
+ replySocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (replySocket == -1)
+ {
+ close(listenSocket);
+ return -1;
+ }
+ int sockopt = 1;
+ setsockopt(listenSocket, IPPROTO_IP, DSTADDR_SOCKOPT, &sockopt, sizeof sockopt);
+ memset((char *) &si_me, 0, sizeof(si_me));
+ si_me.sin_family = AF_INET;
+ si_me.sin_port = htons(opt->port);
+ si_me.sin_addr.s_addr = INADDR_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;
+ sendmsg(listenSocket, &msg, 0);
+ msg.msg_iov[0].iov_base = inbuf;
+ handled = true;
+ }
+ }
+ if (!handled)
+ sendto(listenSocket, outbuf, ret, 0, (struct sockaddr*)&si_other, sizeof(si_other));
+ }
+ return 0;
+}
--- /dev/null
+#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, addr_t *addr, int max, int ipv4, int ipv6);
+ // stats
+ uint64_t nRequests;
+} dns_opt_t;
+
+extern int dnsserver(dns_opt_t *opt);
+
+#endif
--- /dev/null
+#include <algorithm>
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "bitcoin.h"
+#include "db.h"
+
+#define NTHREADS 24
+
+using namespace std;
+
+class CDnsSeedOpts {
+public:
+ int nThreads;
+ int nPort;
+ int nP2Port;
+ int nDnsThreads;
+ int fWipeBan;
+ int fWipeIgnore;
+ const char *mbox;
+ const char *ns;
+ const char *host;
+ const char *tor;
+ const char *magic;
+ vector<string> vSeeds;
+
+ CDnsSeedOpts() : nThreads(24), nDnsThreads(24), nPort(53), fWipeBan(0), fWipeIgnore(0), mbox(NULL), ns(NULL), host(NULL), tor(NULL), magic(NULL), vSeeds()
+ { nP2Port = GetDefaultPort(); }
+
+ void ParseCommandLine(int argc, char **argv) {
+ static const char *help = "NovaCoin-seeder\n"
+ "Usage: %s -h <host> -n <ns> [-m <mbox>] [-t <threads>] [-p <port>]\n"
+ "\n"
+ "Options:\n"
+ "-s <seed> Seed node to collect peers from (replaces default)\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 24)\n"
+ "-d <threads> Number of DNS server threads (default 24)\n"
+ "-p <port> UDP port to listen on (default 53)\n"
+ "-o <ip:port> Tor proxy IP/Port\n"
+ "--p2port <port> P2P port to connect to\n"
+ "--magic <hex> Magic string/network prefix\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[] = {
+ {"seed", required_argument, 0, 's'},
+ {"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'},
+ {"p2port", required_argument, 0, 'b'},
+ {"magic", required_argument, 0, 'k'},
+ {"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, "s:h:n:m:t:p:d:o:b:k:", long_options, &option_index);
+ if (c == -1) break;
+ switch (c) {
+ case 's': {
+ vSeeds.push_back(optarg);
+ break;
+ }
+
+ 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 'b': {
+ int p = strtol(optarg, NULL, 10);
+ if (p > 0 && p < 65536) nP2Port = p;
+ break;
+ }
+
+ case 'k': {
+ long int n;
+ unsigned int c;
+ magic = optarg;
+ if (strlen(magic)!=8)
+ break;
+ n = strtol(magic, NULL, 16);
+ if (n==0 && strcmp(magic, "00000000"))
+ break;
+ for (n=0; n<4; ++n) {
+ sscanf(&magic[n*2], "%2x", &c);
+ pchMessageStart[n] = (unsigned char) (c & 0xff);
+ }
+ break;
+ }
+
+ case '?': {
+ showHelp = true;
+ break;
+ }
+ }
+ }
+ 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) {
+ do {
+ CService ip;
+ int wait = 5;
+ if (!db.Get(ip, wait)) {
+ wait *= 1000;
+ wait += rand() % (500 * NTHREADS);
+ Sleep(wait);
+ continue;
+ }
+ int ban = 0;
+ vector<CAddress> addr;
+ int clientV = 0;
+ int blocks = 0;
+ std::string clientSV;
+ bool ret = TestNode(ip,ban,clientV,clientSV,blocks,addr);
+ db.Add(addr);
+ if (ret) {
+ db.Good(ip, clientV, clientSV, blocks);
+ } else {
+ db.Bad(ip, ban);
+ }
+ } while(1);
+}
+
+extern "C" int GetIPList(void *thread, addr_t *addr, int max, int ipv4, int ipv6);
+
+class CDnsThread {
+public:
+ dns_opt_t dns_opt; // must be first
+ const int id;
+ vector<addr_t> cache;
+ int nIPv4, nIPv6;
+ time_t cacheTime;
+ unsigned int cacheHits;
+ uint64_t dbQueries;
+
+ void cacheHit(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.size()*cache.size()/400) || (cacheHits*cacheHits > cache.size() / 20 && (now - cacheTime > 5))) {
+ set<CNetAddr> ips;
+ db.GetIPs(ips, 1000, nets);
+ dbQueries++;
+ cache.clear();
+ nIPv4 = 0;
+ nIPv6 = 0;
+ cache.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.push_back(a);
+ nIPv4++;
+#ifdef USE_IPV6
+ } else if ((*it).GetIn6Addr(&addr6)) {
+ addr_t a;
+ a.v = 6;
+ memcpy(&a.data.v6, &addr6, 16);
+ cache.push_back(a);
+ nIPv6++;
+#endif
+ }
+ }
+ cacheHits = 0;
+ cacheTime = 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 = 60;
+ dns_opt.nsttl = 40000;
+ dns_opt.cb = GetIPList;
+ dns_opt.port = opts->nPort;
+ dns_opt.nRequests = 0;
+ cache.clear();
+ cache.reserve(1000);
+ cacheTime = 0;
+ cacheHits = 0;
+ dbQueries = 0;
+ nIPv4 = 0;
+ nIPv6 = 0;
+ cacheHit(true);
+ }
+
+ void run() {
+ dnsserver(&dns_opt);
+ }
+};
+
+extern "C" int GetIPList(void *data, addr_t* addr, int max, int ipv4, int ipv6) {
+ CDnsThread *thread = (CDnsThread*)data;
+ thread->cacheHit();
+ unsigned int size = thread->cache.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[j].v == 4) ||
+ (ipv6 && thread->cache[j].v == 6);
+ if (ok) break;
+ j++;
+ if (j==size)
+ j=i;
+ } while(1);
+ addr[i] = thread->cache[j];
+ thread->cache[j] = thread->cache[i];
+ thread->cache[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*) {
+ do {
+ Sleep(100000);
+ {
+ 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");
+ vector<CAddrReport> v = db.GetAll();
+ sort(v.begin(), v.end(), StatCompare);
+ fprintf(d, "# address \t%%(2h)\t%%(8h)\t%%(1d)\t%%(7d)\t%%(30d)\tblocks\tversion\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, "%s\t%.2f%%\t%.2f%%\t%.2f%%\t%.2f%%\t%.2f%%\t%i\t%i \"%s\"\n", rep.ip.ToString().c_str(), 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.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 vector<string> vSeeds;
+unsigned short nP2Port;
+
+extern "C" void* ThreadSeeder(void*) {
+ vector<string> vDnsSeeds;
+ vector<string>::iterator itr;
+ for (itr = vSeeds.begin(); itr != vSeeds.end(); itr++) {
+ size_t len = itr->length();
+ if (len>=6 && !itr->compare(len-6, 6, ".onion"))
+ db.Add(CService(itr->c_str(), nP2Port), true);
+ else
+ vDnsSeeds.push_back(*itr);
+ }
+ do {
+ for (itr = vDnsSeeds.begin(); itr != vDnsSeeds.end(); itr++) {
+ vector<CNetAddr> ips;
+ LookupHost(itr->c_str(), ips);
+ for (vector<CNetAddr>::iterator it = ips.begin(); it != ips.end(); it++) {
+ db.Add(CService(*it, nP2Port), true);
+ }
+ }
+ Sleep(1800000);
+ } while(1);
+}
+
+int main(int argc, char **argv) {
+ signal(SIGPIPE, SIG_IGN);
+ setbuf(stdout, NULL);
+ CDnsSeedOpts opts;
+ opts.ParseCommandLine(argc, argv);
+ nP2Port = opts.nP2Port;
+ vSeeds.reserve(vSeeds.size() + opts.vSeeds.size());
+ vSeeds.insert(vSeeds.end(), opts.vSeeds.begin(), opts.vSeeds.end());
+ if (opts.vSeeds.empty()) {
+ vSeeds.push_back("novacoin.ru");
+ vSeeds.push_back("itzod.ru");
+ }
+ 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);
+ }
+ }
+ bool fDNS = 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);
+ }
+ 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;
+ printf("Starting seeder...");
+ pthread_create(&threadSeed, NULL, ThreadSeeder, NULL);
+ printf("done\n");
+ printf("Starting %i crawler threads...", opts.nThreads);
+ for (int i=0; i<opts.nThreads; i++) {
+ pthread_t thread;
+ pthread_create(&thread, NULL, ThreadCrawler, NULL);
+ }
+ printf("done\n");
+ pthread_create(&threadDump, NULL, ThreadDumper, NULL);
+ 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");
+ }
+ pthread_create(&threadStats, NULL, ThreadStats, NULL);
+ void* res;
+ pthread_join(threadDump, &res);
+ return 0;
+}
--- /dev/null
+// 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.
+
+#include "netbase.h"
+#include "util.h"
+
+#ifndef WIN32
+#include <sys/fcntl.h>
+#endif
+
+#include "strlcpy.h"
+#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
+
+#define printf my_printf
+
+using namespace std;
+
+// Settings
+typedef std::pair<CService, int> proxyType;
+static proxyType proxyInfo[NET_MAX];
+static proxyType nameproxyInfo;
+int nConnectTimeout = 5000;
+bool fNameLookup = false;
+
+static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
+
+enum Network ParseNetwork(std::string net) {
+ boost::to_lower(net);
+ if (net == "ipv4") return NET_IPV4;
+ if (net == "ipv6") return NET_IPV6;
+ if (net == "tor") return NET_TOR;
+ if (net == "i2p") return NET_I2P;
+ return NET_UNROUTABLE;
+}
+
+void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
+ size_t colon = in.find_last_of(':');
+ // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
+ bool fHaveColon = colon != in.npos;
+ bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
+ bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
+ if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
+ char *endp = NULL;
+ int n = strtol(in.c_str() + colon + 1, &endp, 10);
+ if (endp && *endp == 0 && n >= 0) {
+ in = in.substr(0, colon);
+ if (n > 0 && n < 0x10000)
+ portOut = n;
+ }
+ }
+ if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
+ hostOut = in.substr(1, in.size()-2);
+ else
+ hostOut = in;
+}
+
+bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
+{
+ vIP.clear();
+
+ {
+ CNetAddr addr;
+ if (addr.SetSpecial(std::string(pszName))) {
+ vIP.push_back(addr);
+ return true;
+ }
+ }
+
+ struct addrinfo aiHint;
+ memset(&aiHint, 0, sizeof(struct addrinfo));
+
+ aiHint.ai_socktype = SOCK_STREAM;
+ aiHint.ai_protocol = IPPROTO_TCP;
+#ifdef WIN32
+# ifdef USE_IPV6
+ aiHint.ai_family = AF_UNSPEC;
+# else
+ aiHint.ai_family = AF_INET;
+# endif
+ aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
+#else
+# ifdef USE_IPV6
+ aiHint.ai_family = AF_UNSPEC;
+# else
+ aiHint.ai_family = AF_INET;
+# endif
+ aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
+#endif
+ struct addrinfo *aiRes = NULL;
+ int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes);
+ if (nErr)
+ return false;
+
+ struct addrinfo *aiTrav = aiRes;
+ while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
+ {
+ if (aiTrav->ai_family == AF_INET)
+ {
+ assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
+ vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr));
+ }
+
+#ifdef USE_IPV6
+ if (aiTrav->ai_family == AF_INET6)
+ {
+ assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
+ vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr));
+ }
+#endif
+
+ aiTrav = aiTrav->ai_next;
+ }
+
+ freeaddrinfo(aiRes);
+
+ return (vIP.size() > 0);
+}
+
+bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
+{
+ if (pszName[0] == 0)
+ return false;
+ char psz[256];
+ char *pszHost = psz;
+ strlcpy(psz, pszName, sizeof(psz));
+ if (psz[0] == '[' && psz[strlen(psz)-1] == ']')
+ {
+ pszHost = psz+1;
+ psz[strlen(psz)-1] = 0;
+ }
+
+ return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup);
+}
+
+bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions)
+{
+ return LookupHost(pszName, vIP, nMaxSolutions, false);
+}
+
+bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
+{
+ if (pszName[0] == 0)
+ return false;
+ int port = portDefault;
+ std::string hostname = "";
+ SplitHostPort(std::string(pszName), port, hostname);
+
+ std::vector<CNetAddr> vIP;
+ bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup);
+ if (!fRet)
+ return false;
+ vAddr.resize(vIP.size());
+ for (unsigned int i = 0; i < vIP.size(); i++)
+ vAddr[i] = CService(vIP[i], port);
+ return true;
+}
+
+bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup)
+{
+ std::vector<CService> vService;
+ bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1);
+ if (!fRet)
+ return false;
+ addr = vService[0];
+ return true;
+}
+
+bool LookupNumeric(const char *pszName, CService& addr, int portDefault)
+{
+ return Lookup(pszName, addr, portDefault, false);
+}
+
+bool static Socks4(const CService &addrDest, SOCKET& hSocket)
+{
+ printf("SOCKS4 connecting %s\n", addrDest.ToString().c_str());
+ if (!addrDest.IsIPv4())
+ {
+ closesocket(hSocket);
+ return error("Proxy destination is not IPv4");
+ }
+ char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
+ struct sockaddr_in addr;
+ socklen_t len = sizeof(addr);
+ if (!addrDest.GetSockAddr((struct sockaddr*)&addr, &len) || addr.sin_family != AF_INET)
+ {
+ closesocket(hSocket);
+ return error("Cannot get proxy destination address");
+ }
+ memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
+ memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
+ char* pszSocks4 = pszSocks4IP;
+ int nSize = sizeof(pszSocks4IP);
+
+ int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
+ if (ret != nSize)
+ {
+ closesocket(hSocket);
+ return error("Error sending to proxy");
+ }
+ char pchRet[8];
+ if (recv(hSocket, pchRet, 8, 0) != 8)
+ {
+ closesocket(hSocket);
+ return error("Error reading proxy response");
+ }
+ if (pchRet[1] != 0x5a)
+ {
+ closesocket(hSocket);
+ if (pchRet[1] != 0x5b)
+ printf("ERROR: Proxy returned error %d\n", pchRet[1]);
+ return false;
+ }
+ printf("SOCKS4 connected %s\n", addrDest.ToString().c_str());
+ return true;
+}
+
+bool static Socks5(string strDest, int port, SOCKET& hSocket)
+{
+ printf("SOCKS5 connecting %s\n", strDest.c_str());
+ if (strDest.size() > 255)
+ {
+ closesocket(hSocket);
+ return error("Hostname too long");
+ }
+ char pszSocks5Init[] = "\5\1\0";
+ char *pszSocks5 = pszSocks5Init;
+ ssize_t nSize = sizeof(pszSocks5Init) - 1;
+
+ ssize_t ret = send(hSocket, pszSocks5, nSize, MSG_NOSIGNAL);
+ if (ret != nSize)
+ {
+ closesocket(hSocket);
+ return error("Error sending to proxy");
+ }
+ char pchRet1[2];
+ if (recv(hSocket, pchRet1, 2, 0) != 2)
+ {
+ closesocket(hSocket);
+ return error("Error reading proxy response");
+ }
+ if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00)
+ {
+ closesocket(hSocket);
+ return error("Proxy failed to initialize");
+ }
+ string strSocks5("\5\1");
+ strSocks5 += '\000'; strSocks5 += '\003';
+ strSocks5 += static_cast<char>(std::min((int)strDest.size(), 255));
+ strSocks5 += strDest;
+ strSocks5 += static_cast<char>((port >> 8) & 0xFF);
+ strSocks5 += static_cast<char>((port >> 0) & 0xFF);
+ ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL);
+ if (ret != (ssize_t)strSocks5.size())
+ {
+ closesocket(hSocket);
+ return error("Error sending to proxy");
+ }
+ char pchRet2[4];
+ if (recv(hSocket, pchRet2, 4, 0) != 4)
+ {
+ closesocket(hSocket);
+ return error("Error reading proxy response");
+ }
+ if (pchRet2[0] != 0x05)
+ {
+ closesocket(hSocket);
+ return error("Proxy failed to accept request");
+ }
+ if (pchRet2[1] != 0x00)
+ {
+ closesocket(hSocket);
+ switch (pchRet2[1])
+ {
+ case 0x01: return error("Proxy error: general failure");
+ case 0x02: return error("Proxy error: connection not allowed");
+ case 0x03: return error("Proxy error: network unreachable");
+ case 0x04: return error("Proxy error: host unreachable");
+ case 0x05: return error("Proxy error: connection refused");
+ case 0x06: return error("Proxy error: TTL expired");
+ case 0x07: return error("Proxy error: protocol error");
+ case 0x08: return error("Proxy error: address type not supported");
+ default: return error("Proxy error: unknown");
+ }
+ }
+ if (pchRet2[2] != 0x00)
+ {
+ closesocket(hSocket);
+ return error("Error: malformed proxy response");
+ }
+ char pchRet3[256];
+ switch (pchRet2[3])
+ {
+ case 0x01: ret = recv(hSocket, pchRet3, 4, 0) != 4; break;
+ case 0x04: ret = recv(hSocket, pchRet3, 16, 0) != 16; break;
+ case 0x03:
+ {
+ ret = recv(hSocket, pchRet3, 1, 0) != 1;
+ if (ret)
+ return error("Error reading from proxy");
+ int nRecv = pchRet3[0];
+ ret = recv(hSocket, pchRet3, nRecv, 0) != nRecv;
+ break;
+ }
+ default: closesocket(hSocket); return error("Error: malformed proxy response");
+ }
+ if (ret)
+ {
+ closesocket(hSocket);
+ return error("Error reading from proxy");
+ }
+ if (recv(hSocket, pchRet3, 2, 0) != 2)
+ {
+ closesocket(hSocket);
+ return error("Error reading from proxy");
+ }
+ printf("SOCKS5 connected %s\n", strDest.c_str());
+ return true;
+}
+
+bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)
+{
+ hSocketRet = INVALID_SOCKET;
+
+#ifdef USE_IPV6
+ struct sockaddr_storage sockaddr;
+#else
+ struct sockaddr sockaddr;
+#endif
+ socklen_t len = sizeof(sockaddr);
+ if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
+ printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str());
+ return false;
+ }
+
+ SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
+ if (hSocket == INVALID_SOCKET)
+ return false;
+#ifdef SO_NOSIGPIPE
+ int set = 1;
+ setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
+#endif
+
+#ifdef WIN32
+ u_long fNonblock = 1;
+ if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
+#else
+ int fFlags = fcntl(hSocket, F_GETFL, 0);
+ if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
+#endif
+ {
+ closesocket(hSocket);
+ return false;
+ }
+
+ if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
+ {
+ // WSAEINVAL is here because some legacy version of winsock uses it
+ if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
+ {
+ struct timeval timeout;
+ timeout.tv_sec = nTimeout / 1000;
+ timeout.tv_usec = (nTimeout % 1000) * 1000;
+
+ fd_set fdset;
+ FD_ZERO(&fdset);
+ FD_SET(hSocket, &fdset);
+ int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
+ if (nRet == 0)
+ {
+ printf("connection timeout\n");
+ closesocket(hSocket);
+ return false;
+ }
+ if (nRet == SOCKET_ERROR)
+ {
+ printf("select() for connection failed: %i\n",WSAGetLastError());
+ closesocket(hSocket);
+ return false;
+ }
+ socklen_t nRetSize = sizeof(nRet);
+#ifdef WIN32
+ if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
+#else
+ if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
+#endif
+ {
+ printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
+ closesocket(hSocket);
+ return false;
+ }
+ if (nRet != 0)
+ {
+ printf("connect() failed after select(): %s\n",strerror(nRet));
+ closesocket(hSocket);
+ return false;
+ }
+ }
+#ifdef WIN32
+ else if (WSAGetLastError() != WSAEISCONN)
+#else
+ else
+#endif
+ {
+ printf("connect() failed: %i\n",WSAGetLastError());
+ closesocket(hSocket);
+ return false;
+ }
+ }
+
+ // this isn't even strictly necessary
+ // CNode::ConnectNode immediately turns the socket back to non-blocking
+ // but we'll turn it back to blocking just in case
+#ifdef WIN32
+ fNonblock = 0;
+ if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
+#else
+ fFlags = fcntl(hSocket, F_GETFL, 0);
+ if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR)
+#endif
+ {
+ closesocket(hSocket);
+ return false;
+ }
+
+ hSocketRet = hSocket;
+ return true;
+}
+
+bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) {
+ assert(net >= 0 && net < NET_MAX);
+ if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5)
+ return false;
+ if (nSocksVersion != 0 && !addrProxy.IsValid())
+ return false;
+ proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion);
+ return true;
+}
+
+bool GetProxy(enum Network net, CService &addrProxy) {
+ assert(net >= 0 && net < NET_MAX);
+ if (!proxyInfo[net].second)
+ return false;
+ addrProxy = proxyInfo[net].first;
+ return true;
+}
+
+bool SetNameProxy(CService addrProxy, int nSocksVersion) {
+ if (nSocksVersion != 0 && nSocksVersion != 5)
+ return false;
+ if (nSocksVersion != 0 && !addrProxy.IsValid())
+ return false;
+ nameproxyInfo = std::make_pair(addrProxy, nSocksVersion);
+ return true;
+}
+
+bool GetNameProxy() {
+ return nameproxyInfo.second != 0;
+}
+
+bool IsProxy(const CNetAddr &addr) {
+ for (int i=0; i<NET_MAX; i++) {
+ if (proxyInfo[i].second && (addr == (CNetAddr)proxyInfo[i].first))
+ return true;
+ }
+ return false;
+}
+
+bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
+{
+ const proxyType &proxy = proxyInfo[addrDest.GetNetwork()];
+
+ // no proxy needed
+ if (!proxy.second)
+ return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
+
+ SOCKET hSocket = INVALID_SOCKET;
+
+ // first connect to proxy server
+ if (!ConnectSocketDirectly(proxy.first, hSocket, nTimeout))
+ return false;
+
+ // do socks negotiation
+ switch (proxy.second) {
+ case 4:
+ if (!Socks4(addrDest, hSocket))
+ return false;
+ break;
+ case 5:
+ if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ hSocketRet = hSocket;
+ return true;
+}
+
+bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout)
+{
+ string strDest;
+ int port = portDefault;
+ SplitHostPort(string(pszDest), port, strDest);
+
+ SOCKET hSocket = INVALID_SOCKET;
+ CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port);
+ if (addrResolved.IsValid()) {
+ addr = addrResolved;
+ return ConnectSocket(addr, hSocketRet, nTimeout);
+ }
+ addr = CService("0.0.0.0:0");
+ if (!nameproxyInfo.second)
+ return false;
+ if (!ConnectSocketDirectly(nameproxyInfo.first, hSocket, nTimeout))
+ return false;
+
+ switch(nameproxyInfo.second)
+ {
+ default:
+ case 4: return false;
+ case 5:
+ if (!Socks5(strDest, port, hSocket))
+ return false;
+ break;
+ }
+
+ hSocketRet = hSocket;
+ return true;
+}
+
+void CNetAddr::Init()
+{
+ memset(ip, 0, 16);
+}
+
+void CNetAddr::SetIP(const CNetAddr& ipIn)
+{
+ memcpy(ip, ipIn.ip, sizeof(ip));
+}
+
+static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
+static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5};
+
+bool CNetAddr::SetSpecial(const std::string &strName)
+{
+ if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
+ std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str());
+ if (vchAddr.size() != 16-sizeof(pchOnionCat))
+ return false;
+ memcpy(ip, pchOnionCat, sizeof(pchOnionCat));
+ for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++)
+ ip[i + sizeof(pchOnionCat)] = vchAddr[i];
+ return true;
+ }
+ if (strName.size()>11 && strName.substr(strName.size() - 11, 11) == ".oc.b32.i2p") {
+ std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 11).c_str());
+ if (vchAddr.size() != 16-sizeof(pchGarliCat))
+ return false;
+ memcpy(ip, pchOnionCat, sizeof(pchGarliCat));
+ for (unsigned int i=0; i<16-sizeof(pchGarliCat); i++)
+ ip[i + sizeof(pchGarliCat)] = vchAddr[i];
+ return true;
+ }
+ return false;
+}
+
+CNetAddr::CNetAddr()
+{
+ Init();
+}
+
+CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
+{
+ memcpy(ip, pchIPv4, 12);
+ memcpy(ip+12, &ipv4Addr, 4);
+}
+
+#ifdef USE_IPV6
+CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr)
+{
+ memcpy(ip, &ipv6Addr, 16);
+}
+#endif
+
+CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup)
+{
+ Init();
+ std::vector<CNetAddr> vIP;
+ if (LookupHost(pszIp, vIP, 1, fAllowLookup))
+ *this = vIP[0];
+}
+
+CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup)
+{
+ Init();
+ std::vector<CNetAddr> vIP;
+ if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup))
+ *this = vIP[0];
+}
+
+unsigned int CNetAddr::GetByte(int n) const
+{
+ return ip[15-n];
+}
+
+bool CNetAddr::IsIPv4() const
+{
+ return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);
+}
+
+bool CNetAddr::IsIPv6() const
+{
+ return (!IsIPv4() && !IsTor() && !IsI2P());
+}
+
+bool CNetAddr::IsRFC1918() const
+{
+ return IsIPv4() && (
+ GetByte(3) == 10 ||
+ (GetByte(3) == 192 && GetByte(2) == 168) ||
+ (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));
+}
+
+bool CNetAddr::IsRFC3927() const
+{
+ return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
+}
+
+bool CNetAddr::IsRFC3849() const
+{
+ return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8;
+}
+
+bool CNetAddr::IsRFC3964() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x02);
+}
+
+bool CNetAddr::IsRFC6052() const
+{
+ static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0};
+ return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0);
+}
+
+bool CNetAddr::IsRFC4380() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0);
+}
+
+bool CNetAddr::IsRFC4862() const
+{
+ static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0};
+ return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0);
+}
+
+bool CNetAddr::IsRFC4193() const
+{
+ return ((GetByte(15) & 0xFE) == 0xFC);
+}
+
+bool CNetAddr::IsRFC6145() const
+{
+ static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0};
+ return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0);
+}
+
+bool CNetAddr::IsRFC4843() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
+}
+
+bool CNetAddr::IsTor() const
+{
+ return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
+}
+
+bool CNetAddr::IsI2P() const
+{
+ return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0);
+}
+
+bool CNetAddr::IsLocal() const
+{
+ // IPv4 loopback
+ if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0))
+ return true;
+
+ // IPv6 loopback (::1/128)
+ static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+ if (memcmp(ip, pchLocal, 16) == 0)
+ return true;
+
+ return false;
+}
+
+bool CNetAddr::IsMulticast() const
+{
+ return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0)
+ || (GetByte(15) == 0xFF);
+}
+
+bool CNetAddr::IsValid() const
+{
+ // Cleanup 3-byte shifted addresses caused by garbage in size field
+ // of addr messages from versions before 0.2.9 checksum.
+ // Two consecutive addr messages look like this:
+ // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
+ // so if the first length field is garbled, it reads the second batch
+ // of addr misaligned by 3 bytes.
+ if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
+ return false;
+
+ // unspecified IPv6 address (::/128)
+ unsigned char ipNone[16] = {};
+ if (memcmp(ip, ipNone, 16) == 0)
+ return false;
+
+ // documentation IPv6 address
+ if (IsRFC3849())
+ return false;
+
+ if (IsIPv4())
+ {
+ // INADDR_NONE
+ uint32_t ipNone = INADDR_NONE;
+ if (memcmp(ip+12, &ipNone, 4) == 0)
+ return false;
+
+ // 0
+ ipNone = 0;
+ if (memcmp(ip+12, &ipNone, 4) == 0)
+ return false;
+ }
+
+ return true;
+}
+
+bool CNetAddr::IsRoutable() const
+{
+ return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsTor() && !IsI2P()) || IsRFC4843() || IsLocal());
+}
+
+enum Network CNetAddr::GetNetwork() const
+{
+ if (!IsRoutable())
+ return NET_UNROUTABLE;
+
+ if (IsIPv4())
+ return NET_IPV4;
+
+ if (IsTor())
+ return NET_TOR;
+
+ if (IsI2P())
+ return NET_I2P;
+
+ return NET_IPV6;
+}
+
+std::string CNetAddr::ToStringIP() const
+{
+ if (IsTor())
+ return EncodeBase32(&ip[6], 10) + ".onion";
+ if (IsI2P())
+ return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p";
+ CService serv(*this, 0);
+#ifdef USE_IPV6
+ struct sockaddr_storage sockaddr;
+#else
+ struct sockaddr sockaddr;
+#endif
+ socklen_t socklen = sizeof(sockaddr);
+ if (serv.GetSockAddr((struct sockaddr*)&sockaddr, &socklen)) {
+ char name[1025] = "";
+ if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST))
+ return std::string(name);
+ }
+ if (IsIPv4())
+ return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
+ else
+ return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
+ GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12),
+ GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8),
+ GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4),
+ GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0));
+}
+
+std::string CNetAddr::ToString() const
+{
+ return ToStringIP();
+}
+
+bool operator==(const CNetAddr& a, const CNetAddr& b)
+{
+ return (memcmp(a.ip, b.ip, 16) == 0);
+}
+
+bool operator!=(const CNetAddr& a, const CNetAddr& b)
+{
+ return (memcmp(a.ip, b.ip, 16) != 0);
+}
+
+bool operator<(const CNetAddr& a, const CNetAddr& b)
+{
+ return (memcmp(a.ip, b.ip, 16) < 0);
+}
+
+bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
+{
+ if (!IsIPv4())
+ return false;
+ memcpy(pipv4Addr, ip+12, 4);
+ return true;
+}
+
+#ifdef USE_IPV6
+bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
+{
+ memcpy(pipv6Addr, ip, 16);
+ return true;
+}
+#endif
+
+// get canonical identifier of an address' group
+// no two connections will be attempted to addresses with the same group
+std::vector<unsigned char> CNetAddr::GetGroup() const
+{
+ std::vector<unsigned char> vchRet;
+ int nClass = NET_IPV6;
+ int nStartByte = 0;
+ int nBits = 16;
+
+ // all local addresses belong to the same group
+ if (IsLocal())
+ {
+ nClass = 255;
+ nBits = 0;
+ }
+
+ // all unroutable addresses belong to the same group
+ if (!IsRoutable())
+ {
+ nClass = NET_UNROUTABLE;
+ nBits = 0;
+ }
+ // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
+ // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
+ else if (IsIPv4() || IsRFC6145() || IsRFC6052())
+ {
+ nClass = NET_IPV4;
+ nStartByte = 12;
+ }
+ // for 6to4 tunnelled addresses, use the encapsulated IPv4 address
+ else if (IsRFC3964())
+ {
+ nClass = NET_IPV4;
+ nStartByte = 2;
+ }
+ // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
+ else if (IsRFC4380())
+ {
+ vchRet.push_back(NET_IPV4);
+ vchRet.push_back(GetByte(3) ^ 0xFF);
+ vchRet.push_back(GetByte(2) ^ 0xFF);
+ return vchRet;
+ }
+ else if (IsTor())
+ {
+ nClass = NET_TOR;
+ nStartByte = 6;
+ nBits = 4;
+ }
+ else if (IsI2P())
+ {
+ nClass = NET_I2P;
+ nStartByte = 6;
+ nBits = 4;
+ }
+ // for he.net, use /36 groups
+ else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
+ nBits = 36;
+ // for the rest of the IPv6 network, use /32 groups
+ else
+ nBits = 32;
+
+ vchRet.push_back(nClass);
+ while (nBits >= 8)
+ {
+ vchRet.push_back(GetByte(15 - nStartByte));
+ nStartByte++;
+ nBits -= 8;
+ }
+ if (nBits > 0)
+ vchRet.push_back(GetByte(15 - nStartByte) | ((1 << nBits) - 1));
+
+ return vchRet;
+}
+
+uint64 CNetAddr::GetHash() const
+{
+ uint256 hash = Hash(&ip[0], &ip[16]);
+ uint64 nRet;
+ memcpy(&nRet, &hash, sizeof(nRet));
+ return nRet;
+}
+
+void CNetAddr::print() const
+{
+ printf("CNetAddr(%s)\n", ToString().c_str());
+}
+
+// private extensions to enum Network, only returned by GetExtNetwork,
+// and only used in GetReachabilityFrom
+static const int NET_UNKNOWN = NET_MAX + 0;
+static const int NET_TEREDO = NET_MAX + 1;
+int static GetExtNetwork(const CNetAddr *addr)
+{
+ if (addr == NULL)
+ return NET_UNKNOWN;
+ if (addr->IsRFC4380())
+ return NET_TEREDO;
+ return addr->GetNetwork();
+}
+
+/** Calculates a metric for how reachable (*this) is from a given partner */
+int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
+{
+ enum Reachability {
+ REACH_UNREACHABLE,
+ REACH_DEFAULT,
+ REACH_TEREDO,
+ REACH_IPV6_WEAK,
+ REACH_IPV4,
+ REACH_IPV6_STRONG,
+ REACH_PRIVATE
+ };
+
+ if (!IsRoutable())
+ return REACH_UNREACHABLE;
+
+ int ourNet = GetExtNetwork(this);
+ int theirNet = GetExtNetwork(paddrPartner);
+ bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();
+
+ switch(theirNet) {
+ case NET_IPV4:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_IPV4: return REACH_IPV4;
+ }
+ case NET_IPV6:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_TEREDO: return REACH_TEREDO;
+ case NET_IPV4: return REACH_IPV4;
+ case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled
+ }
+ case NET_TOR:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well
+ case NET_TOR: return REACH_PRIVATE;
+ }
+ case NET_I2P:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_I2P: return REACH_PRIVATE;
+ }
+ case NET_TEREDO:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_TEREDO: return REACH_TEREDO;
+ case NET_IPV6: return REACH_IPV6_WEAK;
+ case NET_IPV4: return REACH_IPV4;
+ }
+ case NET_UNKNOWN:
+ case NET_UNROUTABLE:
+ default:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_TEREDO: return REACH_TEREDO;
+ case NET_IPV6: return REACH_IPV6_WEAK;
+ case NET_IPV4: return REACH_IPV4;
+ case NET_I2P: return REACH_PRIVATE; // assume connections from unroutable addresses are
+ case NET_TOR: return REACH_PRIVATE; // either from Tor/I2P, or don't care about our address
+ }
+ }
+}
+
+void CService::Init()
+{
+ port = 0;
+}
+
+CService::CService()
+{
+ Init();
+}
+
+CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn)
+{
+}
+
+CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn)
+{
+}
+
+#ifdef USE_IPV6
+CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn)
+{
+}
+#endif
+
+CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))
+{
+ assert(addr.sin_family == AF_INET);
+}
+
+#ifdef USE_IPV6
+CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port))
+{
+ assert(addr.sin6_family == AF_INET6);
+}
+#endif
+
+bool CService::SetSockAddr(const struct sockaddr *paddr)
+{
+ switch (paddr->sa_family) {
+ case AF_INET:
+ *this = CService(*(const struct sockaddr_in*)paddr);
+ return true;
+#ifdef USE_IPV6
+ case AF_INET6:
+ *this = CService(*(const struct sockaddr_in6*)paddr);
+ return true;
+#endif
+ default:
+ return false;
+ }
+}
+
+CService::CService(const char *pszIpPort, bool fAllowLookup)
+{
+ Init();
+ CService ip;
+ if (Lookup(pszIpPort, ip, 0, fAllowLookup))
+ *this = ip;
+}
+
+CService::CService(const char *pszIpPort, int portDefault, bool fAllowLookup)
+{
+ Init();
+ CService ip;
+ if (Lookup(pszIpPort, ip, portDefault, fAllowLookup))
+ *this = ip;
+}
+
+CService::CService(const std::string &strIpPort, bool fAllowLookup)
+{
+ Init();
+ CService ip;
+ if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup))
+ *this = ip;
+}
+
+CService::CService(const std::string &strIpPort, int portDefault, bool fAllowLookup)
+{
+ Init();
+ CService ip;
+ if (Lookup(strIpPort.c_str(), ip, portDefault, fAllowLookup))
+ *this = ip;
+}
+
+unsigned short CService::GetPort() const
+{
+ return port;
+}
+
+bool operator==(const CService& a, const CService& b)
+{
+ return (CNetAddr)a == (CNetAddr)b && a.port == b.port;
+}
+
+bool operator!=(const CService& a, const CService& b)
+{
+ return (CNetAddr)a != (CNetAddr)b || a.port != b.port;
+}
+
+bool operator<(const CService& a, const CService& b)
+{
+ return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port);
+}
+
+bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
+{
+ if (IsIPv4()) {
+ if (*addrlen < (socklen_t)sizeof(struct sockaddr_in))
+ return false;
+ *addrlen = sizeof(struct sockaddr_in);
+ struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;
+ memset(paddrin, 0, *addrlen);
+ if (!GetInAddr(&paddrin->sin_addr))
+ return false;
+ paddrin->sin_family = AF_INET;
+ paddrin->sin_port = htons(port);
+ return true;
+ }
+#ifdef USE_IPV6
+ if (IsIPv6()) {
+ if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))
+ return false;
+ *addrlen = sizeof(struct sockaddr_in6);
+ struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;
+ memset(paddrin6, 0, *addrlen);
+ if (!GetIn6Addr(&paddrin6->sin6_addr))
+ return false;
+ paddrin6->sin6_family = AF_INET6;
+ paddrin6->sin6_port = htons(port);
+ return true;
+ }
+#endif
+ return false;
+}
+
+std::vector<unsigned char> CService::GetKey() const
+{
+ std::vector<unsigned char> vKey;
+ vKey.resize(18);
+ memcpy(&vKey[0], ip, 16);
+ vKey[16] = port / 0x100;
+ vKey[17] = port & 0x0FF;
+ return vKey;
+}
+
+std::string CService::ToStringPort() const
+{
+ return strprintf("%u", port);
+}
+
+std::string CService::ToStringIPPort() const
+{
+ if (IsIPv4() || IsTor() || IsI2P()) {
+ return ToStringIP() + ":" + ToStringPort();
+ } else {
+ return "[" + ToStringIP() + "]:" + ToStringPort();
+ }
+}
+
+std::string CService::ToString() const
+{
+ return ToStringIPPort();
+}
+
+void CService::print() const
+{
+ printf("CService(%s)\n", ToString().c_str());
+}
+
+void CService::SetPort(unsigned short portIn)
+{
+ port = portIn;
+}
--- /dev/null
+// 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 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;
+
+#ifdef USE_IPV6
+ CNetAddr(const struct in6_addr& pipv6Addr);
+ bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
+#endif
+
+ friend bool operator==(const CNetAddr& a, const CNetAddr& b);
+ friend bool operator!=(const CNetAddr& a, const CNetAddr& b);
+ friend bool operator<(const CNetAddr& a, const CNetAddr& b);
+
+ 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;
+
+#ifdef USE_IPV6
+ CService(const struct in6_addr& ipv6Addr, unsigned short port);
+ CService(const struct sockaddr_in6& addr);
+#endif
+
+ 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
--- /dev/null
+// 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
+
+bool fTestNet = false;
+
+static const char* ppszTypeName[] =
+{
+ "ERROR",
+ "tx",
+ "block",
+};
+
+unsigned char pchMessageStart[4] = { 0xe4, 0xe8, 0xe9, 0xe5 };
+
+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");
+}
--- /dev/null
+// 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 unsigned short nP2Port;
+
+extern bool fTestNet;
+static inline unsigned short GetDefaultPort(const bool testnet = fTestNet)
+{
+ return testnet ? 17777 : 7777;
+}
+
+//
+// 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__
--- /dev/null
+// 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_SERIALIZE_H
+#define BITCOIN_SERIALIZE_H
+
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <cassert>
+#include <climits>
+#include <cstring>
+#include <cstdio>
+
+#include <boost/type_traits/is_fundamental.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/tuple/tuple_io.hpp>
+
+#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
+
+#ifdef WIN32
+#include <windows.h>
+// This is used to attempt to keep keying material out of swap
+// Note that VirtualLock does not provide this as a guarantee on Windows,
+// but, in practice, memory that has been VirtualLock'd almost never gets written to
+// the pagefile except in rare circumstances where memory is extremely low.
+#include <windows.h>
+#define mlock(p, n) VirtualLock((p), (n));
+#define munlock(p, n) VirtualUnlock((p), (n));
+#else
+#include <sys/mman.h>
+#include <limits.h>
+/* This comes from limits.h if it's not defined there set a sane default */
+#ifndef PAGESIZE
+#include <unistd.h>
+#define PAGESIZE sysconf(_SC_PAGESIZE)
+#endif
+#define mlock(a,b) \
+ mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
+ (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
+#define munlock(a,b) \
+ munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
+ (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
+#endif
+
+class CScript;
+class CDataStream;
+class CAutoFile;
+static const unsigned int MAX_SIZE = 0x02000000;
+
+static const int PROTOCOL_VERSION = 60000;
+
+// Used to bypass the rule against non-const reference to temporary
+// where it makes sense with wrappers such as CFlatData or CTxDB
+template<typename T>
+inline T& REF(const T& val)
+{
+ return const_cast<T&>(val);
+}
+
+/////////////////////////////////////////////////////////////////
+//
+// Templates for serializing to anything that looks like a stream,
+// i.e. anything that supports .read(char*, int) and .write(char*, int)
+//
+
+enum
+{
+ // primary actions
+ SER_NETWORK = (1 << 0),
+ SER_DISK = (1 << 1),
+ SER_GETHASH = (1 << 2),
+
+ // modifiers
+ SER_SKIPSIG = (1 << 16),
+ SER_BLOCKHEADERONLY = (1 << 17),
+};
+
+#define IMPLEMENT_SERIALIZE(statements) \
+ unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const \
+ { \
+ CSerActionGetSerializeSize ser_action; \
+ const bool fGetSize = true; \
+ const bool fWrite = false; \
+ const bool fRead = false; \
+ unsigned int nSerSize = 0; \
+ ser_streamplaceholder s; \
+ s.nType = nType; \
+ s.nVersion = nVersion; \
+ {statements} \
+ return nSerSize; \
+ } \
+ template<typename Stream> \
+ void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const \
+ { \
+ CSerActionSerialize ser_action; \
+ const bool fGetSize = false; \
+ const bool fWrite = true; \
+ const bool fRead = false; \
+ unsigned int nSerSize = 0; \
+ {statements} \
+ } \
+ template<typename Stream> \
+ void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) \
+ { \
+ CSerActionUnserialize ser_action; \
+ const bool fGetSize = false; \
+ const bool fWrite = false; \
+ const bool fRead = true; \
+ unsigned int nSerSize = 0; \
+ {statements} \
+ }
+
+#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))
+
+
+
+
+
+
+//
+// Basic types
+//
+#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj))
+#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj))
+
+inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); }
+
+template<typename Stream> inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); }
+
+template<typename Stream> inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); }
+
+inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); }
+template<typename Stream> inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); }
+template<typename Stream> inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; }
+
+
+
+
+
+
+//
+// Compact size
+// size < 253 -- 1 byte
+// size <= USHRT_MAX -- 3 bytes (253 + 2 bytes)
+// size <= UINT_MAX -- 5 bytes (254 + 4 bytes)
+// size > UINT_MAX -- 9 bytes (255 + 8 bytes)
+//
+inline unsigned int GetSizeOfCompactSize(uint64 nSize)
+{
+ if (nSize < 253) return sizeof(unsigned char);
+ else if (nSize <= USHRT_MAX) return sizeof(unsigned char) + sizeof(unsigned short);
+ else if (nSize <= UINT_MAX) return sizeof(unsigned char) + sizeof(unsigned int);
+ else return sizeof(unsigned char) + sizeof(uint64);
+}
+
+template<typename Stream>
+void WriteCompactSize(Stream& os, uint64 nSize)
+{
+ if (nSize < 253)
+ {
+ unsigned char chSize = nSize;
+ WRITEDATA(os, chSize);
+ }
+ else if (nSize <= USHRT_MAX)
+ {
+ unsigned char chSize = 253;
+ unsigned short xSize = nSize;
+ WRITEDATA(os, chSize);
+ WRITEDATA(os, xSize);
+ }
+ else if (nSize <= UINT_MAX)
+ {
+ unsigned char chSize = 254;
+ unsigned int xSize = nSize;
+ WRITEDATA(os, chSize);
+ WRITEDATA(os, xSize);
+ }
+ else
+ {
+ unsigned char chSize = 255;
+ uint64 xSize = nSize;
+ WRITEDATA(os, chSize);
+ WRITEDATA(os, xSize);
+ }
+ return;
+}
+
+template<typename Stream>
+uint64 ReadCompactSize(Stream& is)
+{
+ unsigned char chSize;
+ READDATA(is, chSize);
+ uint64 nSizeRet = 0;
+ if (chSize < 253)
+ {
+ nSizeRet = chSize;
+ }
+ else if (chSize == 253)
+ {
+ unsigned short xSize;
+ READDATA(is, xSize);
+ nSizeRet = xSize;
+ }
+ else if (chSize == 254)
+ {
+ unsigned int xSize;
+ READDATA(is, xSize);
+ nSizeRet = xSize;
+ }
+ else
+ {
+ uint64 xSize;
+ READDATA(is, xSize);
+ nSizeRet = xSize;
+ }
+ if (nSizeRet > (uint64)MAX_SIZE)
+ throw std::ios_base::failure("ReadCompactSize() : size too large");
+ return nSizeRet;
+}
+
+
+
+//
+// Wrapper for serializing arrays and POD
+// There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it
+//
+#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
+class CFlatData
+{
+protected:
+ char* pbegin;
+ char* pend;
+public:
+ CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { }
+ char* begin() { return pbegin; }
+ const char* begin() const { return pbegin; }
+ char* end() { return pend; }
+ const char* end() const { return pend; }
+
+ unsigned int GetSerializeSize(int, int=0) const
+ {
+ return pend - pbegin;
+ }
+
+ template<typename Stream>
+ void Serialize(Stream& s, int, int=0) const
+ {
+ s.write(pbegin, pend - pbegin);
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream& s, int, int=0)
+ {
+ s.read(pbegin, pend - pbegin);
+ }
+};
+
+
+
+//
+// string stored as a fixed length field
+//
+template<std::size_t LEN>
+class CFixedFieldString
+{
+protected:
+ const std::string* pcstr;
+ std::string* pstr;
+public:
+ explicit CFixedFieldString(const std::string& str) : pcstr(&str), pstr(NULL) { }
+ explicit CFixedFieldString(std::string& str) : pcstr(&str), pstr(&str) { }
+
+ unsigned int GetSerializeSize(int, int=0) const
+ {
+ return LEN;
+ }
+
+ template<typename Stream>
+ void Serialize(Stream& s, int, int=0) const
+ {
+ char pszBuf[LEN];
+ strncpy(pszBuf, pcstr->c_str(), LEN);
+ s.write(pszBuf, LEN);
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream& s, int, int=0)
+ {
+ if (pstr == NULL)
+ throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string");
+ char pszBuf[LEN+1];
+ s.read(pszBuf, LEN);
+ pszBuf[LEN] = '\0';
+ *pstr = pszBuf;
+ }
+};
+
+
+
+
+
+//
+// Forward declarations
+//
+
+// string
+template<typename C> unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int=0);
+template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str, int, int=0);
+template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str, int, int=0);
+
+// vector
+template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
+template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
+template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
+template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
+template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
+template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
+template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION);
+
+// others derived from vector
+extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion=PROTOCOL_VERSION);
+
+// pair
+template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION);
+
+// 3 tuple
+template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION);
+
+// 4 tuple
+template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION);
+
+// map
+template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
+
+// set
+template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
+
+
+
+
+
+//
+// If none of the specialized versions above matched, default to calling member function.
+// "int nType" is changed to "long nType" to keep from getting an ambiguous overload error.
+// The compiler will only cast int to long if none of the other templates matched.
+// Thanks to Boost serialization for this idea.
+//
+template<typename T>
+inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=PROTOCOL_VERSION)
+{
+ return a.GetSerializeSize((int)nType, nVersion);
+}
+
+template<typename Stream, typename T>
+inline void Serialize(Stream& os, const T& a, long nType, int nVersion=PROTOCOL_VERSION)
+{
+ a.Serialize(os, (int)nType, nVersion);
+}
+
+template<typename Stream, typename T>
+inline void Unserialize(Stream& is, T& a, long nType, int nVersion=PROTOCOL_VERSION)
+{
+ a.Unserialize(is, (int)nType, nVersion);
+}
+
+
+
+
+
+//
+// string
+//
+template<typename C>
+unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int)
+{
+ return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]);
+}
+
+template<typename Stream, typename C>
+void Serialize(Stream& os, const std::basic_string<C>& str, int, int)
+{
+ WriteCompactSize(os, str.size());
+ if (!str.empty())
+ os.write((char*)&str[0], str.size() * sizeof(str[0]));
+}
+
+template<typename Stream, typename C>
+void Unserialize(Stream& is, std::basic_string<C>& str, int, int)
+{
+ unsigned int nSize = ReadCompactSize(is);
+ str.resize(nSize);
+ if (nSize != 0)
+ is.read((char*)&str[0], nSize * sizeof(str[0]));
+}
+
+
+
+//
+// vector
+//
+template<typename T, typename A>
+unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
+{
+ return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T));
+}
+
+template<typename T, typename A>
+unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
+{
+ unsigned int nSize = GetSizeOfCompactSize(v.size());
+ for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
+ nSize += GetSerializeSize((*vi), nType, nVersion);
+ return nSize;
+}
+
+template<typename T, typename A>
+inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion)
+{
+ return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental<T>());
+}
+
+
+template<typename Stream, typename T, typename A>
+void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
+{
+ WriteCompactSize(os, v.size());
+ if (!v.empty())
+ os.write((char*)&v[0], v.size() * sizeof(T));
+}
+
+template<typename Stream, typename T, typename A>
+void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
+{
+ WriteCompactSize(os, v.size());
+ for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
+ ::Serialize(os, (*vi), nType, nVersion);
+}
+
+template<typename Stream, typename T, typename A>
+inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion)
+{
+ Serialize_impl(os, v, nType, nVersion, boost::is_fundamental<T>());
+}
+
+
+template<typename Stream, typename T, typename A>
+void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
+{
+ //unsigned int nSize = ReadCompactSize(is);
+ //v.resize(nSize);
+ //is.read((char*)&v[0], nSize * sizeof(T));
+
+ // Limit size per read so bogus size value won't cause out of memory
+ v.clear();
+ unsigned int nSize = ReadCompactSize(is);
+ unsigned int i = 0;
+ while (i < nSize)
+ {
+ unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
+ v.resize(i + blk);
+ is.read((char*)&v[i], blk * sizeof(T));
+ i += blk;
+ }
+}
+
+template<typename Stream, typename T, typename A>
+void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
+{
+ //unsigned int nSize = ReadCompactSize(is);
+ //v.resize(nSize);
+ //for (std::vector<T, A>::iterator vi = v.begin(); vi != v.end(); ++vi)
+ // Unserialize(is, (*vi), nType, nVersion);
+
+ v.clear();
+ unsigned int nSize = ReadCompactSize(is);
+ unsigned int i = 0;
+ unsigned int nMid = 0;
+ while (nMid < nSize)
+ {
+ nMid += 5000000 / sizeof(T);
+ if (nMid > nSize)
+ nMid = nSize;
+ v.resize(nMid);
+ for (; i < nMid; i++)
+ Unserialize(is, v[i], nType, nVersion);
+ }
+}
+
+template<typename Stream, typename T, typename A>
+inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion)
+{
+ Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental<T>());
+}
+
+
+
+//
+// others derived from vector
+//
+inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion)
+{
+ return GetSerializeSize((const std::vector<unsigned char>&)v, nType, nVersion);
+}
+
+template<typename Stream>
+void Serialize(Stream& os, const CScript& v, int nType, int nVersion)
+{
+ Serialize(os, (const std::vector<unsigned char>&)v, nType, nVersion);
+}
+
+template<typename Stream>
+void Unserialize(Stream& is, CScript& v, int nType, int nVersion)
+{
+ Unserialize(is, (std::vector<unsigned char>&)v, nType, nVersion);
+}
+
+
+
+//
+// pair
+//
+template<typename K, typename T>
+unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion)
+{
+ return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion);
+}
+
+template<typename Stream, typename K, typename T>
+void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion)
+{
+ Serialize(os, item.first, nType, nVersion);
+ Serialize(os, item.second, nType, nVersion);
+}
+
+template<typename Stream, typename K, typename T>
+void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion)
+{
+ Unserialize(is, item.first, nType, nVersion);
+ Unserialize(is, item.second, nType, nVersion);
+}
+
+
+
+//
+// 3 tuple
+//
+template<typename T0, typename T1, typename T2>
+unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion)
+{
+ unsigned int nSize = 0;
+ nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion);
+ nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion);
+ nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion);
+ return nSize;
+}
+
+template<typename Stream, typename T0, typename T1, typename T2>
+void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion)
+{
+ Serialize(os, boost::get<0>(item), nType, nVersion);
+ Serialize(os, boost::get<1>(item), nType, nVersion);
+ Serialize(os, boost::get<2>(item), nType, nVersion);
+}
+
+template<typename Stream, typename T0, typename T1, typename T2>
+void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion)
+{
+ Unserialize(is, boost::get<0>(item), nType, nVersion);
+ Unserialize(is, boost::get<1>(item), nType, nVersion);
+ Unserialize(is, boost::get<2>(item), nType, nVersion);
+}
+
+
+
+//
+// 4 tuple
+//
+template<typename T0, typename T1, typename T2, typename T3>
+unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion)
+{
+ unsigned int nSize = 0;
+ nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion);
+ nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion);
+ nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion);
+ nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion);
+ return nSize;
+}
+
+template<typename Stream, typename T0, typename T1, typename T2, typename T3>
+void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion)
+{
+ Serialize(os, boost::get<0>(item), nType, nVersion);
+ Serialize(os, boost::get<1>(item), nType, nVersion);
+ Serialize(os, boost::get<2>(item), nType, nVersion);
+ Serialize(os, boost::get<3>(item), nType, nVersion);
+}
+
+template<typename Stream, typename T0, typename T1, typename T2, typename T3>
+void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion)
+{
+ Unserialize(is, boost::get<0>(item), nType, nVersion);
+ Unserialize(is, boost::get<1>(item), nType, nVersion);
+ Unserialize(is, boost::get<2>(item), nType, nVersion);
+ Unserialize(is, boost::get<3>(item), nType, nVersion);
+}
+
+
+
+//
+// map
+//
+template<typename K, typename T, typename Pred, typename A>
+unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion)
+{
+ unsigned int nSize = GetSizeOfCompactSize(m.size());
+ for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
+ nSize += GetSerializeSize((*mi), nType, nVersion);
+ return nSize;
+}
+
+template<typename Stream, typename K, typename T, typename Pred, typename A>
+void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion)
+{
+ WriteCompactSize(os, m.size());
+ for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
+ Serialize(os, (*mi), nType, nVersion);
+}
+
+template<typename Stream, typename K, typename T, typename Pred, typename A>
+void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion)
+{
+ m.clear();
+ unsigned int nSize = ReadCompactSize(is);
+ typename std::map<K, T, Pred, A>::iterator mi = m.begin();
+ for (unsigned int i = 0; i < nSize; i++)
+ {
+ std::pair<K, T> item;
+ Unserialize(is, item, nType, nVersion);
+ mi = m.insert(mi, item);
+ }
+}
+
+
+
+//
+// set
+//
+template<typename K, typename Pred, typename A>
+unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion)
+{
+ unsigned int nSize = GetSizeOfCompactSize(m.size());
+ for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)
+ nSize += GetSerializeSize((*it), nType, nVersion);
+ return nSize;
+}
+
+template<typename Stream, typename K, typename Pred, typename A>
+void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion)
+{
+ WriteCompactSize(os, m.size());
+ for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)
+ Serialize(os, (*it), nType, nVersion);
+}
+
+template<typename Stream, typename K, typename Pred, typename A>
+void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion)
+{
+ m.clear();
+ unsigned int nSize = ReadCompactSize(is);
+ typename std::set<K, Pred, A>::iterator it = m.begin();
+ for (unsigned int i = 0; i < nSize; i++)
+ {
+ K key;
+ Unserialize(is, key, nType, nVersion);
+ it = m.insert(it, key);
+ }
+}
+
+
+
+//
+// Support for IMPLEMENT_SERIALIZE and READWRITE macro
+//
+class CSerActionGetSerializeSize { };
+class CSerActionSerialize { };
+class CSerActionUnserialize { };
+
+template<typename Stream, typename T>
+inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action)
+{
+ return ::GetSerializeSize(obj, nType, nVersion);
+}
+
+template<typename Stream, typename T>
+inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action)
+{
+ ::Serialize(s, obj, nType, nVersion);
+ return 0;
+}
+
+template<typename Stream, typename T>
+inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action)
+{
+ ::Unserialize(s, obj, nType, nVersion);
+ return 0;
+}
+
+struct ser_streamplaceholder
+{
+ int nType;
+ int nVersion;
+};
+
+
+
+
+
+
+
+
+
+//
+// Allocator that locks its contents from being paged
+// out of memory and clears its contents before deletion.
+//
+template<typename T>
+struct secure_allocator : public std::allocator<T>
+{
+ // MSVC8 default copy constructor is broken
+ typedef std::allocator<T> base;
+ typedef typename base::size_type size_type;
+ typedef typename base::difference_type difference_type;
+ typedef typename base::pointer pointer;
+ typedef typename base::const_pointer const_pointer;
+ typedef typename base::reference reference;
+ typedef typename base::const_reference const_reference;
+ typedef typename base::value_type value_type;
+ secure_allocator() throw() {}
+ secure_allocator(const secure_allocator& a) throw() : base(a) {}
+ template <typename U>
+ secure_allocator(const secure_allocator<U>& a) throw() : base(a) {}
+ ~secure_allocator() throw() {}
+ template<typename _Other> struct rebind
+ { typedef secure_allocator<_Other> other; };
+
+ T* allocate(std::size_t n, const void *hint = 0)
+ {
+ T *p;
+ p = std::allocator<T>::allocate(n, hint);
+ if (p != NULL)
+ mlock(p, sizeof(T) * n);
+ return p;
+ }
+
+ void deallocate(T* p, std::size_t n)
+ {
+ if (p != NULL)
+ {
+ memset(p, 0, sizeof(T) * n);
+ munlock(p, sizeof(T) * n);
+ }
+ std::allocator<T>::deallocate(p, n);
+ }
+};
+
+
+
+//
+// Double ended buffer combining vector and stream-like interfaces.
+// >> and << read and write unformatted data using the above serialization templates.
+// Fills with data in linear time; some stringstream implementations take N^2 time.
+//
+class CDataStream
+{
+protected:
+ typedef std::vector<char, secure_allocator<char> > vector_type;
+ vector_type vch;
+ unsigned int nReadPos;
+ short state;
+ short exceptmask;
+public:
+ int nType;
+ int nVersion;
+
+ typedef vector_type::allocator_type allocator_type;
+ typedef vector_type::size_type size_type;
+ typedef vector_type::difference_type difference_type;
+ typedef vector_type::reference reference;
+ typedef vector_type::const_reference const_reference;
+ typedef vector_type::value_type value_type;
+ typedef vector_type::iterator iterator;
+ typedef vector_type::const_iterator const_iterator;
+ typedef vector_type::reverse_iterator reverse_iterator;
+
+ explicit CDataStream(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION)
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+ CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend)
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1300
+ CDataStream(const char* pbegin, const char* pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend)
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+#endif
+
+ CDataStream(const vector_type& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end())
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+ CDataStream(const std::vector<char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end())
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+ CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0])
+ {
+ Init(nTypeIn, nVersionIn);
+ }
+
+ void Init(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION)
+ {
+ nReadPos = 0;
+ nType = nTypeIn;
+ nVersion = nVersionIn;
+ state = 0;
+ exceptmask = std::ios::badbit | std::ios::failbit;
+ }
+
+ CDataStream& operator+=(const CDataStream& b)
+ {
+ vch.insert(vch.end(), b.begin(), b.end());
+ return *this;
+ }
+
+ friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
+ {
+ CDataStream ret = a;
+ ret += b;
+ return (ret);
+ }
+
+ std::string str() const
+ {
+ return (std::string(begin(), end()));
+ }
+
+
+ //
+ // Vector subset
+ //
+ const_iterator begin() const { return vch.begin() + nReadPos; }
+ iterator begin() { return vch.begin() + nReadPos; }
+ const_iterator end() const { return vch.end(); }
+ iterator end() { return vch.end(); }
+ size_type size() const { return vch.size() - nReadPos; }
+ bool empty() const { return vch.size() == nReadPos; }
+ void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
+ void reserve(size_type n) { vch.reserve(n + nReadPos); }
+ const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
+ reference operator[](size_type pos) { return vch[pos + nReadPos]; }
+ void clear() { vch.clear(); nReadPos = 0; }
+ iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); }
+ void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); }
+
+ void insert(iterator it, const_iterator first, const_iterator last)
+ {
+ if (it == vch.begin() + nReadPos && last - first <= nReadPos)
+ {
+ // special case for inserting at the front when there's room
+ nReadPos -= (last - first);
+ memcpy(&vch[nReadPos], &first[0], last - first);
+ }
+ else
+ vch.insert(it, first, last);
+ }
+
+ void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
+ {
+ if (it == vch.begin() + nReadPos && last - first <= nReadPos)
+ {
+ // special case for inserting at the front when there's room
+ nReadPos -= (last - first);
+ memcpy(&vch[nReadPos], &first[0], last - first);
+ }
+ else
+ vch.insert(it, first, last);
+ }
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1300
+ void insert(iterator it, const char* first, const char* last)
+ {
+ if (it == vch.begin() + nReadPos && last - first <= nReadPos)
+ {
+ // special case for inserting at the front when there's room
+ nReadPos -= (last - first);
+ memcpy(&vch[nReadPos], &first[0], last - first);
+ }
+ else
+ vch.insert(it, first, last);
+ }
+#endif
+
+ iterator erase(iterator it)
+ {
+ if (it == vch.begin() + nReadPos)
+ {
+ // special case for erasing from the front
+ if (++nReadPos >= vch.size())
+ {
+ // whenever we reach the end, we take the opportunity to clear the buffer
+ nReadPos = 0;
+ return vch.erase(vch.begin(), vch.end());
+ }
+ return vch.begin() + nReadPos;
+ }
+ else
+ return vch.erase(it);
+ }
+
+ iterator erase(iterator first, iterator last)
+ {
+ if (first == vch.begin() + nReadPos)
+ {
+ // special case for erasing from the front
+ if (last == vch.end())
+ {
+ nReadPos = 0;
+ return vch.erase(vch.begin(), vch.end());
+ }
+ else
+ {
+ nReadPos = (last - vch.begin());
+ return last;
+ }
+ }
+ else
+ return vch.erase(first, last);
+ }
+
+ inline void Compact()
+ {
+ vch.erase(vch.begin(), vch.begin() + nReadPos);
+ nReadPos = 0;
+ }
+
+ bool Rewind(size_type n)
+ {
+ // Rewind by n characters if the buffer hasn't been compacted yet
+ if (n > nReadPos)
+ return false;
+ nReadPos -= n;
+ return true;
+ }
+
+
+ //
+ // Stream subset
+ //
+ void setstate(short bits, const char* psz)
+ {
+ state |= bits;
+ if (state & exceptmask)
+ throw std::ios_base::failure(psz);
+ }
+
+ bool eof() const { return size() == 0; }
+ bool fail() const { return state & (std::ios::badbit | std::ios::failbit); }
+ bool good() const { return !eof() && (state == 0); }
+ void clear(short n) { state = n; } // name conflict with vector clear()
+ short exceptions() { return exceptmask; }
+ short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; }
+ CDataStream* rdbuf() { return this; }
+ int in_avail() { return size(); }
+
+ void SetType(int n) { nType = n; }
+ int GetType() { return nType; }
+ void SetVersion(int n) { nVersion = n; }
+ int GetVersion() { return nVersion; }
+ void ReadVersion() { *this >> nVersion; }
+ void WriteVersion() { *this << nVersion; }
+
+ CDataStream& read(char* pch, int nSize)
+ {
+ // Read from the beginning of the buffer
+ assert(nSize >= 0);
+ unsigned int nReadPosNext = nReadPos + nSize;
+ if (nReadPosNext >= vch.size())
+ {
+ if (nReadPosNext > vch.size())
+ {
+ setstate(std::ios::failbit, "CDataStream::read() : end of data");
+ memset(pch, 0, nSize);
+ nSize = vch.size() - nReadPos;
+ }
+ memcpy(pch, &vch[nReadPos], nSize);
+ nReadPos = 0;
+ vch.clear();
+ return (*this);
+ }
+ memcpy(pch, &vch[nReadPos], nSize);
+ nReadPos = nReadPosNext;
+ return (*this);
+ }
+
+ CDataStream& ignore(int nSize)
+ {
+ // Ignore from the beginning of the buffer
+ assert(nSize >= 0);
+ unsigned int nReadPosNext = nReadPos + nSize;
+ if (nReadPosNext >= vch.size())
+ {
+ if (nReadPosNext > vch.size())
+ {
+ setstate(std::ios::failbit, "CDataStream::ignore() : end of data");
+ nSize = vch.size() - nReadPos;
+ }
+ nReadPos = 0;
+ vch.clear();
+ return (*this);
+ }
+ nReadPos = nReadPosNext;
+ return (*this);
+ }
+
+ CDataStream& write(const char* pch, int nSize)
+ {
+ // Write to the end of the buffer
+ assert(nSize >= 0);
+ vch.insert(vch.end(), pch, pch + nSize);
+ return (*this);
+ }
+
+ template<typename Stream>
+ void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
+ {
+ // Special case: stream << stream concatenates like stream += stream
+ if (!vch.empty())
+ s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
+ }
+
+ template<typename T>
+ unsigned int GetSerializeSize(const T& obj)
+ {
+ // Tells the size of the object if serialized to this stream
+ return ::GetSerializeSize(obj, nType, nVersion);
+ }
+
+ template<typename T>
+ CDataStream& operator<<(const T& obj)
+ {
+ // Serialize to this stream
+ ::Serialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+
+ template<typename T>
+ CDataStream& operator>>(T& obj)
+ {
+ // Unserialize from this stream
+ ::Unserialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+};
+
+#ifdef TESTCDATASTREAM
+// VC6sp6
+// CDataStream:
+// n=1000 0 seconds
+// n=2000 0 seconds
+// n=4000 0 seconds
+// n=8000 0 seconds
+// n=16000 0 seconds
+// n=32000 0 seconds
+// n=64000 1 seconds
+// n=128000 1 seconds
+// n=256000 2 seconds
+// n=512000 4 seconds
+// n=1024000 8 seconds
+// n=2048000 16 seconds
+// n=4096000 32 seconds
+// stringstream:
+// n=1000 1 seconds
+// n=2000 1 seconds
+// n=4000 13 seconds
+// n=8000 87 seconds
+// n=16000 400 seconds
+// n=32000 1660 seconds
+// n=64000 6749 seconds
+// n=128000 27241 seconds
+// n=256000 109804 seconds
+#include <iostream>
+int main(int argc, char *argv[])
+{
+ vector<unsigned char> vch(0xcc, 250);
+ printf("CDataStream:\n");
+ for (int n = 1000; n <= 4500000; n *= 2)
+ {
+ CDataStream ss;
+ time_t nStart = time(NULL);
+ for (int i = 0; i < n; i++)
+ ss.write((char*)&vch[0], vch.size());
+ printf("n=%-10d %d seconds\n", n, time(NULL) - nStart);
+ }
+ printf("stringstream:\n");
+ for (int n = 1000; n <= 4500000; n *= 2)
+ {
+ stringstream ss;
+ time_t nStart = time(NULL);
+ for (int i = 0; i < n; i++)
+ ss.write((char*)&vch[0], vch.size());
+ printf("n=%-10d %d seconds\n", n, time(NULL) - nStart);
+ }
+}
+#endif
+
+
+
+
+
+
+
+
+
+
+//
+// Automatic closing wrapper for FILE*
+// - Will automatically close the file when it goes out of scope if not null.
+// - If you're returning the file pointer, return file.release().
+// - If you need to close the file early, use file.fclose() instead of fclose(file).
+//
+class CAutoFile
+{
+protected:
+ FILE* file;
+ short state;
+ short exceptmask;
+public:
+ int nType;
+ int nVersion;
+
+ typedef FILE element_type;
+
+ CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=PROTOCOL_VERSION)
+ {
+ file = filenew;
+ nType = nTypeIn;
+ nVersion = nVersionIn;
+ state = 0;
+ exceptmask = std::ios::badbit | std::ios::failbit;
+ }
+
+ ~CAutoFile()
+ {
+ fclose();
+ }
+
+ void fclose()
+ {
+ if (file != NULL && file != stdin && file != stdout && file != stderr)
+ ::fclose(file);
+ file = NULL;
+ }
+
+ FILE* release() { FILE* ret = file; file = NULL; return ret; }
+ operator FILE*() { return file; }
+ FILE* operator->() { return file; }
+ FILE& operator*() { return *file; }
+ FILE** operator&() { return &file; }
+ FILE* operator=(FILE* pnew) { return file = pnew; }
+ bool operator!() { return (file == NULL); }
+
+
+ //
+ // Stream subset
+ //
+ void setstate(short bits, const char* psz)
+ {
+ state |= bits;
+ if (state & exceptmask)
+ throw std::ios_base::failure(psz);
+ }
+
+ bool fail() const { return state & (std::ios::badbit | std::ios::failbit); }
+ bool good() const { return state == 0; }
+ void clear(short n = 0) { state = n; }
+ short exceptions() { return exceptmask; }
+ short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; }
+
+ void SetType(int n) { nType = n; }
+ int GetType() { return nType; }
+ void SetVersion(int n) { nVersion = n; }
+ int GetVersion() { return nVersion; }
+ void ReadVersion() { *this >> nVersion; }
+ void WriteVersion() { *this << nVersion; }
+
+ CAutoFile& read(char* pch, int nSize)
+ {
+ if (!file)
+ throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
+ if (fread(pch, 1, nSize, file) != nSize)
+ setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
+ return (*this);
+ }
+
+ CAutoFile& write(const char* pch, int nSize)
+ {
+ if (!file)
+ throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
+ if (fwrite(pch, 1, nSize, file) != nSize)
+ setstate(std::ios::failbit, "CAutoFile::write : write failed");
+ return (*this);
+ }
+
+ template<typename T>
+ unsigned int GetSerializeSize(const T& obj)
+ {
+ // Tells the size of the object if serialized to this stream
+ return ::GetSerializeSize(obj, nType, nVersion);
+ }
+
+ template<typename T>
+ CAutoFile& operator<<(const T& obj)
+ {
+ // Serialize to this stream
+ if (!file)
+ throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL");
+ ::Serialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+
+ template<typename T>
+ CAutoFile& operator>>(T& obj)
+ {
+ // Unserialize from this stream
+ if (!file)
+ throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL");
+ ::Unserialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+};
+
+#endif
--- /dev/null
+/*
+ * 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
--- /dev/null
+#!/usr/bin/perl
+
+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";
--- /dev/null
+// 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
--- /dev/null
+#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());
+}
--- /dev/null
+#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