├── .gitignore ├── bitcoin.h ├── Makefile ├── dns.h ├── combine.pl ├── test.pl ├── compat.h ├── README ├── strlcpy.h ├── util.h ├── protocol.h ├── protocol.cpp ├── db.cpp ├── netbase.h ├── util.cpp ├── bitcoin.cpp ├── db.h ├── dns.cpp ├── main.cpp ├── uint256.h ├── netbase.cpp └── serialize.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | dnsseed* 3 | dnsstats.log 4 | -------------------------------------------------------------------------------- /bitcoin.h: -------------------------------------------------------------------------------- 1 | #ifndef _BITCOIN_H_ 2 | #define _BITCOIN_H_ 1 3 | 4 | #include "protocol.h" 5 | 6 | bool TestNode(const CService &cip, int &ban, int &client, std::string &clientSV, int &blocks, std::vector* vAddr, uint64_t& services); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS = -O3 -g0 -march=native 2 | LDFLAGS = $(CXXFLAGS) 3 | 4 | dnsseed: dns.o bitcoin.o netbase.o protocol.o db.o main.o util.o 5 | g++ -pthread $(LDFLAGS) -o dnsseed dns.o bitcoin.o netbase.o protocol.o db.o main.o util.o -lcrypto 6 | 7 | %.o: %.cpp *.h 8 | g++ -std=c++11 -pthread $(CXXFLAGS) -Wall -Wno-unused -Wno-sign-compare -Wno-reorder -Wno-comment -c -o $@ $< 9 | -------------------------------------------------------------------------------- /dns.h: -------------------------------------------------------------------------------- 1 | #ifndef _DNS_H_ 2 | #define _DNS_H_ 1 3 | 4 | #include 5 | 6 | struct addr_t { 7 | int v; 8 | union { 9 | unsigned char v4[4]; 10 | unsigned char v6[16]; 11 | } data; 12 | }; 13 | 14 | struct dns_opt_t { 15 | int port; 16 | int datattl; 17 | int nsttl; 18 | const char *host; 19 | const char *ns; 20 | const char *mbox; 21 | int (*cb)(void *opt, char *requested_hostname, addr_t *addr, int max, int ipv4, int ipv6); 22 | // stats 23 | uint64_t nRequests; 24 | }; 25 | 26 | int dnsserver(dns_opt_t *opt); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /combine.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | sub loadFile { 6 | my ($file) = @_; 7 | my %ret; 8 | my $max = 0; 9 | open FILE,$file; 10 | while () { 11 | my ($addr,$p2h,$p8h,$p1d,$p1w,$p1m) = split(/\s+/,$_); 12 | if ($p1m =~ /\A([1-9.]+)%\Z/) { 13 | my $x = $1*0.01; 14 | $max=$x if ($x > $max); 15 | $ret{$addr} = $x; 16 | } 17 | } 18 | for my $k (keys %ret) { 19 | $ret{$k} /= $max; 20 | } 21 | close FILE; 22 | return \%ret; 23 | } 24 | 25 | sub merge { 26 | my ($a,$b) = @_; 27 | return 1-(1-$a)*(1-$b); 28 | } 29 | 30 | sub combine { 31 | my ($f1,$f2) = @_; 32 | my %ret; 33 | for my $k1 (keys %{$f1}) { 34 | if (defined $f2->{$k1}) { 35 | $ret{$k1} = merge($f1->{$k1}, $f2->{$k1}); 36 | } else { 37 | $ret{$k1} = merge($f1->{$k1}, 0); 38 | } 39 | } 40 | for my $k2 (keys %{$f2}) { 41 | if (!defined $f1->{$k2}) { 42 | $ret{$k2} = merge(0, $f2->{$k2}); 43 | } 44 | } 45 | return \%ret; 46 | } 47 | 48 | my $res; 49 | my $n=0; 50 | for my $file (@ARGV) { 51 | my $r = loadFile($file); 52 | if ($res) { 53 | $res = combine($res,$r); 54 | } else { 55 | $res = $r; 56 | } 57 | $n++; 58 | } 59 | 60 | for my $addr (sort { $res->{$b} <=> $res->{$a} } (keys %{$res})) { 61 | if ($addr =~ /\A(\d+)\.(\d+)\.(\d+)\.(\d+):8333/) { 62 | my $a = $1*0x1000000 + $2*0x10000 + $3*0x100 + $4; 63 | printf "0x%08x %s %g%%\n",$a,$addr,(1-((1-$res->{$addr}) ** (1/$n)))*100; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use threads; 4 | use threads::shared; 5 | use bytes; 6 | use IO::Socket; 7 | use strict; 8 | 9 | my @dom = ("seed","bitcoin","sipa","be"); 10 | 11 | my $run :shared = 1; 12 | 13 | sub go { 14 | my ($idx) = @_; 15 | 16 | my $runs = 0; 17 | 18 | my $sock = IO::Socket::INET->new( 19 | Proto => 'udp', 20 | PeerPort => 53, 21 | PeerAddr => "vps.sipa.be", 22 | ) or die "Could not create socket: $!\n"; 23 | 24 | while($run) { 25 | 26 | my $id = int(rand(65536)); 27 | my $qr = 0; 28 | my $opcode = 0; 29 | my $aa = 0; 30 | my $tc = 0; 31 | my $rd = 0; 32 | my $ra = 0; 33 | my $z = 0; 34 | my $rcode = 0; 35 | my $qdcount = 1; 36 | my $ancount = 0; 37 | my $nscount = 0; 38 | my $arcount = 0; 39 | 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); 40 | my $qtype = 1; # A record 41 | my $qclass = 1; # IN class 42 | my $query = (join("", map { chr(length($_)) . $_ } (@dom,""))) . pack('nn',$qtype,$qclass); 43 | my $msg = $header . $query; 44 | $sock->send($msg); 45 | my $resp; 46 | $runs++ if ($sock->recv($resp, 512, 0)); 47 | 48 | # $sock->close(); 49 | } 50 | return $runs; 51 | } 52 | 53 | my @threads; 54 | 55 | for my $i (0..500) { 56 | $threads[$i] = threads->create(\&go, $i); 57 | } 58 | 59 | sleep 10; 60 | 61 | $run=0; 62 | my $runs = 0; 63 | foreach my $thr (@threads) { 64 | $runs += $thr->join(); 65 | } 66 | 67 | print "$runs runs\n"; 68 | -------------------------------------------------------------------------------- /compat.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto 2 | // Copyright (c) 2009-2012 The Bitcoin developers 3 | // Distributed under the MIT/X11 software license, see the accompanying 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | #ifndef _BITCOIN_COMPAT_H 6 | #define _BITCOIN_COMPAT_H 1 7 | 8 | #ifdef WIN32 9 | #define _WIN32_WINNT 0x0501 10 | #define WIN32_LEAN_AND_MEAN 1 11 | #ifndef NOMINMAX 12 | #define NOMINMAX 13 | #endif 14 | #include 15 | #include 16 | #include 17 | #else 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #endif 27 | 28 | typedef u_int SOCKET; 29 | #ifdef __APPLE__ 30 | #define MSG_NOSIGNAL 0 31 | #endif 32 | #ifdef WIN32 33 | #define MSG_NOSIGNAL 0 34 | #define MSG_DONTWAIT 0 35 | typedef int socklen_t; 36 | #else 37 | #include "errno.h" 38 | #define WSAGetLastError() errno 39 | #define WSAEINVAL EINVAL 40 | #define WSAEALREADY EALREADY 41 | #define WSAEWOULDBLOCK EWOULDBLOCK 42 | #define WSAEMSGSIZE EMSGSIZE 43 | #define WSAEINTR EINTR 44 | #define WSAEINPROGRESS EINPROGRESS 45 | #define WSAEADDRINUSE EADDRINUSE 46 | #define WSAENOTSOCK EBADF 47 | #define INVALID_SOCKET (SOCKET)(~0) 48 | #define SOCKET_ERROR -1 49 | #endif 50 | 51 | inline int myclosesocket(SOCKET& hSocket) 52 | { 53 | if (hSocket == INVALID_SOCKET) 54 | return WSAENOTSOCK; 55 | #ifdef WIN32 56 | int ret = closesocket(hSocket); 57 | #else 58 | int ret = close(hSocket); 59 | #endif 60 | hSocket = INVALID_SOCKET; 61 | return ret; 62 | } 63 | #define closesocket(s) myclosesocket(s) 64 | 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | bitcoin-seeder 2 | ============== 3 | 4 | Bitcoin-seeder is a crawler for the Bitcoin network, which exposes a list 5 | of reliable nodes via a built-in DNS server. 6 | 7 | Features: 8 | * regularly revisits known nodes to check their availability 9 | * bans nodes after enough failures, or bad behaviour 10 | * accepts nodes down to v0.3.19 to request new IP addresses from, 11 | but only reports good post-v0.3.24 nodes. 12 | * keeps statistics over (exponential) windows of 2 hours, 8 hours, 13 | 1 day and 1 week, to base decisions on. 14 | * very low memory (a few tens of megabytes) and cpu requirements. 15 | * crawlers run in parallel (by default 24 threads simultaneously). 16 | 17 | REQUIREMENTS 18 | ------------ 19 | 20 | $ sudo apt-get install build-essential libboost-all-dev libssl-dev 21 | 22 | USAGE 23 | ----- 24 | 25 | Assuming you want to run a dns seed on dnsseed.example.com, you will 26 | need an authorative NS record in example.com's domain record, pointing 27 | to for example vps.example.com: 28 | 29 | $ dig -t NS dnsseed.example.com 30 | 31 | ;; ANSWER SECTION 32 | dnsseed.example.com. 86400 IN NS vps.example.com. 33 | 34 | On the system vps.example.com, you can now run dnsseed: 35 | 36 | ./dnsseed -h dnsseed.example.com -n vps.example.com 37 | 38 | If you want the DNS server to report SOA records, please provide an 39 | e-mail address (with the @ part replaced by .) using -m. 40 | 41 | COMPILING 42 | --------- 43 | Compiling will require boost and ssl. On debian systems, these are provided 44 | by `libboost-dev` and `libssl-dev` respectively. 45 | 46 | $ make 47 | 48 | This will produce the `dnsseed` binary. 49 | 50 | 51 | RUNNING AS NON-ROOT 52 | ------------------- 53 | 54 | Typically, you'll need root privileges to listen to port 53 (name service). 55 | 56 | One solution is using an iptables rule (Linux only) to redirect it to 57 | a non-privileged port: 58 | 59 | $ iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-port 5353 60 | 61 | If properly configured, this will allow you to run dnsseed in userspace, using 62 | the -p 5353 option. 63 | 64 | Another solution is allowing a binary to bind to ports < 1024 with setcap (IPv6 access-safe) 65 | 66 | $ setcap 'cap_net_bind_service=+ep' /path/to/dnsseed 67 | -------------------------------------------------------------------------------- /strlcpy.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998 Todd C. Miller 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef BITCOIN_STRLCPY_H 17 | #define BITCOIN_STRLCPY_H 18 | 19 | #include 20 | #include 21 | 22 | /* 23 | * Copy src to string dst of size siz. At most siz-1 characters 24 | * will be copied. Always NUL terminates (unless siz == 0). 25 | * Returns strlen(src); if retval >= siz, truncation occurred. 26 | */ 27 | inline size_t strlcpy(char *dst, const char *src, size_t siz) 28 | { 29 | char *d = dst; 30 | const char *s = src; 31 | size_t n = siz; 32 | 33 | /* Copy as many bytes as will fit */ 34 | if (n != 0) 35 | { 36 | while (--n != 0) 37 | { 38 | if ((*d++ = *s++) == '\0') 39 | break; 40 | } 41 | } 42 | 43 | /* Not enough room in dst, add NUL and traverse rest of src */ 44 | if (n == 0) 45 | { 46 | if (siz != 0) 47 | *d = '\0'; /* NUL-terminate dst */ 48 | while (*s++) 49 | ; 50 | } 51 | 52 | return(s - src - 1); /* count does not include NUL */ 53 | } 54 | 55 | /* 56 | * Appends src to string dst of size siz (unlike strncat, siz is the 57 | * full size of dst, not space left). At most siz-1 characters 58 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). 59 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). 60 | * If retval >= siz, truncation occurred. 61 | */ 62 | inline size_t strlcat(char *dst, const char *src, size_t siz) 63 | { 64 | char *d = dst; 65 | const char *s = src; 66 | size_t n = siz; 67 | size_t dlen; 68 | 69 | /* Find the end of dst and adjust bytes left but don't go past end */ 70 | while (n-- != 0 && *d != '\0') 71 | d++; 72 | dlen = d - dst; 73 | n = siz - dlen; 74 | 75 | if (n == 0) 76 | return(dlen + strlen(s)); 77 | while (*s != '\0') 78 | { 79 | if (n != 1) 80 | { 81 | *d++ = *s; 82 | n--; 83 | } 84 | s++; 85 | } 86 | *d = '\0'; 87 | 88 | return(dlen + (s - src)); /* count does not include NUL */ 89 | } 90 | #endif 91 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H_ 2 | #define _UTIL_H_ 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "uint256.h" 10 | 11 | #define loop for (;;) 12 | #define BEGIN(a) ((char*)&(a)) 13 | #define END(a) ((char*)&((&(a))[1])) 14 | #define UBEGIN(a) ((unsigned char*)&(a)) 15 | #define UEND(a) ((unsigned char*)&((&(a))[1])) 16 | #define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) 17 | 18 | #define WSAGetLastError() errno 19 | #define WSAEINVAL EINVAL 20 | #define WSAEALREADY EALREADY 21 | #define WSAEWOULDBLOCK EWOULDBLOCK 22 | #define WSAEMSGSIZE EMSGSIZE 23 | #define WSAEINTR EINTR 24 | #define WSAEINPROGRESS EINPROGRESS 25 | #define WSAEADDRINUSE EADDRINUSE 26 | #define WSAENOTSOCK EBADF 27 | #define INVALID_SOCKET (SOCKET)(~0) 28 | #define SOCKET_ERROR -1 29 | 30 | // Wrapper to automatically initialize mutex 31 | class CCriticalSection 32 | { 33 | protected: 34 | pthread_rwlock_t mutex; 35 | public: 36 | explicit CCriticalSection() { pthread_rwlock_init(&mutex, NULL); } 37 | ~CCriticalSection() { pthread_rwlock_destroy(&mutex); } 38 | void Enter(bool fShared = false) { 39 | if (fShared) { 40 | pthread_rwlock_rdlock(&mutex); 41 | } else { 42 | pthread_rwlock_wrlock(&mutex); 43 | } 44 | } 45 | void Leave() { pthread_rwlock_unlock(&mutex); } 46 | }; 47 | 48 | // Automatically leave critical section when leaving block, needed for exception safety 49 | class CCriticalBlock 50 | { 51 | protected: 52 | CCriticalSection* pcs; 53 | public: 54 | CCriticalBlock(CCriticalSection& cs, bool fShared = false) : pcs(&cs) { pcs->Enter(fShared); } 55 | operator bool() const { return true; } 56 | ~CCriticalBlock() { pcs->Leave(); } 57 | }; 58 | 59 | #define CRITICAL_BLOCK(cs) \ 60 | if (CCriticalBlock criticalblock = CCriticalBlock(cs)) 61 | 62 | #define SHARED_CRITICAL_BLOCK(cs) \ 63 | if (CCriticalBlock criticalblock = CCriticalBlock(cs, true)) 64 | 65 | template inline uint256 Hash(const T1 pbegin, const T1 pend) 66 | { 67 | static unsigned char pblank[1]; 68 | uint256 hash1; 69 | SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); 70 | uint256 hash2; 71 | SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); 72 | return hash2; 73 | } 74 | 75 | void static inline Sleep(int nMilliSec) { 76 | struct timespec wa; 77 | wa.tv_sec = nMilliSec/1000; 78 | wa.tv_nsec = (nMilliSec % 1000) * 1000000; 79 | nanosleep(&wa, NULL); 80 | } 81 | 82 | 83 | std::string vstrprintf(const std::string &format, va_list ap); 84 | 85 | std::string static inline strprintf(const std::string &format, ...) { 86 | va_list arg_ptr; 87 | va_start(arg_ptr, format); 88 | std::string ret = vstrprintf(format, arg_ptr); 89 | va_end(arg_ptr); 90 | return ret; 91 | } 92 | 93 | bool static inline error(std::string err, ...) { 94 | return false; 95 | } 96 | 97 | bool static inline my_printf(std::string err, ...) { 98 | return true; 99 | } 100 | 101 | std::vector DecodeBase32(const char* p, bool* pfInvalid = NULL); 102 | std::string DecodeBase32(const std::string& str); 103 | std::string EncodeBase32(const unsigned char* pch, size_t len); 104 | std::string EncodeBase32(const std::string& str); 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /protocol.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto 2 | // Copyright (c) 2011 The Bitcoin developers 3 | // Distributed under the MIT/X11 software license, see the accompanying 4 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | #ifndef __cplusplus 7 | # error This header can only be compiled as C++. 8 | #endif 9 | 10 | #ifndef __INCLUDED_PROTOCOL_H__ 11 | #define __INCLUDED_PROTOCOL_H__ 12 | 13 | #include "netbase.h" 14 | #include "serialize.h" 15 | #include 16 | #include "uint256.h" 17 | 18 | extern bool fTestNet; 19 | static inline unsigned short GetDefaultPort(const bool testnet = fTestNet) 20 | { 21 | return testnet ? 18333 : 8333; 22 | } 23 | 24 | // 25 | // Message header 26 | // (4) message start 27 | // (12) command 28 | // (4) size 29 | // (4) checksum 30 | 31 | extern unsigned char pchMessageStart[4]; 32 | 33 | class CMessageHeader 34 | { 35 | public: 36 | CMessageHeader(); 37 | CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn); 38 | 39 | std::string GetCommand() const; 40 | bool IsValid() const; 41 | 42 | IMPLEMENT_SERIALIZE 43 | ( 44 | READWRITE(FLATDATA(pchMessageStart)); 45 | READWRITE(FLATDATA(pchCommand)); 46 | READWRITE(nMessageSize); 47 | if (nVersion >= 209) 48 | READWRITE(nChecksum); 49 | ) 50 | 51 | // TODO: make private (improves encapsulation) 52 | public: 53 | enum { COMMAND_SIZE=12 }; 54 | char pchMessageStart[sizeof(::pchMessageStart)]; 55 | char pchCommand[COMMAND_SIZE]; 56 | unsigned int nMessageSize; 57 | unsigned int nChecksum; 58 | }; 59 | 60 | enum 61 | { 62 | NODE_NETWORK = (1 << 0), 63 | NODE_BLOOM = (1 << 2), 64 | NODE_WITNESS = (1 << 3), 65 | NODE_COMPACT_FILTERS = (1 << 6), 66 | NODE_NETWORK_LIMITED = (1 << 10), 67 | }; 68 | 69 | class CAddress : public CService 70 | { 71 | public: 72 | CAddress(); 73 | CAddress(CService ipIn, uint64 nServicesIn=NODE_NETWORK); 74 | 75 | void Init(); 76 | 77 | IMPLEMENT_SERIALIZE 78 | ( 79 | CAddress* pthis = const_cast(this); 80 | CService* pip = (CService*)pthis; 81 | if (fRead) 82 | pthis->Init(); 83 | if (nType & SER_DISK) 84 | READWRITE(nVersion); 85 | if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH))) 86 | READWRITE(nTime); 87 | READWRITE(nServices); 88 | READWRITE(*pip); 89 | ) 90 | 91 | void print() const; 92 | 93 | // TODO: make private (improves encapsulation) 94 | public: 95 | uint64 nServices; 96 | 97 | // disk and network only 98 | unsigned int nTime; 99 | }; 100 | 101 | class CInv 102 | { 103 | public: 104 | CInv(); 105 | CInv(int typeIn, const uint256& hashIn); 106 | CInv(const std::string& strType, const uint256& hashIn); 107 | 108 | IMPLEMENT_SERIALIZE 109 | ( 110 | READWRITE(type); 111 | READWRITE(hash); 112 | ) 113 | 114 | friend bool operator<(const CInv& a, const CInv& b); 115 | 116 | bool IsKnownType() const; 117 | const char* GetCommand() const; 118 | std::string ToString() const; 119 | void print() const; 120 | 121 | // TODO: make private (improves encapsulation) 122 | public: 123 | int type; 124 | uint256 hash; 125 | }; 126 | 127 | #endif // __INCLUDED_PROTOCOL_H__ 128 | -------------------------------------------------------------------------------- /protocol.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto 2 | // Copyright (c) 2011 The Bitcoin developers 3 | // Distributed under the MIT/X11 software license, see the accompanying 4 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | #include 7 | #include 8 | 9 | #include "protocol.h" 10 | #include "util.h" 11 | #include "netbase.h" 12 | 13 | 14 | #ifndef WIN32 15 | # include 16 | #endif 17 | 18 | static const char* ppszTypeName[] = 19 | { 20 | "ERROR", 21 | "tx", 22 | "block", 23 | }; 24 | 25 | unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 }; 26 | 27 | CMessageHeader::CMessageHeader() 28 | { 29 | memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); 30 | memset(pchCommand, 0, sizeof(pchCommand)); 31 | pchCommand[1] = 1; 32 | nMessageSize = -1; 33 | nChecksum = 0; 34 | } 35 | 36 | CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) 37 | { 38 | memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); 39 | int command_len = strlen(pszCommand); 40 | memcpy(pchCommand, pszCommand, command_len); 41 | memset(pchCommand + command_len, 0, COMMAND_SIZE - command_len); 42 | nMessageSize = nMessageSizeIn; 43 | nChecksum = 0; 44 | } 45 | 46 | std::string CMessageHeader::GetCommand() const 47 | { 48 | if (pchCommand[COMMAND_SIZE-1] == 0) 49 | return std::string(pchCommand, pchCommand + strlen(pchCommand)); 50 | else 51 | return std::string(pchCommand, pchCommand + COMMAND_SIZE); 52 | } 53 | 54 | bool CMessageHeader::IsValid() const 55 | { 56 | // Check start string 57 | if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0) 58 | return false; 59 | 60 | // Check the command string for errors 61 | for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++) 62 | { 63 | if (*p1 == 0) 64 | { 65 | // Must be all zeros after the first zero 66 | for (; p1 < pchCommand + COMMAND_SIZE; p1++) 67 | if (*p1 != 0) 68 | return false; 69 | } 70 | else if (*p1 < ' ' || *p1 > 0x7E) 71 | return false; 72 | } 73 | 74 | // Message size 75 | if (nMessageSize > MAX_SIZE) 76 | { 77 | printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize); 78 | return false; 79 | } 80 | 81 | return true; 82 | } 83 | 84 | 85 | 86 | CAddress::CAddress() : CService() 87 | { 88 | Init(); 89 | } 90 | 91 | CAddress::CAddress(CService ipIn, uint64 nServicesIn) : CService(ipIn) 92 | { 93 | Init(); 94 | nServices = nServicesIn; 95 | } 96 | 97 | void CAddress::Init() 98 | { 99 | nServices = NODE_NETWORK; 100 | nTime = 100000000; 101 | } 102 | 103 | void CAddress::print() const 104 | { 105 | printf("CAddress(%s)\n", ToString().c_str()); 106 | } 107 | 108 | CInv::CInv() 109 | { 110 | type = 0; 111 | hash = 0; 112 | } 113 | 114 | CInv::CInv(int typeIn, const uint256& hashIn) 115 | { 116 | type = typeIn; 117 | hash = hashIn; 118 | } 119 | 120 | CInv::CInv(const std::string& strType, const uint256& hashIn) 121 | { 122 | int i; 123 | for (i = 1; i < ARRAYLEN(ppszTypeName); i++) 124 | { 125 | if (strType == ppszTypeName[i]) 126 | { 127 | type = i; 128 | break; 129 | } 130 | } 131 | if (i == ARRAYLEN(ppszTypeName)) 132 | throw std::out_of_range("CInv::CInv(string, uint256) : unknown type"); 133 | hash = hashIn; 134 | } 135 | 136 | bool operator<(const CInv& a, const CInv& b) 137 | { 138 | return (a.type < b.type || (a.type == b.type && a.hash < b.hash)); 139 | } 140 | 141 | bool CInv::IsKnownType() const 142 | { 143 | return (type >= 1 && type < ARRAYLEN(ppszTypeName)); 144 | } 145 | 146 | const char* CInv::GetCommand() const 147 | { 148 | if (!IsKnownType()) 149 | throw std::out_of_range("CInv::GetCommand() : unknown type"); 150 | return ppszTypeName[type]; 151 | } 152 | 153 | std::string CInv::ToString() const 154 | { 155 | return "CInv()"; 156 | } 157 | 158 | void CInv::print() const 159 | { 160 | printf("CInv\n"); 161 | } 162 | -------------------------------------------------------------------------------- /db.cpp: -------------------------------------------------------------------------------- 1 | #include "db.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | void CAddrInfo::Update(bool good) { 7 | uint32_t now = time(NULL); 8 | if (ourLastTry == 0) 9 | ourLastTry = now - MIN_RETRY; 10 | int age = now - ourLastTry; 11 | lastTry = now; 12 | ourLastTry = now; 13 | total++; 14 | if (good) 15 | { 16 | success++; 17 | ourLastSuccess = now; 18 | } 19 | stat2H.Update(good, age, 3600*2); 20 | stat8H.Update(good, age, 3600*8); 21 | stat1D.Update(good, age, 3600*24); 22 | stat1W.Update(good, age, 3600*24*7); 23 | stat1M.Update(good, age, 3600*24*30); 24 | int ign = GetIgnoreTime(); 25 | if (ign && (ignoreTill==0 || ignoreTill < ign+now)) ignoreTill = ign+now; 26 | // 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, 27 | // 100.0 * stat2H.reliability, 100.0 * (stat2H.reliability + 1.0 - stat2H.weight), stat2H.count, 28 | // 100.0 * stat8H.reliability, 100.0 * (stat8H.reliability + 1.0 - stat8H.weight), stat8H.count, 29 | // 100.0 * stat1D.reliability, 100.0 * (stat1D.reliability + 1.0 - stat1D.weight), stat1D.count, 30 | // 100.0 * stat1W.reliability, 100.0 * (stat1W.reliability + 1.0 - stat1W.weight), stat1W.count); 31 | } 32 | 33 | bool CAddrDb::Get_(CServiceResult &ip, int &wait) { 34 | int64 now = time(NULL); 35 | int cont = 0; 36 | int tot = unkId.size() + ourId.size(); 37 | if (tot == 0) { 38 | wait = 5; 39 | return false; 40 | } 41 | do { 42 | int rnd = rand() % tot; 43 | int ret; 44 | if (rnd < unkId.size()) { 45 | set::iterator it = unkId.end(); it--; 46 | ret = *it; 47 | unkId.erase(it); 48 | } else { 49 | ret = ourId.front(); 50 | if (time(NULL) - idToInfo[ret].ourLastTry < MIN_RETRY) return false; 51 | ourId.pop_front(); 52 | } 53 | if (idToInfo[ret].ignoreTill && idToInfo[ret].ignoreTill < now) { 54 | ourId.push_back(ret); 55 | idToInfo[ret].ourLastTry = now; 56 | } else { 57 | ip.service = idToInfo[ret].ip; 58 | ip.ourLastSuccess = idToInfo[ret].ourLastSuccess; 59 | break; 60 | } 61 | } while(1); 62 | nDirty++; 63 | return true; 64 | } 65 | 66 | int CAddrDb::Lookup_(const CService &ip) { 67 | if (ipToId.count(ip)) 68 | return ipToId[ip]; 69 | return -1; 70 | } 71 | 72 | void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV, int blocks, uint64_t services) { 73 | int id = Lookup_(addr); 74 | if (id == -1) return; 75 | unkId.erase(id); 76 | banned.erase(addr); 77 | CAddrInfo &info = idToInfo[id]; 78 | info.clientVersion = clientV; 79 | info.clientSubVersion = clientSV; 80 | info.blocks = blocks; 81 | info.services = services; 82 | info.Update(true); 83 | if (info.IsGood() && goodId.count(id)==0) { 84 | goodId.insert(id); 85 | // printf("%s: good; %i good nodes now\n", ToString(addr).c_str(), (int)goodId.size()); 86 | } 87 | nDirty++; 88 | ourId.push_back(id); 89 | } 90 | 91 | void CAddrDb::Bad_(const CService &addr, int ban) 92 | { 93 | int id = Lookup_(addr); 94 | if (id == -1) return; 95 | unkId.erase(id); 96 | CAddrInfo &info = idToInfo[id]; 97 | info.Update(false); 98 | uint32_t now = time(NULL); 99 | int ter = info.GetBanTime(); 100 | if (ter) { 101 | // printf("%s: terrible\n", ToString(addr).c_str()); 102 | if (ban < ter) ban = ter; 103 | } 104 | if (ban > 0) { 105 | // printf("%s: ban for %i seconds\n", ToString(addr).c_str(), ban); 106 | banned[info.ip] = ban + now; 107 | ipToId.erase(info.ip); 108 | goodId.erase(id); 109 | idToInfo.erase(id); 110 | } else { 111 | if (/*!info.IsGood() && */ goodId.count(id)==1) { 112 | goodId.erase(id); 113 | // printf("%s: not good; %i good nodes left\n", ToString(addr).c_str(), (int)goodId.size()); 114 | } 115 | ourId.push_back(id); 116 | } 117 | nDirty++; 118 | } 119 | 120 | void CAddrDb::Skipped_(const CService &addr) 121 | { 122 | int id = Lookup_(addr); 123 | if (id == -1) return; 124 | unkId.erase(id); 125 | ourId.push_back(id); 126 | // printf("%s: skipped\n", ToString(addr).c_str()); 127 | nDirty++; 128 | } 129 | 130 | 131 | void CAddrDb::Add_(const CAddress &addr, bool force) { 132 | if (!force && !addr.IsRoutable()) 133 | return; 134 | CService ipp(addr); 135 | if (banned.count(ipp)) { 136 | time_t bantime = banned[ipp]; 137 | if (force || (bantime < time(NULL) && addr.nTime > bantime)) 138 | banned.erase(ipp); 139 | else 140 | return; 141 | } 142 | if (ipToId.count(ipp)) { 143 | CAddrInfo &ai = idToInfo[ipToId[ipp]]; 144 | if (addr.nTime > ai.lastTry) ai.lastTry = addr.nTime; 145 | // Do not update ai.nServices (data from VERSION from the peer itself is better than random ADDR rumours). 146 | if (force) { 147 | ai.ignoreTill = 0; 148 | } 149 | return; 150 | } 151 | CAddrInfo ai; 152 | ai.ip = ipp; 153 | ai.services = addr.nServices; 154 | ai.lastTry = addr.nTime; 155 | ai.ourLastTry = 0; 156 | ai.total = 0; 157 | ai.success = 0; 158 | int id = nId++; 159 | idToInfo[id] = ai; 160 | ipToId[ipp] = id; 161 | // printf("%s: added\n", ToString(ipp).c_str(), ipToId[ipp]); 162 | unkId.insert(id); 163 | nDirty++; 164 | } 165 | 166 | void CAddrDb::GetIPs_(set& ips, uint64_t requestedFlags, int max, const bool* nets) { 167 | if (goodId.size() == 0) { 168 | int id = -1; 169 | if (ourId.size() == 0) { 170 | if (unkId.size() == 0) return; 171 | id = *unkId.begin(); 172 | } else { 173 | id = *ourId.begin(); 174 | } 175 | if (id >= 0 && (idToInfo[id].services & requestedFlags) == requestedFlags) { 176 | ips.insert(idToInfo[id].ip); 177 | } 178 | return; 179 | } 180 | std::vector goodIdFiltered; 181 | for (std::set::const_iterator it = goodId.begin(); it != goodId.end(); it++) { 182 | if ((idToInfo[*it].services & requestedFlags) == requestedFlags) 183 | goodIdFiltered.push_back(*it); 184 | } 185 | 186 | if (!goodIdFiltered.size()) 187 | return; 188 | 189 | if (max > goodIdFiltered.size() / 2) 190 | max = goodIdFiltered.size() / 2; 191 | if (max < 1) 192 | max = 1; 193 | 194 | set ids; 195 | while (ids.size() < max) { 196 | ids.insert(goodIdFiltered[rand() % goodIdFiltered.size()]); 197 | } 198 | for (set::const_iterator it = ids.begin(); it != ids.end(); it++) { 199 | CService &ip = idToInfo[*it].ip; 200 | if (nets[ip.GetNetwork()]) 201 | ips.insert(ip); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /netbase.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2012 The Bitcoin developers 2 | // Distributed under the MIT/X11 software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | #ifndef BITCOIN_NETBASE_H 5 | #define BITCOIN_NETBASE_H 6 | 7 | #include 8 | #include 9 | 10 | #include "serialize.h" 11 | #include "compat.h" 12 | 13 | extern int nConnectTimeout; 14 | 15 | #ifdef WIN32 16 | // In MSVC, this is defined as a macro, undefine it to prevent a compile and link error 17 | #undef SetPort 18 | #endif 19 | 20 | enum Network 21 | { 22 | NET_UNROUTABLE, 23 | NET_IPV4, 24 | NET_IPV6, 25 | NET_TOR, 26 | NET_I2P, 27 | 28 | NET_MAX, 29 | }; 30 | 31 | extern int nConnectTimeout; 32 | extern bool fNameLookup; 33 | 34 | /** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ 35 | class CNetAddr 36 | { 37 | protected: 38 | unsigned char ip[16]; // in network byte order 39 | 40 | public: 41 | CNetAddr(); 42 | CNetAddr(const struct in_addr& ipv4Addr); 43 | explicit CNetAddr(const char *pszIp, bool fAllowLookup = false); 44 | explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); 45 | void Init(); 46 | void SetIP(const CNetAddr& ip); 47 | bool SetSpecial(const std::string &strName); // for Tor and I2P addresses 48 | bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) 49 | bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/I2P) 50 | bool IsReserved() const; // Against Hetzners Abusal/Netscan Bot 51 | bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) 52 | bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) 53 | bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) 54 | bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16) 55 | bool IsRFC4193() const; // IPv6 unique local (FC00::/15) 56 | bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32) 57 | bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) 58 | bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) 59 | bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) 60 | bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) 61 | bool IsTor() const; 62 | bool IsI2P() const; 63 | bool IsLocal() const; 64 | bool IsRoutable() const; 65 | bool IsValid() const; 66 | bool IsMulticast() const; 67 | enum Network GetNetwork() const; 68 | std::string ToString() const; 69 | std::string ToStringIP() const; 70 | unsigned int GetByte(int n) const; 71 | uint64 GetHash() const; 72 | bool GetInAddr(struct in_addr* pipv4Addr) const; 73 | std::vector GetGroup() const; 74 | int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; 75 | void print() const; 76 | 77 | CNetAddr(const struct in6_addr& pipv6Addr); 78 | bool GetIn6Addr(struct in6_addr* pipv6Addr) const; 79 | 80 | friend bool operator==(const CNetAddr& a, const CNetAddr& b); 81 | friend bool operator!=(const CNetAddr& a, const CNetAddr& b); 82 | friend bool operator<(const CNetAddr& a, const CNetAddr& b); 83 | 84 | IMPLEMENT_SERIALIZE 85 | ( 86 | READWRITE(FLATDATA(ip)); 87 | ) 88 | }; 89 | 90 | /** A combination of a network address (CNetAddr) and a (TCP) port */ 91 | class CService : public CNetAddr 92 | { 93 | protected: 94 | unsigned short port; // host order 95 | 96 | public: 97 | CService(); 98 | CService(const CNetAddr& ip, unsigned short port); 99 | CService(const struct in_addr& ipv4Addr, unsigned short port); 100 | CService(const struct sockaddr_in& addr); 101 | explicit CService(const char *pszIpPort, int portDefault, bool fAllowLookup = false); 102 | explicit CService(const char *pszIpPort, bool fAllowLookup = false); 103 | explicit CService(const std::string& strIpPort, int portDefault, bool fAllowLookup = false); 104 | explicit CService(const std::string& strIpPort, bool fAllowLookup = false); 105 | void Init(); 106 | void SetPort(unsigned short portIn); 107 | unsigned short GetPort() const; 108 | bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const; 109 | bool SetSockAddr(const struct sockaddr* paddr); 110 | friend bool operator==(const CService& a, const CService& b); 111 | friend bool operator!=(const CService& a, const CService& b); 112 | friend bool operator<(const CService& a, const CService& b); 113 | std::vector GetKey() const; 114 | std::string ToString() const; 115 | std::string ToStringPort() const; 116 | std::string ToStringIPPort() const; 117 | void print() const; 118 | 119 | CService(const struct in6_addr& ipv6Addr, unsigned short port); 120 | CService(const struct sockaddr_in6& addr); 121 | 122 | IMPLEMENT_SERIALIZE 123 | ( 124 | CService* pthis = const_cast(this); 125 | READWRITE(FLATDATA(ip)); 126 | unsigned short portN = htons(port); 127 | READWRITE(portN); 128 | if (fRead) 129 | pthis->port = ntohs(portN); 130 | ) 131 | }; 132 | 133 | enum Network ParseNetwork(std::string net); 134 | void SplitHostPort(std::string in, int &portOut, std::string &hostOut); 135 | bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5); 136 | bool GetProxy(enum Network net, CService &addrProxy); 137 | bool IsProxy(const CNetAddr &addr); 138 | bool SetNameProxy(CService addrProxy, int nSocksVersion = 5); 139 | bool GetNameProxy(); 140 | bool LookupHost(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); 141 | bool LookupHostNumeric(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions = 0); 142 | bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); 143 | bool Lookup(const char *pszName, std::vector& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0); 144 | bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); 145 | bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); 146 | bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "util.h" 3 | 4 | using namespace std; 5 | 6 | string vstrprintf(const std::string &format, va_list ap) 7 | { 8 | char buffer[50000]; 9 | char* p = buffer; 10 | int limit = sizeof(buffer); 11 | int ret; 12 | loop 13 | { 14 | va_list arg_ptr; 15 | va_copy(arg_ptr, ap); 16 | ret = vsnprintf(p, limit, format.c_str(), arg_ptr); 17 | va_end(arg_ptr); 18 | if (ret >= 0 && ret < limit) 19 | break; 20 | if (p != buffer) 21 | delete[] p; 22 | limit *= 2; 23 | p = new char[limit]; 24 | if (p == NULL) 25 | throw std::bad_alloc(); 26 | } 27 | string str(p, p+ret); 28 | if (p != buffer) 29 | delete[] p; 30 | return str; 31 | } 32 | 33 | string EncodeBase32(const unsigned char* pch, size_t len) 34 | { 35 | static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; 36 | 37 | string strRet=""; 38 | strRet.reserve((len+4)/5*8); 39 | 40 | int mode=0, left=0; 41 | const unsigned char *pchEnd = pch+len; 42 | 43 | while (pch> 3]; 50 | left = (enc & 7) << 2; 51 | mode = 1; 52 | break; 53 | 54 | case 1: // we have three bits 55 | strRet += pbase32[left | (enc >> 6)]; 56 | strRet += pbase32[(enc >> 1) & 31]; 57 | left = (enc & 1) << 4; 58 | mode = 2; 59 | break; 60 | 61 | case 2: // we have one bit 62 | strRet += pbase32[left | (enc >> 4)]; 63 | left = (enc & 15) << 1; 64 | mode = 3; 65 | break; 66 | 67 | case 3: // we have four bits 68 | strRet += pbase32[left | (enc >> 7)]; 69 | strRet += pbase32[(enc >> 2) & 31]; 70 | left = (enc & 3) << 3; 71 | mode = 4; 72 | break; 73 | 74 | case 4: // we have two bits 75 | strRet += pbase32[left | (enc >> 5)]; 76 | strRet += pbase32[enc & 31]; 77 | mode = 0; 78 | } 79 | } 80 | 81 | static const int nPadding[5] = {0, 6, 4, 3, 1}; 82 | if (mode) 83 | { 84 | strRet += pbase32[left]; 85 | for (int n=0; n DecodeBase32(const char* p, bool* pfInvalid) 98 | { 99 | static const int decode32_table[256] = 100 | { 101 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 103 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, 104 | -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 105 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, 106 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 107 | 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 108 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 109 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 110 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 111 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 112 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 113 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 114 | }; 115 | 116 | if (pfInvalid) 117 | *pfInvalid = false; 118 | 119 | vector vchRet; 120 | vchRet.reserve((strlen(p))*5/8); 121 | 122 | int mode = 0; 123 | int left = 0; 124 | 125 | while (1) 126 | { 127 | int dec = decode32_table[(unsigned char)*p]; 128 | if (dec == -1) break; 129 | p++; 130 | switch (mode) 131 | { 132 | case 0: // we have no bits and get 5 133 | left = dec; 134 | mode = 1; 135 | break; 136 | 137 | case 1: // we have 5 bits and keep 2 138 | vchRet.push_back((left<<3) | (dec>>2)); 139 | left = dec & 3; 140 | mode = 2; 141 | break; 142 | 143 | case 2: // we have 2 bits and keep 7 144 | left = left << 5 | dec; 145 | mode = 3; 146 | break; 147 | 148 | case 3: // we have 7 bits and keep 4 149 | vchRet.push_back((left<<1) | (dec>>4)); 150 | left = dec & 15; 151 | mode = 4; 152 | break; 153 | 154 | case 4: // we have 4 bits, and keep 1 155 | vchRet.push_back((left<<4) | (dec>>1)); 156 | left = dec & 1; 157 | mode = 5; 158 | break; 159 | 160 | case 5: // we have 1 bit, and keep 6 161 | left = left << 5 | dec; 162 | mode = 6; 163 | break; 164 | 165 | case 6: // we have 6 bits, and keep 3 166 | vchRet.push_back((left<<2) | (dec>>3)); 167 | left = dec & 7; 168 | mode = 7; 169 | break; 170 | 171 | case 7: // we have 3 bits, and keep 0 172 | vchRet.push_back((left<<5) | dec); 173 | mode = 0; 174 | break; 175 | } 176 | } 177 | 178 | if (pfInvalid) 179 | switch (mode) 180 | { 181 | case 0: // 8n base32 characters processed: ok 182 | break; 183 | 184 | case 1: // 8n+1 base32 characters processed: impossible 185 | case 3: // +3 186 | case 6: // +6 187 | *pfInvalid = true; 188 | break; 189 | 190 | case 2: // 8n+2 base32 characters processed: require '======' 191 | if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1) 192 | *pfInvalid = true; 193 | break; 194 | 195 | case 4: // 8n+4 base32 characters processed: require '====' 196 | if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1) 197 | *pfInvalid = true; 198 | break; 199 | 200 | case 5: // 8n+5 base32 characters processed: require '===' 201 | if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1) 202 | *pfInvalid = true; 203 | break; 204 | 205 | case 7: // 8n+7 base32 characters processed: require '=' 206 | if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1) 207 | *pfInvalid = true; 208 | break; 209 | } 210 | 211 | return vchRet; 212 | } 213 | 214 | string DecodeBase32(const string& str) 215 | { 216 | vector vchRet = DecodeBase32(str.c_str()); 217 | return string((const char*)&vchRet[0], vchRet.size()); 218 | } 219 | -------------------------------------------------------------------------------- /bitcoin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "db.h" 4 | #include "netbase.h" 5 | #include "protocol.h" 6 | #include "serialize.h" 7 | #include "uint256.h" 8 | 9 | #define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL 10 | 11 | using namespace std; 12 | 13 | class CNode { 14 | SOCKET sock; 15 | CDataStream vSend; 16 | CDataStream vRecv; 17 | unsigned int nHeaderStart; 18 | unsigned int nMessageStart; 19 | int nVersion; 20 | string strSubVer; 21 | int nStartingHeight; 22 | vector *vAddr; 23 | int ban; 24 | int64 doneAfter; 25 | CAddress you; 26 | 27 | int GetTimeout() { 28 | if (you.IsTor()) 29 | return 120; 30 | else 31 | return 30; 32 | } 33 | 34 | void BeginMessage(const char *pszCommand) { 35 | if (nHeaderStart != -1) AbortMessage(); 36 | nHeaderStart = vSend.size(); 37 | vSend << CMessageHeader(pszCommand, 0); 38 | nMessageStart = vSend.size(); 39 | // printf("%s: SEND %s\n", ToString(you).c_str(), pszCommand); 40 | } 41 | 42 | void AbortMessage() { 43 | if (nHeaderStart == -1) return; 44 | vSend.resize(nHeaderStart); 45 | nHeaderStart = -1; 46 | nMessageStart = -1; 47 | } 48 | 49 | void EndMessage() { 50 | if (nHeaderStart == -1) return; 51 | unsigned int nSize = vSend.size() - nMessageStart; 52 | memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); 53 | if (vSend.GetVersion() >= 209) { 54 | uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); 55 | unsigned int nChecksum = 0; 56 | memcpy(&nChecksum, &hash, sizeof(nChecksum)); 57 | assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum)); 58 | memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum)); 59 | } 60 | nHeaderStart = -1; 61 | nMessageStart = -1; 62 | } 63 | 64 | void Send() { 65 | if (sock == INVALID_SOCKET) return; 66 | if (vSend.empty()) return; 67 | int nBytes = send(sock, &vSend[0], vSend.size(), 0); 68 | if (nBytes > 0) { 69 | vSend.erase(vSend.begin(), vSend.begin() + nBytes); 70 | } else { 71 | close(sock); 72 | sock = INVALID_SOCKET; 73 | } 74 | } 75 | 76 | void PushVersion() { 77 | int64 nTime = time(NULL); 78 | uint64 nLocalNonce = BITCOIN_SEED_NONCE; 79 | int64 nLocalServices = 0; 80 | CAddress me(CService("0.0.0.0")); 81 | BeginMessage("version"); 82 | int nBestHeight = GetRequireHeight(); 83 | string ver = "/bitcoin-seeder:0.01/"; 84 | uint8_t fRelayTxs = 0; 85 | vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me << nLocalNonce << ver << nBestHeight << fRelayTxs; 86 | EndMessage(); 87 | } 88 | 89 | void GotVersion() { 90 | // printf("\n%s: version %i\n", ToString(you).c_str(), nVersion); 91 | if (vAddr) { 92 | BeginMessage("getaddr"); 93 | EndMessage(); 94 | doneAfter = time(NULL) + GetTimeout(); 95 | } else { 96 | doneAfter = time(NULL) + 1; 97 | } 98 | } 99 | 100 | bool ProcessMessage(string strCommand, CDataStream& vRecv) { 101 | // printf("%s: RECV %s\n", ToString(you).c_str(), strCommand.c_str()); 102 | if (strCommand == "version") { 103 | int64 nTime; 104 | CAddress addrMe; 105 | CAddress addrFrom; 106 | uint64 nNonce = 1; 107 | vRecv >> nVersion >> you.nServices >> nTime >> addrMe; 108 | if (nVersion == 10300) nVersion = 300; 109 | if (nVersion >= 106 && !vRecv.empty()) 110 | vRecv >> addrFrom >> nNonce; 111 | if (nVersion >= 106 && !vRecv.empty()) 112 | vRecv >> strSubVer; 113 | if (nVersion >= 209 && !vRecv.empty()) 114 | vRecv >> nStartingHeight; 115 | 116 | if (nVersion >= 209) { 117 | BeginMessage("verack"); 118 | EndMessage(); 119 | } 120 | vSend.SetVersion(min(nVersion, PROTOCOL_VERSION)); 121 | if (nVersion < 209) { 122 | this->vRecv.SetVersion(min(nVersion, PROTOCOL_VERSION)); 123 | GotVersion(); 124 | } 125 | return false; 126 | } 127 | 128 | if (strCommand == "verack") { 129 | this->vRecv.SetVersion(min(nVersion, PROTOCOL_VERSION)); 130 | GotVersion(); 131 | return false; 132 | } 133 | 134 | if (strCommand == "addr" && vAddr) { 135 | vector vAddrNew; 136 | vRecv >> vAddrNew; 137 | // printf("%s: got %i addresses\n", ToString(you).c_str(), (int)vAddrNew.size()); 138 | int64 now = time(NULL); 139 | vector::iterator it = vAddrNew.begin(); 140 | if (vAddrNew.size() > 1) { 141 | if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1; 142 | } 143 | while (it != vAddrNew.end()) { 144 | CAddress &addr = *it; 145 | // printf("%s: got address %s\n", ToString(you).c_str(), addr.ToString().c_str(), (int)(vAddr->size())); 146 | it++; 147 | if (addr.nTime <= 100000000 || addr.nTime > now + 600) 148 | addr.nTime = now - 5 * 86400; 149 | if (addr.nTime > now - 604800) 150 | vAddr->push_back(addr); 151 | // printf("%s: added address %s (#%i)\n", ToString(you).c_str(), addr.ToString().c_str(), (int)(vAddr->size())); 152 | if (vAddr->size() > 1000) {doneAfter = 1; return true; } 153 | } 154 | return false; 155 | } 156 | 157 | return false; 158 | } 159 | 160 | bool ProcessMessages() { 161 | if (vRecv.empty()) return false; 162 | do { 163 | CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart)); 164 | int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader()); 165 | if (vRecv.end() - pstart < nHeaderSize) { 166 | if (vRecv.size() > nHeaderSize) { 167 | vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize); 168 | } 169 | break; 170 | } 171 | vRecv.erase(vRecv.begin(), pstart); 172 | vector vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize); 173 | CMessageHeader hdr; 174 | vRecv >> hdr; 175 | if (!hdr.IsValid()) { 176 | // printf("%s: BAD (invalid header)\n", ToString(you).c_str()); 177 | ban = 100000; return true; 178 | } 179 | string strCommand = hdr.GetCommand(); 180 | unsigned int nMessageSize = hdr.nMessageSize; 181 | if (nMessageSize > MAX_SIZE) { 182 | // printf("%s: BAD (message too large)\n", ToString(you).c_str()); 183 | ban = 100000; 184 | return true; 185 | } 186 | if (nMessageSize > vRecv.size()) { 187 | vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end()); 188 | break; 189 | } 190 | if (vRecv.GetVersion() >= 209) { 191 | uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); 192 | unsigned int nChecksum = 0; 193 | memcpy(&nChecksum, &hash, sizeof(nChecksum)); 194 | if (nChecksum != hdr.nChecksum) continue; 195 | } 196 | CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); 197 | vRecv.ignore(nMessageSize); 198 | if (ProcessMessage(strCommand, vMsg)) 199 | return true; 200 | // printf("%s: done processing %s\n", ToString(you).c_str(), strCommand.c_str()); 201 | } while(1); 202 | return false; 203 | } 204 | 205 | public: 206 | CNode(const CService& ip, vector* vAddrIn) : you(ip), nHeaderStart(-1), nMessageStart(-1), vAddr(vAddrIn), ban(0), doneAfter(0), nVersion(0) { 207 | vSend.SetType(SER_NETWORK); 208 | vSend.SetVersion(0); 209 | vRecv.SetType(SER_NETWORK); 210 | vRecv.SetVersion(0); 211 | if (time(NULL) > 1329696000) { 212 | vSend.SetVersion(209); 213 | vRecv.SetVersion(209); 214 | } 215 | } 216 | bool Run() { 217 | bool res = true; 218 | if (!ConnectSocket(you, sock)) return false; 219 | PushVersion(); 220 | Send(); 221 | int64 now; 222 | while (now = time(NULL), ban == 0 && (doneAfter == 0 || doneAfter > now) && sock != INVALID_SOCKET) { 223 | char pchBuf[0x10000]; 224 | fd_set read_set, except_set; 225 | FD_ZERO(&read_set); 226 | FD_ZERO(&except_set); 227 | FD_SET(sock,&read_set); 228 | FD_SET(sock,&except_set); 229 | struct timeval wa; 230 | if (doneAfter) { 231 | wa.tv_sec = doneAfter - now; 232 | wa.tv_usec = 0; 233 | } else { 234 | wa.tv_sec = GetTimeout(); 235 | wa.tv_usec = 0; 236 | } 237 | int ret = select(sock+1, &read_set, NULL, &except_set, &wa); 238 | if (ret != 1) { 239 | if (!doneAfter) res = false; 240 | break; 241 | } 242 | int nBytes = recv(sock, pchBuf, sizeof(pchBuf), 0); 243 | int nPos = vRecv.size(); 244 | if (nBytes > 0) { 245 | vRecv.resize(nPos + nBytes); 246 | memcpy(&vRecv[nPos], pchBuf, nBytes); 247 | } else if (nBytes == 0) { 248 | // printf("%s: BAD (connection closed prematurely)\n", ToString(you).c_str()); 249 | res = false; 250 | break; 251 | } else { 252 | // printf("%s: BAD (connection error)\n", ToString(you).c_str()); 253 | res = false; 254 | break; 255 | } 256 | ProcessMessages(); 257 | Send(); 258 | } 259 | if (sock == INVALID_SOCKET) res = false; 260 | close(sock); 261 | sock = INVALID_SOCKET; 262 | return (ban == 0) && res; 263 | } 264 | 265 | int GetBan() { 266 | return ban; 267 | } 268 | 269 | int GetClientVersion() { 270 | return nVersion; 271 | } 272 | 273 | std::string GetClientSubVersion() { 274 | return strSubVer; 275 | } 276 | 277 | int GetStartingHeight() { 278 | return nStartingHeight; 279 | } 280 | 281 | uint64_t GetServices() { 282 | return you.nServices; 283 | } 284 | }; 285 | 286 | bool TestNode(const CService &cip, int &ban, int &clientV, std::string &clientSV, int &blocks, vector* vAddr, uint64_t& services) { 287 | try { 288 | CNode node(cip, vAddr); 289 | bool ret = node.Run(); 290 | if (!ret) { 291 | ban = node.GetBan(); 292 | } else { 293 | ban = 0; 294 | } 295 | clientV = node.GetClientVersion(); 296 | clientSV = node.GetClientSubVersion(); 297 | blocks = node.GetStartingHeight(); 298 | services = node.GetServices(); 299 | // printf("%s: %s!!!\n", cip.ToString().c_str(), ret ? "GOOD" : "BAD"); 300 | return ret; 301 | } catch(std::ios_base::failure& e) { 302 | ban = 0; 303 | return false; 304 | } 305 | } 306 | 307 | /* 308 | int main(void) { 309 | CService ip("bitcoin.sipa.be", 8333, true); 310 | vector vAddr; 311 | vAddr.clear(); 312 | int ban = 0; 313 | bool ret = TestNode(ip, ban, vAddr); 314 | printf("ret=%s ban=%i vAddr.size()=%i\n", ret ? "good" : "bad", ban, (int)vAddr.size()); 315 | } 316 | */ 317 | 318 | -------------------------------------------------------------------------------- /db.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "netbase.h" 10 | #include "protocol.h" 11 | #include "util.h" 12 | 13 | #define MIN_RETRY 1000 14 | 15 | #define REQUIRE_VERSION 70001 16 | 17 | static inline int GetRequireHeight(const bool testnet = fTestNet) 18 | { 19 | return testnet ? 500000 : 350000; 20 | } 21 | 22 | std::string static inline ToString(const CService &ip) { 23 | std::string str = ip.ToString(); 24 | while (str.size() < 22) str += ' '; 25 | return str; 26 | } 27 | 28 | class CAddrStat { 29 | private: 30 | float weight; 31 | float count; 32 | float reliability; 33 | public: 34 | CAddrStat() : weight(0), count(0), reliability(0) {} 35 | 36 | void Update(bool good, int64 age, double tau) { 37 | double f = exp(-age/tau); 38 | reliability = reliability * f + (good ? (1.0-f) : 0); 39 | count = count * f + 1; 40 | weight = weight * f + (1.0-f); 41 | } 42 | 43 | IMPLEMENT_SERIALIZE ( 44 | READWRITE(weight); 45 | READWRITE(count); 46 | READWRITE(reliability); 47 | ) 48 | 49 | friend class CAddrInfo; 50 | }; 51 | 52 | class CAddrReport { 53 | public: 54 | CService ip; 55 | int clientVersion; 56 | int blocks; 57 | double uptime[5]; 58 | std::string clientSubVersion; 59 | int64_t lastSuccess; 60 | bool fGood; 61 | uint64_t services; 62 | }; 63 | 64 | 65 | class CAddrInfo { 66 | private: 67 | CService ip; 68 | uint64_t services; 69 | int64 lastTry; 70 | int64 ourLastTry; 71 | int64 ourLastSuccess; 72 | int64 ignoreTill; 73 | CAddrStat stat2H; 74 | CAddrStat stat8H; 75 | CAddrStat stat1D; 76 | CAddrStat stat1W; 77 | CAddrStat stat1M; 78 | int clientVersion; 79 | int blocks; 80 | int total; 81 | int success; 82 | std::string clientSubVersion; 83 | public: 84 | CAddrInfo() : services(0), lastTry(0), ourLastTry(0), ourLastSuccess(0), ignoreTill(0), clientVersion(0), blocks(0), total(0), success(0) {} 85 | 86 | CAddrReport GetReport() const { 87 | CAddrReport ret; 88 | ret.ip = ip; 89 | ret.clientVersion = clientVersion; 90 | ret.clientSubVersion = clientSubVersion; 91 | ret.blocks = blocks; 92 | ret.uptime[0] = stat2H.reliability; 93 | ret.uptime[1] = stat8H.reliability; 94 | ret.uptime[2] = stat1D.reliability; 95 | ret.uptime[3] = stat1W.reliability; 96 | ret.uptime[4] = stat1M.reliability; 97 | ret.lastSuccess = ourLastSuccess; 98 | ret.fGood = IsGood(); 99 | ret.services = services; 100 | return ret; 101 | } 102 | 103 | bool IsGood() const { 104 | if (ip.GetPort() != GetDefaultPort()) return false; 105 | if (!(services & NODE_NETWORK)) return false; 106 | if (!ip.IsRoutable()) return false; 107 | if (clientVersion && clientVersion < REQUIRE_VERSION) return false; 108 | if (blocks && blocks < GetRequireHeight()) return false; 109 | 110 | if (total <= 3 && success * 2 >= total) return true; 111 | 112 | if (stat2H.reliability > 0.85 && stat2H.count > 2) return true; 113 | if (stat8H.reliability > 0.70 && stat8H.count > 4) return true; 114 | if (stat1D.reliability > 0.55 && stat1D.count > 8) return true; 115 | if (stat1W.reliability > 0.45 && stat1W.count > 16) return true; 116 | if (stat1M.reliability > 0.35 && stat1M.count > 32) return true; 117 | 118 | return false; 119 | } 120 | int GetBanTime() const { 121 | if (IsGood()) return 0; 122 | if (clientVersion && clientVersion < 31900) { return 604800; } 123 | if (stat1M.reliability - stat1M.weight + 1.0 < 0.15 && stat1M.count > 32) { return 30*86400; } 124 | if (stat1W.reliability - stat1W.weight + 1.0 < 0.10 && stat1W.count > 16) { return 7*86400; } 125 | if (stat1D.reliability - stat1D.weight + 1.0 < 0.05 && stat1D.count > 8) { return 1*86400; } 126 | return 0; 127 | } 128 | int GetIgnoreTime() const { 129 | if (IsGood()) return 0; 130 | if (stat1M.reliability - stat1M.weight + 1.0 < 0.20 && stat1M.count > 2) { return 10*86400; } 131 | if (stat1W.reliability - stat1W.weight + 1.0 < 0.16 && stat1W.count > 2) { return 3*86400; } 132 | if (stat1D.reliability - stat1D.weight + 1.0 < 0.12 && stat1D.count > 2) { return 8*3600; } 133 | if (stat8H.reliability - stat8H.weight + 1.0 < 0.08 && stat8H.count > 2) { return 2*3600; } 134 | return 0; 135 | } 136 | 137 | void Update(bool good); 138 | 139 | friend class CAddrDb; 140 | 141 | IMPLEMENT_SERIALIZE ( 142 | unsigned char version = 4; 143 | READWRITE(version); 144 | READWRITE(ip); 145 | READWRITE(services); 146 | READWRITE(lastTry); 147 | unsigned char tried = ourLastTry != 0; 148 | READWRITE(tried); 149 | if (tried) { 150 | READWRITE(ourLastTry); 151 | READWRITE(ignoreTill); 152 | READWRITE(stat2H); 153 | READWRITE(stat8H); 154 | READWRITE(stat1D); 155 | READWRITE(stat1W); 156 | if (version >= 1) 157 | READWRITE(stat1M); 158 | else 159 | if (!fWrite) 160 | *((CAddrStat*)(&stat1M)) = stat1W; 161 | READWRITE(total); 162 | READWRITE(success); 163 | READWRITE(clientVersion); 164 | if (version >= 2) 165 | READWRITE(clientSubVersion); 166 | if (version >= 3) 167 | READWRITE(blocks); 168 | if (version >= 4) 169 | READWRITE(ourLastSuccess); 170 | } 171 | ) 172 | }; 173 | 174 | class CAddrDbStats { 175 | public: 176 | int nBanned; 177 | int nAvail; 178 | int nTracked; 179 | int nNew; 180 | int nGood; 181 | int nAge; 182 | }; 183 | 184 | struct CServiceResult { 185 | CService service; 186 | uint64_t services; 187 | bool fGood; 188 | int nBanTime; 189 | int nHeight; 190 | int nClientV; 191 | std::string strClientV; 192 | int64 ourLastSuccess; 193 | }; 194 | 195 | // seen nodes 196 | // / \ 197 | // (a) banned nodes available nodes-------------- 198 | // / | \ 199 | // tracked nodes (b) unknown nodes (e) active nodes 200 | // / \ 201 | // (d) good nodes (c) non-good nodes 202 | 203 | class CAddrDb { 204 | private: 205 | mutable CCriticalSection cs; 206 | int nId; // number of address id's 207 | std::map idToInfo; // map address id to address info (b,c,d,e) 208 | std::map ipToId; // map ip to id (b,c,d,e) 209 | std::deque ourId; // sequence of tried nodes, in order we have tried connecting to them (c,d) 210 | std::set unkId; // set of nodes not yet tried (b) 211 | std::set goodId; // set of good nodes (d, good e) 212 | int nDirty; 213 | 214 | protected: 215 | // internal routines that assume proper locks are acquired 216 | void Add_(const CAddress &addr, bool force); // add an address 217 | bool Get_(CServiceResult &ip, int& wait); // get an IP to test (must call Good_, Bad_, or Skipped_ on result afterwards) 218 | bool GetMany_(std::vector &ips, int max, int& wait); 219 | void Good_(const CService &ip, int clientV, std::string clientSV, int blocks, uint64_t services); // mark an IP as good (must have been returned by Get_) 220 | void Bad_(const CService &ip, int ban); // mark an IP as bad (and optionally ban it) (must have been returned by Get_) 221 | void Skipped_(const CService &ip); // mark an IP as skipped (must have been returned by Get_) 222 | int Lookup_(const CService &ip); // look up id of an IP 223 | void GetIPs_(std::set& ips, uint64_t requestedFlags, int max, const bool *nets); // get a random set of IPs (shared lock only) 224 | 225 | public: 226 | std::map banned; // nodes that are banned, with their unban time (a) 227 | 228 | void GetStats(CAddrDbStats &stats) { 229 | SHARED_CRITICAL_BLOCK(cs) { 230 | stats.nBanned = banned.size(); 231 | stats.nAvail = idToInfo.size(); 232 | stats.nTracked = ourId.size(); 233 | stats.nGood = goodId.size(); 234 | stats.nNew = unkId.size(); 235 | stats.nAge = time(NULL) - idToInfo[ourId[0]].ourLastTry; 236 | } 237 | } 238 | 239 | void ResetIgnores() { 240 | for (std::map::iterator it = idToInfo.begin(); it != idToInfo.end(); it++) { 241 | (*it).second.ignoreTill = 0; 242 | } 243 | } 244 | 245 | std::vector GetAll() { 246 | std::vector ret; 247 | SHARED_CRITICAL_BLOCK(cs) { 248 | for (std::deque::const_iterator it = ourId.begin(); it != ourId.end(); it++) { 249 | const CAddrInfo &info = idToInfo[*it]; 250 | if (info.success > 0) { 251 | ret.push_back(info.GetReport()); 252 | } 253 | } 254 | } 255 | return ret; 256 | } 257 | 258 | // serialization code 259 | // format: 260 | // nVersion (0 for now) 261 | // n (number of ips in (b,c,d)) 262 | // CAddrInfo[n] 263 | // banned 264 | // acquires a shared lock (this does not suffice for read mode, but we assume that only happens at startup, single-threaded) 265 | // this way, dumping does not interfere with GetIPs_, which is called from the DNS thread 266 | IMPLEMENT_SERIALIZE (({ 267 | int nVersion = 0; 268 | READWRITE(nVersion); 269 | SHARED_CRITICAL_BLOCK(cs) { 270 | if (fWrite) { 271 | CAddrDb *db = const_cast(this); 272 | int n = ourId.size() + unkId.size(); 273 | READWRITE(n); 274 | for (std::deque::const_iterator it = ourId.begin(); it != ourId.end(); it++) { 275 | std::map::iterator ci = db->idToInfo.find(*it); 276 | READWRITE((*ci).second); 277 | } 278 | for (std::set::const_iterator it = unkId.begin(); it != unkId.end(); it++) { 279 | std::map::iterator ci = db->idToInfo.find(*it); 280 | READWRITE((*ci).second); 281 | } 282 | } else { 283 | CAddrDb *db = const_cast(this); 284 | db->nId = 0; 285 | int n; 286 | READWRITE(n); 287 | for (int i=0; inId++; 292 | db->idToInfo[id] = info; 293 | db->ipToId[info.ip] = id; 294 | if (info.ourLastTry) { 295 | db->ourId.push_back(id); 296 | if (info.IsGood()) db->goodId.insert(id); 297 | } else { 298 | db->unkId.insert(id); 299 | } 300 | } 301 | } 302 | db->nDirty++; 303 | } 304 | READWRITE(banned); 305 | } 306 | });) 307 | 308 | void Add(const CAddress &addr, bool fForce = false) { 309 | CRITICAL_BLOCK(cs) 310 | Add_(addr, fForce); 311 | } 312 | void Add(const std::vector &vAddr, bool fForce = false) { 313 | CRITICAL_BLOCK(cs) 314 | for (int i=0; i &ips, int max, int& wait) { 334 | CRITICAL_BLOCK(cs) { 335 | while (max > 0) { 336 | CServiceResult ip = {}; 337 | if (!Get_(ip, wait)) 338 | return; 339 | ips.push_back(ip); 340 | max--; 341 | } 342 | } 343 | } 344 | void ResultMany(const std::vector &ips) { 345 | CRITICAL_BLOCK(cs) { 346 | for (int i=0; i& ips, uint64_t requestedFlags, int max, const bool *nets) { 356 | SHARED_CRITICAL_BLOCK(cs) 357 | GetIPs_(ips, requestedFlags, max, nets); 358 | } 359 | }; 360 | -------------------------------------------------------------------------------- /dns.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "dns.h" 16 | 17 | #define BUFLEN 512 18 | 19 | #if defined(IP_RECVDSTADDR) 20 | # define DSTADDR_SOCKOPT IP_RECVDSTADDR 21 | # define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_addr))) 22 | # define dstaddr(x) (CMSG_DATA(x)) 23 | #elif defined(IPV6_PKTINFO) 24 | # define DSTADDR_SOCKOPT IPV6_PKTINFO 25 | # define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_pktinfo))) 26 | # define dstaddr(x) (&(((struct in6_pktinfo *)(CMSG_DATA(x)))->ipi6_addr)) 27 | #else 28 | # error "can't determine socket option" 29 | #endif 30 | 31 | union control_data { 32 | struct cmsghdr cmsg; 33 | unsigned char data[DSTADDR_DATASIZE]; 34 | }; 35 | 36 | typedef enum { 37 | CLASS_IN = 1, 38 | QCLASS_ANY = 255 39 | } dns_class; 40 | 41 | typedef enum { 42 | TYPE_A = 1, 43 | TYPE_NS = 2, 44 | TYPE_CNAME = 5, 45 | TYPE_SOA = 6, 46 | TYPE_MX = 15, 47 | TYPE_AAAA = 28, 48 | TYPE_SRV = 33, 49 | QTYPE_ANY = 255 50 | } dns_type; 51 | 52 | 53 | // 0: ok 54 | // -1: premature end of input, forward reference, component > 63 char, invalid character 55 | // -2: insufficient space in output 56 | int static parse_name(const unsigned char **inpos, const unsigned char *inend, const unsigned char *inbuf, char *buf, size_t bufsize) { 57 | size_t bufused = 0; 58 | int init = 1; 59 | do { 60 | if (*inpos == inend) 61 | return -1; 62 | // read length of next component 63 | int octet = *((*inpos)++); 64 | if (octet == 0) { 65 | buf[bufused] = 0; 66 | return 0; 67 | } 68 | // add dot in output 69 | if (!init) { 70 | if (bufused == bufsize-1) 71 | return -2; 72 | buf[bufused++] = '.'; 73 | } else 74 | init = 0; 75 | // handle references 76 | if ((octet & 0xC0) == 0xC0) { 77 | if (*inpos == inend) 78 | return -1; 79 | int ref = ((octet - 0xC0) << 8) + *((*inpos)++); 80 | if (ref < 0 || ref >= (*inpos)-inbuf-2) return -1; 81 | const unsigned char *newbuf = inbuf + ref; 82 | return parse_name(&newbuf, (*inpos) - 2, inbuf, buf+bufused, bufsize-bufused); 83 | } 84 | if (octet > 63) return -1; 85 | // copy label 86 | while (octet) { 87 | if (*inpos == inend) 88 | return -1; 89 | if (bufused == bufsize-1) 90 | return -2; 91 | int c = *((*inpos)++); 92 | if (c == '.') 93 | return -1; 94 | octet--; 95 | buf[bufused++] = c; 96 | } 97 | } while(1); 98 | } 99 | 100 | // 0: k 101 | // -1: component > 63 characters 102 | // -2: insufficent space in output 103 | // -3: two subsequent dots 104 | int static write_name(unsigned char** outpos, const unsigned char *outend, const char *name, int offset) { 105 | while (*name != 0) { 106 | const char *dot = strchr(name, '.'); 107 | const char *fin = dot; 108 | if (!dot) fin = name + strlen(name); 109 | if (fin - name > 63) return -1; 110 | if (fin == name) return -3; 111 | if (outend - *outpos < fin - name + 2) return -2; 112 | *((*outpos)++) = fin - name; 113 | memcpy(*outpos, name, fin - name); 114 | *outpos += fin - name; 115 | if (!dot) break; 116 | name = dot + 1; 117 | } 118 | if (offset < 0) { 119 | // no reference 120 | if (outend == *outpos) return -2; 121 | *((*outpos)++) = 0; 122 | } else { 123 | if (outend - *outpos < 2) return -2; 124 | *((*outpos)++) = (offset >> 8) | 0xC0; 125 | *((*outpos)++) = offset & 0xFF; 126 | } 127 | return 0; 128 | } 129 | 130 | int static write_record(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_type typ, dns_class cls, int ttl) { 131 | unsigned char *oldpos = *outpos; 132 | int error = 0; 133 | // name 134 | int ret = write_name(outpos, outend, name, offset); 135 | if (ret) { 136 | error = ret; 137 | } else { 138 | if (outend - *outpos < 8) { 139 | error = -4; 140 | } else { 141 | // type 142 | *((*outpos)++) = typ >> 8; *((*outpos)++) = typ & 0xFF; 143 | // class 144 | *((*outpos)++) = cls >> 8; *((*outpos)++) = cls & 0xFF; 145 | // ttl 146 | *((*outpos)++) = (ttl >> 24) & 0xFF; *((*outpos)++) = (ttl >> 16) & 0xFF; *((*outpos)++) = (ttl >> 8) & 0xFF; *((*outpos)++) = ttl & 0xFF; 147 | return 0; 148 | } 149 | } 150 | *outpos = oldpos; 151 | return error; 152 | } 153 | 154 | 155 | 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) { 156 | if (ip->v != 4) 157 | return -6; 158 | unsigned char *oldpos = *outpos; 159 | int error = 0; 160 | int ret = write_record(outpos, outend, name, offset, TYPE_A, cls, ttl); 161 | if (ret) return ret; 162 | if (outend - *outpos < 6) { 163 | error = -5; 164 | } else { 165 | // rdlength 166 | *((*outpos)++) = 0; *((*outpos)++) = 4; 167 | // rdata 168 | for (int i=0; i<4; i++) 169 | *((*outpos)++) = ip->data.v4[i]; 170 | return 0; 171 | } 172 | *outpos = oldpos; 173 | return error; 174 | } 175 | 176 | 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) { 177 | if (ip->v != 6) 178 | return -6; 179 | unsigned char *oldpos = *outpos; 180 | int error = 0; 181 | int ret = write_record(outpos, outend, name, offset, TYPE_AAAA, cls, ttl); 182 | if (ret) return ret; 183 | if (outend - *outpos < 18) { 184 | error = -5; 185 | } else { 186 | // rdlength 187 | *((*outpos)++) = 0; *((*outpos)++) = 16; 188 | // rdata 189 | for (int i=0; i<16; i++) 190 | *((*outpos)++) = ip->data.v6[i]; 191 | return 0; 192 | } 193 | *outpos = oldpos; 194 | return error; 195 | } 196 | 197 | int static write_record_ns(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const char *ns) { 198 | unsigned char *oldpos = *outpos; 199 | int ret = write_record(outpos, outend, name, offset, TYPE_NS, cls, ttl); 200 | if (ret) return ret; 201 | int error = 0; 202 | if (outend - *outpos < 2) { 203 | error = -5; 204 | } else { 205 | (*outpos) += 2; 206 | unsigned char *curpos = *outpos; 207 | ret = write_name(outpos, outend, ns, -1); 208 | if (ret) { 209 | error = ret; 210 | } else { 211 | curpos[-2] = (*outpos - curpos) >> 8; 212 | curpos[-1] = (*outpos - curpos) & 0xFF; 213 | return 0; 214 | } 215 | } 216 | *outpos = oldpos; 217 | return error; 218 | } 219 | 220 | int static write_record_soa(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const char* mname, const char *rname, 221 | uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) { 222 | unsigned char *oldpos = *outpos; 223 | int ret = write_record(outpos, outend, name, offset, TYPE_SOA, cls, ttl); 224 | if (ret) return ret; 225 | int error = 0; 226 | if (outend - *outpos < 2) { 227 | error = -5; 228 | } else { 229 | (*outpos) += 2; 230 | unsigned char *curpos = *outpos; 231 | ret = write_name(outpos, outend, mname, -1); 232 | if (ret) { 233 | error = ret; 234 | } else { 235 | ret = write_name(outpos, outend, rname, -1); 236 | if (ret) { 237 | error = ret; 238 | } else { 239 | if (outend - *outpos < 20) { 240 | error = -5; 241 | } else { 242 | *((*outpos)++) = (serial >> 24) & 0xFF; *((*outpos)++) = (serial >> 16) & 0xFF; *((*outpos)++) = (serial >> 8) & 0xFF; *((*outpos)++) = serial & 0xFF; 243 | *((*outpos)++) = (refresh >> 24) & 0xFF; *((*outpos)++) = (refresh >> 16) & 0xFF; *((*outpos)++) = (refresh >> 8) & 0xFF; *((*outpos)++) = refresh & 0xFF; 244 | *((*outpos)++) = (retry >> 24) & 0xFF; *((*outpos)++) = (retry >> 16) & 0xFF; *((*outpos)++) = (retry >> 8) & 0xFF; *((*outpos)++) = retry & 0xFF; 245 | *((*outpos)++) = (expire >> 24) & 0xFF; *((*outpos)++) = (expire >> 16) & 0xFF; *((*outpos)++) = (expire >> 8) & 0xFF; *((*outpos)++) = expire & 0xFF; 246 | *((*outpos)++) = (minimum >> 24) & 0xFF; *((*outpos)++) = (minimum >> 16) & 0xFF; *((*outpos)++) = (minimum >> 8) & 0xFF; *((*outpos)++) = minimum & 0xFF; 247 | curpos[-2] = (*outpos - curpos) >> 8; 248 | curpos[-1] = (*outpos - curpos) & 0xFF; 249 | return 0; 250 | } 251 | } 252 | } 253 | } 254 | *outpos = oldpos; 255 | return error; 256 | } 257 | 258 | static ssize_t set_error(unsigned char* outbuf, int error) { 259 | // set error 260 | outbuf[3] |= error & 0xF; 261 | // set counts 262 | outbuf[4] = 0; outbuf[5] = 0; 263 | outbuf[6] = 0; outbuf[7] = 0; 264 | outbuf[8] = 0; outbuf[9] = 0; 265 | outbuf[10] = 0; outbuf[11] = 0; 266 | return 12; 267 | } 268 | 269 | ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insize, unsigned char* outbuf) { 270 | int error = 0; 271 | if (insize < 12) // DNS header 272 | return -1; 273 | // copy id 274 | outbuf[0] = inbuf[0]; 275 | outbuf[1] = inbuf[1]; 276 | // copy flags; 277 | outbuf[2] = inbuf[2]; 278 | outbuf[3] = inbuf[3]; 279 | // clear error 280 | outbuf[3] &= ~15; 281 | // check qr 282 | if (inbuf[2] & 128) return set_error(outbuf, 1); /* printf("Got response?\n"); */ 283 | // check opcode 284 | if (((inbuf[2] & 120) >> 3) != 0) return set_error(outbuf, 1); /* printf("Opcode nonzero?\n"); */ 285 | // unset TC 286 | outbuf[2] &= ~2; 287 | // unset RA 288 | outbuf[3] &= ~128; 289 | // check questions 290 | int nquestion = (inbuf[4] << 8) + inbuf[5]; 291 | if (nquestion == 0) return set_error(outbuf, 0); /* printf("No questions?\n"); */ 292 | if (nquestion > 1) return set_error(outbuf, 4); /* printf("Multiple questions %i?\n", nquestion); */ 293 | const unsigned char *inpos = inbuf + 12; 294 | const unsigned char *inend = inbuf + insize; 295 | char name[256]; 296 | int offset = inpos - inbuf; 297 | int ret = parse_name(&inpos, inend, inbuf, name, 256); 298 | if (ret == -1) return set_error(outbuf, 1); 299 | if (ret == -2) return set_error(outbuf, 5); 300 | int namel = strlen(name), hostl = strlen(opt->host); 301 | if (strcasecmp(name, opt->host) && (namelhost))) return set_error(outbuf, 5); 302 | if (inend - inpos < 4) return set_error(outbuf, 1); 303 | // copy question to output 304 | memcpy(outbuf+12, inbuf+12, inpos+4 - (inbuf+12)); 305 | // set counts 306 | outbuf[4] = 0; outbuf[5] = 1; 307 | outbuf[6] = 0; outbuf[7] = 0; 308 | outbuf[8] = 0; outbuf[9] = 0; 309 | outbuf[10] = 0; outbuf[11] = 0; 310 | // set qr 311 | outbuf[2] |= 128; 312 | 313 | int typ = (inpos[0] << 8) + inpos[1]; 314 | int cls = (inpos[2] << 8) + inpos[3]; 315 | inpos += 4; 316 | 317 | unsigned char *outpos = outbuf+(inpos-inbuf); 318 | unsigned char *outend = outbuf + BUFLEN; 319 | 320 | // printf("DNS: Request host='%s' type=%i class=%i\n", name, typ, cls); 321 | 322 | // calculate max size of authority section 323 | 324 | int max_auth_size = 0; 325 | 326 | if (!((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY))) { 327 | // authority section will be necessary, either NS or SOA 328 | unsigned char *newpos = outpos; 329 | write_record_ns(&newpos, outend, "", offset, CLASS_IN, 0, opt->ns); 330 | max_auth_size = newpos - outpos; 331 | 332 | newpos = outpos; 333 | write_record_soa(&newpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800); 334 | if (max_auth_size < newpos - outpos) 335 | max_auth_size = newpos - outpos; 336 | // printf("Authority section will claim %i bytes max\n", max_auth_size); 337 | } 338 | 339 | // Answer section 340 | 341 | int have_ns = 0; 342 | 343 | // NS records 344 | if ((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) { 345 | int ret2 = write_record_ns(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns); 346 | // printf("wrote NS record: %i\n", ret2); 347 | if (!ret2) { outbuf[7]++; have_ns++; } 348 | } 349 | 350 | // SOA records 351 | if ((typ == TYPE_SOA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY) && opt->mbox) { 352 | int ret2 = write_record_soa(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800); 353 | // printf("wrote SOA record: %i\n", ret2); 354 | if (!ret2) { outbuf[7]++; } 355 | } 356 | 357 | // A/AAAA records 358 | if ((typ == TYPE_A || typ == TYPE_AAAA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) { 359 | addr_t addr[32]; 360 | int naddr = opt->cb((void*)opt, name, addr, 32, typ == TYPE_A || typ == QTYPE_ANY, typ == TYPE_AAAA || typ == QTYPE_ANY); 361 | int n = 0; 362 | while (n < naddr) { 363 | int ret = 1; 364 | if (addr[n].v == 4) 365 | ret = write_record_a(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]); 366 | else if (addr[n].v == 6) 367 | ret = write_record_aaaa(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]); 368 | // printf("wrote A record: %i\n", ret); 369 | if (!ret) { 370 | n++; 371 | outbuf[7]++; 372 | } else 373 | break; 374 | } 375 | } 376 | 377 | // Authority section 378 | if (!have_ns && outbuf[7]) { 379 | int ret2 = write_record_ns(&outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns); 380 | // printf("wrote NS record: %i\n", ret2); 381 | if (!ret2) { 382 | outbuf[9]++; 383 | } 384 | } 385 | else if (!outbuf[7]) { 386 | // Didn't include any answers, so reply with SOA as this is a negative 387 | // response. If we replied with NS above we'd create a bad horizontal 388 | // referral loop, as the NS response indicates where the resolver should 389 | // try next. 390 | int ret2 = write_record_soa(&outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800); 391 | // printf("wrote SOA record: %i\n", ret2); 392 | if (!ret2) { outbuf[9]++; } 393 | } 394 | 395 | // set AA 396 | outbuf[2] |= 4; 397 | 398 | return outpos - outbuf; 399 | } 400 | 401 | static int listenSocket = -1; 402 | 403 | int dnsserver(dns_opt_t *opt) { 404 | struct sockaddr_in6 si_other; 405 | int senderSocket = -1; 406 | senderSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 407 | if (senderSocket == -1) 408 | return -3; 409 | 410 | int replySocket; 411 | if (listenSocket == -1) { 412 | struct sockaddr_in6 si_me; 413 | if ((listenSocket=socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP))==-1) { 414 | listenSocket = -1; 415 | return -1; 416 | } 417 | replySocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 418 | if (replySocket == -1) 419 | { 420 | close(listenSocket); 421 | return -1; 422 | } 423 | int sockopt = 1; 424 | setsockopt(listenSocket, IPPROTO_IPV6, DSTADDR_SOCKOPT, &sockopt, sizeof sockopt); 425 | memset((char *) &si_me, 0, sizeof(si_me)); 426 | si_me.sin6_family = AF_INET6; 427 | si_me.sin6_port = htons(opt->port); 428 | si_me.sin6_addr = in6addr_any; 429 | if (bind(listenSocket, (struct sockaddr*)&si_me, sizeof(si_me))==-1) 430 | return -2; 431 | } 432 | 433 | unsigned char inbuf[BUFLEN], outbuf[BUFLEN]; 434 | struct iovec iov[1] = { 435 | { 436 | .iov_base = inbuf, 437 | .iov_len = sizeof(inbuf), 438 | }, 439 | }; 440 | union control_data cmsg; 441 | struct msghdr msg = { 442 | .msg_name = &si_other, 443 | .msg_namelen = sizeof(si_other), 444 | .msg_iov = iov, 445 | .msg_iovlen = 1, 446 | .msg_control = &cmsg, 447 | .msg_controllen = sizeof(cmsg), 448 | }; 449 | for (; 1; ++(opt->nRequests)) 450 | { 451 | ssize_t insize = recvmsg(listenSocket, &msg, 0); 452 | // unsigned char *addr = (unsigned char*)&si_other.sin_addr.s_addr; 453 | // 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); 454 | if (insize <= 0) 455 | continue; 456 | 457 | ssize_t ret = dnshandle(opt, inbuf, insize, outbuf); 458 | if (ret <= 0) 459 | continue; 460 | 461 | bool handled = false; 462 | for (struct cmsghdr*hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) 463 | { 464 | if (hdr->cmsg_level == IPPROTO_IP && hdr->cmsg_type == DSTADDR_SOCKOPT) 465 | { 466 | msg.msg_iov[0].iov_base = outbuf; 467 | msg.msg_iov[0].iov_len = ret; 468 | sendmsg(listenSocket, &msg, 0); 469 | msg.msg_iov[0].iov_base = inbuf; 470 | msg.msg_iov[0].iov_len = sizeof(inbuf); 471 | handled = true; 472 | } 473 | } 474 | if (!handled) 475 | sendto(listenSocket, outbuf, ret, 0, (struct sockaddr*)&si_other, sizeof(si_other)); 476 | } 477 | return 0; 478 | } 479 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define __STDC_FORMAT_MACROS 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "bitcoin.h" 13 | #include "db.h" 14 | 15 | using namespace std; 16 | 17 | bool fTestNet = false; 18 | 19 | class CDnsSeedOpts { 20 | public: 21 | int nThreads; 22 | int nPort; 23 | int nDnsThreads; 24 | int fUseTestNet; 25 | int fWipeBan; 26 | int fWipeIgnore; 27 | const char *mbox; 28 | const char *ns; 29 | const char *host; 30 | const char *tor; 31 | const char *ipv4_proxy; 32 | const char *ipv6_proxy; 33 | std::set filter_whitelist; 34 | 35 | CDnsSeedOpts() : nThreads(96), nDnsThreads(4), nPort(53), mbox(NULL), ns(NULL), host(NULL), tor(NULL), fUseTestNet(false), fWipeBan(false), fWipeIgnore(false), ipv4_proxy(NULL), ipv6_proxy(NULL) {} 36 | 37 | void ParseCommandLine(int argc, char **argv) { 38 | static const char *help = "Bitcoin-seeder\n" 39 | "Usage: %s -h -n [-m ] [-t ] [-p ]\n" 40 | "\n" 41 | "Options:\n" 42 | "-h Hostname of the DNS seed\n" 43 | "-n Hostname of the nameserver\n" 44 | "-m E-Mail address reported in SOA records\n" 45 | "-t Number of crawlers to run in parallel (default 96)\n" 46 | "-d Number of DNS server threads (default 4)\n" 47 | "-p UDP port to listen on (default 53)\n" 48 | "-o Tor proxy IP/Port\n" 49 | "-i IPV4 SOCKS5 proxy IP/Port\n" 50 | "-k IPV6 SOCKS5 proxy IP/Port\n" 51 | "-w f1,f2,... Allow these flag combinations as filters\n" 52 | "--testnet Use testnet\n" 53 | "--wipeban Wipe list of banned nodes\n" 54 | "--wipeignore Wipe list of ignored nodes\n" 55 | "-?, --help Show this text\n" 56 | "\n"; 57 | bool showHelp = false; 58 | 59 | while(1) { 60 | static struct option long_options[] = { 61 | {"host", required_argument, 0, 'h'}, 62 | {"ns", required_argument, 0, 'n'}, 63 | {"mbox", required_argument, 0, 'm'}, 64 | {"threads", required_argument, 0, 't'}, 65 | {"dnsthreads", required_argument, 0, 'd'}, 66 | {"port", required_argument, 0, 'p'}, 67 | {"onion", required_argument, 0, 'o'}, 68 | {"proxyipv4", required_argument, 0, 'i'}, 69 | {"proxyipv6", required_argument, 0, 'k'}, 70 | {"filter", required_argument, 0, 'w'}, 71 | {"testnet", no_argument, &fUseTestNet, 1}, 72 | {"wipeban", no_argument, &fWipeBan, 1}, 73 | {"wipeignore", no_argument, &fWipeBan, 1}, 74 | {"help", no_argument, 0, 'h'}, 75 | {0, 0, 0, 0} 76 | }; 77 | int option_index = 0; 78 | int c = getopt_long(argc, argv, "h:n:m:t:p:d:o:i:k:w:", long_options, &option_index); 79 | if (c == -1) break; 80 | switch (c) { 81 | case 'h': { 82 | host = optarg; 83 | break; 84 | } 85 | 86 | case 'm': { 87 | mbox = optarg; 88 | break; 89 | } 90 | 91 | case 'n': { 92 | ns = optarg; 93 | break; 94 | } 95 | 96 | case 't': { 97 | int n = strtol(optarg, NULL, 10); 98 | if (n > 0 && n < 1000) nThreads = n; 99 | break; 100 | } 101 | 102 | case 'd': { 103 | int n = strtol(optarg, NULL, 10); 104 | if (n > 0 && n < 1000) nDnsThreads = n; 105 | break; 106 | } 107 | 108 | case 'p': { 109 | int p = strtol(optarg, NULL, 10); 110 | if (p > 0 && p < 65536) nPort = p; 111 | break; 112 | } 113 | 114 | case 'o': { 115 | tor = optarg; 116 | break; 117 | } 118 | 119 | case 'i': { 120 | ipv4_proxy = optarg; 121 | break; 122 | } 123 | 124 | case 'k': { 125 | ipv6_proxy = optarg; 126 | break; 127 | } 128 | 129 | case 'w': { 130 | char* ptr = optarg; 131 | while (*ptr != 0) { 132 | unsigned long l = strtoul(ptr, &ptr, 0); 133 | if (*ptr == ',') { 134 | ptr++; 135 | } else if (*ptr != 0) { 136 | break; 137 | } 138 | filter_whitelist.insert(l); 139 | } 140 | break; 141 | } 142 | 143 | case '?': { 144 | showHelp = true; 145 | break; 146 | } 147 | } 148 | } 149 | if (filter_whitelist.empty()) { 150 | filter_whitelist.insert(NODE_NETWORK); 151 | filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM); 152 | filter_whitelist.insert(NODE_NETWORK | NODE_WITNESS); 153 | filter_whitelist.insert(NODE_NETWORK | NODE_WITNESS | NODE_COMPACT_FILTERS); 154 | filter_whitelist.insert(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM); 155 | filter_whitelist.insert(NODE_NETWORK_LIMITED); 156 | filter_whitelist.insert(NODE_NETWORK_LIMITED | NODE_BLOOM); 157 | filter_whitelist.insert(NODE_NETWORK_LIMITED | NODE_WITNESS); 158 | filter_whitelist.insert(NODE_NETWORK_LIMITED | NODE_WITNESS | NODE_COMPACT_FILTERS); 159 | filter_whitelist.insert(NODE_NETWORK_LIMITED | NODE_WITNESS | NODE_BLOOM); 160 | } 161 | if (host != NULL && ns == NULL) showHelp = true; 162 | if (showHelp) fprintf(stderr, help, argv[0]); 163 | } 164 | }; 165 | 166 | #include "dns.h" 167 | 168 | CAddrDb db; 169 | 170 | extern "C" void* ThreadCrawler(void* data) { 171 | int *nThreads=(int*)data; 172 | do { 173 | std::vector ips; 174 | int wait = 5; 175 | db.GetMany(ips, 16, wait); 176 | int64 now = time(NULL); 177 | if (ips.empty()) { 178 | wait *= 1000; 179 | wait += rand() % (500 * *nThreads); 180 | Sleep(wait); 181 | continue; 182 | } 183 | vector addr; 184 | for (int i=0; i cache; 207 | time_t cacheTime; 208 | unsigned int cacheHits; 209 | FlagSpecificData() : nIPv4(0), nIPv6(0), cacheTime(0), cacheHits(0) {} 210 | }; 211 | 212 | dns_opt_t dns_opt; // must be first 213 | const int id; 214 | std::map perflag; 215 | std::atomic dbQueries; 216 | std::set filterWhitelist; 217 | 218 | void cacheHit(uint64_t requestedFlags, bool force = false) { 219 | static bool nets[NET_MAX] = {}; 220 | if (!nets[NET_IPV4]) { 221 | nets[NET_IPV4] = true; 222 | nets[NET_IPV6] = true; 223 | } 224 | time_t now = time(NULL); 225 | FlagSpecificData& thisflag = perflag[requestedFlags]; 226 | thisflag.cacheHits++; 227 | if (force || thisflag.cacheHits * 400 > (thisflag.cache.size()*thisflag.cache.size()) || (thisflag.cacheHits*thisflag.cacheHits * 20 > thisflag.cache.size() && (now - thisflag.cacheTime > 5))) { 228 | set ips; 229 | db.GetIPs(ips, requestedFlags, 1000, nets); 230 | dbQueries++; 231 | thisflag.cache.clear(); 232 | thisflag.nIPv4 = 0; 233 | thisflag.nIPv6 = 0; 234 | thisflag.cache.reserve(ips.size()); 235 | for (set::iterator it = ips.begin(); it != ips.end(); it++) { 236 | struct in_addr addr; 237 | struct in6_addr addr6; 238 | if ((*it).GetInAddr(&addr)) { 239 | addr_t a; 240 | a.v = 4; 241 | memcpy(&a.data.v4, &addr, 4); 242 | thisflag.cache.push_back(a); 243 | thisflag.nIPv4++; 244 | } else if ((*it).GetIn6Addr(&addr6)) { 245 | addr_t a; 246 | a.v = 6; 247 | memcpy(&a.data.v6, &addr6, 16); 248 | thisflag.cache.push_back(a); 249 | thisflag.nIPv6++; 250 | } 251 | } 252 | thisflag.cacheHits = 0; 253 | thisflag.cacheTime = now; 254 | } 255 | } 256 | 257 | CDnsThread(CDnsSeedOpts* opts, int idIn) : id(idIn) { 258 | dns_opt.host = opts->host; 259 | dns_opt.ns = opts->ns; 260 | dns_opt.mbox = opts->mbox; 261 | dns_opt.datattl = 3600; 262 | dns_opt.nsttl = 40000; 263 | dns_opt.cb = GetIPList; 264 | dns_opt.port = opts->nPort; 265 | dns_opt.nRequests = 0; 266 | dbQueries = 0; 267 | perflag.clear(); 268 | filterWhitelist = opts->filter_whitelist; 269 | } 270 | 271 | void run() { 272 | dnsserver(&dns_opt); 273 | } 274 | }; 275 | 276 | extern "C" int GetIPList(void *data, char *requestedHostname, addr_t* addr, int max, int ipv4, int ipv6) { 277 | CDnsThread *thread = (CDnsThread*)data; 278 | 279 | uint64_t requestedFlags = 0; 280 | int hostlen = strlen(requestedHostname); 281 | if (hostlen > 1 && requestedHostname[0] == 'x' && requestedHostname[1] != '0') { 282 | char *pEnd; 283 | uint64_t flags = (uint64_t)strtoull(requestedHostname+1, &pEnd, 16); 284 | if (*pEnd == '.' && pEnd <= requestedHostname+17 && std::find(thread->filterWhitelist.begin(), thread->filterWhitelist.end(), flags) != thread->filterWhitelist.end()) 285 | requestedFlags = flags; 286 | else 287 | return 0; 288 | } 289 | else if (strcasecmp(requestedHostname, thread->dns_opt.host)) 290 | return 0; 291 | thread->cacheHit(requestedFlags); 292 | auto& thisflag = thread->perflag[requestedFlags]; 293 | unsigned int size = thisflag.cache.size(); 294 | unsigned int maxmax = (ipv4 ? thisflag.nIPv4 : 0) + (ipv6 ? thisflag.nIPv6 : 0); 295 | if (max > size) 296 | max = size; 297 | if (max > maxmax) 298 | max = maxmax; 299 | int i=0; 300 | while (i dnsThread; 319 | 320 | extern "C" void* ThreadDNS(void* arg) { 321 | CDnsThread *thread = (CDnsThread*)arg; 322 | thread->run(); 323 | return nullptr; 324 | } 325 | 326 | int StatCompare(const CAddrReport& a, const CAddrReport& b) { 327 | if (a.uptime[4] == b.uptime[4]) { 328 | if (a.uptime[3] == b.uptime[3]) { 329 | return a.clientVersion > b.clientVersion; 330 | } else { 331 | return a.uptime[3] > b.uptime[3]; 332 | } 333 | } else { 334 | return a.uptime[4] > b.uptime[4]; 335 | } 336 | } 337 | 338 | extern "C" void* ThreadDumper(void*) { 339 | int count = 0; 340 | do { 341 | Sleep(100000 << count); // First 100s, than 200s, 400s, 800s, 1600s, and then 3200s forever 342 | if (count < 5) 343 | count++; 344 | { 345 | vector v = db.GetAll(); 346 | sort(v.begin(), v.end(), StatCompare); 347 | FILE *f = fopen("dnsseed.dat.new","w+"); 348 | if (f) { 349 | { 350 | CAutoFile cf(f); 351 | cf << db; 352 | } 353 | rename("dnsseed.dat.new", "dnsseed.dat"); 354 | } 355 | FILE *d = fopen("dnsseed.dump", "w"); 356 | fprintf(d, "# address good lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) %%(30d) blocks svcs version\n"); 357 | double stat[5]={0,0,0,0,0}; 358 | for (vector::const_iterator it = v.begin(); it < v.end(); it++) { 359 | CAddrReport rep = *it; 360 | fprintf(d, "%-47s %4d %11" PRId64 " %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08" PRIx64 " %5i \"%s\"\n", rep.ip.ToString().c_str(), (int)rep.fGood, rep.lastSuccess, 100.0*rep.uptime[0], 100.0*rep.uptime[1], 100.0*rep.uptime[2], 100.0*rep.uptime[3], 100.0*rep.uptime[4], rep.blocks, rep.services, rep.clientVersion, rep.clientSubVersion.c_str()); 361 | stat[0] += rep.uptime[0]; 362 | stat[1] += rep.uptime[1]; 363 | stat[2] += rep.uptime[2]; 364 | stat[3] += rep.uptime[3]; 365 | stat[4] += rep.uptime[4]; 366 | } 367 | fclose(d); 368 | FILE *ff = fopen("dnsstats.log", "a"); 369 | fprintf(ff, "%llu %g %g %g %g %g\n", (unsigned long long)(time(NULL)), stat[0], stat[1], stat[2], stat[3], stat[4]); 370 | fclose(ff); 371 | } 372 | } while(1); 373 | return nullptr; 374 | } 375 | 376 | extern "C" void* ThreadStats(void*) { 377 | bool first = true; 378 | do { 379 | char c[256]; 380 | time_t tim = time(NULL); 381 | struct tm *tmp = localtime(&tim); 382 | strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp); 383 | CAddrDbStats stats; 384 | db.GetStats(stats); 385 | if (first) 386 | { 387 | first = false; 388 | printf("\n\n\n\x1b[3A"); 389 | } 390 | else 391 | printf("\x1b[2K\x1b[u"); 392 | printf("\x1b[s"); 393 | uint64_t requests = 0; 394 | uint64_t queries = 0; 395 | for (unsigned int i=0; idns_opt.nRequests; 397 | queries += dnsThread[i]->dbQueries; 398 | } 399 | 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); 400 | Sleep(1000); 401 | } while(1); 402 | return nullptr; 403 | } 404 | 405 | static const string mainnet_seeds[] = {"dnsseed.bluematt.me", "bitseed.xf2.org", "dnsseed.bitcoin.dashjr.org", "seed.bitcoin.sipa.be", ""}; 406 | static const string testnet_seeds[] = {"testnet-seed.alexykot.me", 407 | "testnet-seed.bitcoin.petertodd.org", 408 | "testnet-seed.bluematt.me", 409 | "testnet-seed.bitcoin.schildbach.de", 410 | ""}; 411 | static const string *seeds = mainnet_seeds; 412 | 413 | extern "C" void* ThreadSeeder(void*) { 414 | if (!fTestNet){ 415 | db.Add(CService("kjy2eqzk4zwi5zd3.onion", 8333), true); 416 | } 417 | do { 418 | for (int i=0; seeds[i] != ""; i++) { 419 | vector ips; 420 | LookupHost(seeds[i].c_str(), ips); 421 | for (vector::iterator it = ips.begin(); it != ips.end(); it++) { 422 | db.Add(CService(*it, GetDefaultPort()), true); 423 | } 424 | } 425 | Sleep(1800000); 426 | } while(1); 427 | return nullptr; 428 | } 429 | 430 | int main(int argc, char **argv) { 431 | signal(SIGPIPE, SIG_IGN); 432 | setbuf(stdout, NULL); 433 | CDnsSeedOpts opts; 434 | opts.ParseCommandLine(argc, argv); 435 | printf("Supporting whitelisted filters: "); 436 | for (std::set::const_iterator it = opts.filter_whitelist.begin(); it != opts.filter_whitelist.end(); it++) { 437 | if (it != opts.filter_whitelist.begin()) { 438 | printf(","); 439 | } 440 | printf("0x%lx", (unsigned long)*it); 441 | } 442 | printf("\n"); 443 | if (opts.tor) { 444 | CService service(opts.tor, 9050); 445 | if (service.IsValid()) { 446 | printf("Using Tor proxy at %s\n", service.ToStringIPPort().c_str()); 447 | SetProxy(NET_TOR, service); 448 | } 449 | } 450 | if (opts.ipv4_proxy) { 451 | CService service(opts.ipv4_proxy, 9050); 452 | if (service.IsValid()) { 453 | printf("Using IPv4 proxy at %s\n", service.ToStringIPPort().c_str()); 454 | SetProxy(NET_IPV4, service); 455 | } 456 | } 457 | if (opts.ipv6_proxy) { 458 | CService service(opts.ipv6_proxy, 9050); 459 | if (service.IsValid()) { 460 | printf("Using IPv6 proxy at %s\n", service.ToStringIPPort().c_str()); 461 | SetProxy(NET_IPV6, service); 462 | } 463 | } 464 | bool fDNS = true; 465 | if (opts.fUseTestNet) { 466 | printf("Using testnet.\n"); 467 | pchMessageStart[0] = 0x0b; 468 | pchMessageStart[1] = 0x11; 469 | pchMessageStart[2] = 0x09; 470 | pchMessageStart[3] = 0x07; 471 | seeds = testnet_seeds; 472 | fTestNet = true; 473 | } 474 | if (!opts.ns) { 475 | printf("No nameserver set. Not starting DNS server.\n"); 476 | fDNS = false; 477 | } 478 | if (fDNS && !opts.host) { 479 | fprintf(stderr, "No hostname set. Please use -h.\n"); 480 | exit(1); 481 | } 482 | if (fDNS && !opts.mbox) { 483 | fprintf(stderr, "No e-mail address set. Please use -m.\n"); 484 | exit(1); 485 | } 486 | FILE *f = fopen("dnsseed.dat","r"); 487 | if (f) { 488 | printf("Loading dnsseed.dat..."); 489 | CAutoFile cf(f); 490 | cf >> db; 491 | if (opts.fWipeBan) 492 | db.banned.clear(); 493 | if (opts.fWipeIgnore) 494 | db.ResetIgnores(); 495 | printf("done\n"); 496 | } 497 | pthread_t threadDns, threadSeed, threadDump, threadStats; 498 | if (fDNS) { 499 | printf("Starting %i DNS threads for %s on %s (port %i)...", opts.nDnsThreads, opts.host, opts.ns, opts.nPort); 500 | dnsThread.clear(); 501 | for (int i=0; i 11 | #include 12 | #include 13 | 14 | #if defined(_MSC_VER) || defined(__BORLANDC__) 15 | typedef __int64 int64; 16 | typedef unsigned __int64 uint64; 17 | #else 18 | typedef long long int64; 19 | typedef unsigned long long uint64; 20 | #endif 21 | #if defined(_MSC_VER) && _MSC_VER < 1300 22 | #define for if (false) ; else for 23 | #endif 24 | 25 | // We have to keep a separate base class without constructors 26 | // so the compiler will let us use it in a union 27 | template 28 | class base_uint 29 | { 30 | protected: 31 | enum { WIDTH=BITS/32 }; 32 | unsigned int pn[WIDTH]; 33 | public: 34 | 35 | bool operator!() const 36 | { 37 | for (int i = 0; i < WIDTH; i++) 38 | if (pn[i] != 0) 39 | return false; 40 | return true; 41 | } 42 | 43 | const base_uint operator~() const 44 | { 45 | base_uint ret; 46 | for (int i = 0; i < WIDTH; i++) 47 | ret.pn[i] = ~pn[i]; 48 | return ret; 49 | } 50 | 51 | const base_uint operator-() const 52 | { 53 | base_uint ret; 54 | for (int i = 0; i < WIDTH; i++) 55 | ret.pn[i] = ~pn[i]; 56 | ret++; 57 | return ret; 58 | } 59 | 60 | 61 | base_uint& operator=(uint64 b) 62 | { 63 | pn[0] = (unsigned int)b; 64 | pn[1] = (unsigned int)(b >> 32); 65 | for (int i = 2; i < WIDTH; i++) 66 | pn[i] = 0; 67 | return *this; 68 | } 69 | 70 | base_uint& operator^=(const base_uint& b) 71 | { 72 | for (int i = 0; i < WIDTH; i++) 73 | pn[i] ^= b.pn[i]; 74 | return *this; 75 | } 76 | 77 | base_uint& operator&=(const base_uint& b) 78 | { 79 | for (int i = 0; i < WIDTH; i++) 80 | pn[i] &= b.pn[i]; 81 | return *this; 82 | } 83 | 84 | base_uint& operator|=(const base_uint& b) 85 | { 86 | for (int i = 0; i < WIDTH; i++) 87 | pn[i] |= b.pn[i]; 88 | return *this; 89 | } 90 | 91 | base_uint& operator^=(uint64 b) 92 | { 93 | pn[0] ^= (unsigned int)b; 94 | pn[1] ^= (unsigned int)(b >> 32); 95 | return *this; 96 | } 97 | 98 | base_uint& operator&=(uint64 b) 99 | { 100 | pn[0] &= (unsigned int)b; 101 | pn[1] &= (unsigned int)(b >> 32); 102 | return *this; 103 | } 104 | 105 | base_uint& operator|=(uint64 b) 106 | { 107 | pn[0] |= (unsigned int)b; 108 | pn[1] |= (unsigned int)(b >> 32); 109 | return *this; 110 | } 111 | 112 | base_uint& operator<<=(unsigned int shift) 113 | { 114 | base_uint a(*this); 115 | for (int i = 0; i < WIDTH; i++) 116 | pn[i] = 0; 117 | int k = shift / 32; 118 | shift = shift % 32; 119 | for (int i = 0; i < WIDTH; i++) 120 | { 121 | if (i+k+1 < WIDTH && shift != 0) 122 | pn[i+k+1] |= (a.pn[i] >> (32-shift)); 123 | if (i+k < WIDTH) 124 | pn[i+k] |= (a.pn[i] << shift); 125 | } 126 | return *this; 127 | } 128 | 129 | base_uint& operator>>=(unsigned int shift) 130 | { 131 | base_uint a(*this); 132 | for (int i = 0; i < WIDTH; i++) 133 | pn[i] = 0; 134 | int k = shift / 32; 135 | shift = shift % 32; 136 | for (int i = 0; i < WIDTH; i++) 137 | { 138 | if (i-k-1 >= 0 && shift != 0) 139 | pn[i-k-1] |= (a.pn[i] << (32-shift)); 140 | if (i-k >= 0) 141 | pn[i-k] |= (a.pn[i] >> shift); 142 | } 143 | return *this; 144 | } 145 | 146 | base_uint& operator+=(const base_uint& b) 147 | { 148 | uint64 carry = 0; 149 | for (int i = 0; i < WIDTH; i++) 150 | { 151 | uint64 n = carry + pn[i] + b.pn[i]; 152 | pn[i] = n & 0xffffffff; 153 | carry = n >> 32; 154 | } 155 | return *this; 156 | } 157 | 158 | base_uint& operator-=(const base_uint& b) 159 | { 160 | *this += -b; 161 | return *this; 162 | } 163 | 164 | base_uint& operator+=(uint64 b64) 165 | { 166 | base_uint b; 167 | b = b64; 168 | *this += b; 169 | return *this; 170 | } 171 | 172 | base_uint& operator-=(uint64 b64) 173 | { 174 | base_uint b; 175 | b = b64; 176 | *this += -b; 177 | return *this; 178 | } 179 | 180 | 181 | base_uint& operator++() 182 | { 183 | // prefix operator 184 | int i = 0; 185 | while (++pn[i] == 0 && i < WIDTH-1) 186 | i++; 187 | return *this; 188 | } 189 | 190 | const base_uint operator++(int) 191 | { 192 | // postfix operator 193 | const base_uint ret = *this; 194 | ++(*this); 195 | return ret; 196 | } 197 | 198 | base_uint& operator--() 199 | { 200 | // prefix operator 201 | int i = 0; 202 | while (--pn[i] == -1 && i < WIDTH-1) 203 | i++; 204 | return *this; 205 | } 206 | 207 | const base_uint operator--(int) 208 | { 209 | // postfix operator 210 | const base_uint ret = *this; 211 | --(*this); 212 | return ret; 213 | } 214 | 215 | 216 | friend inline bool operator<(const base_uint& a, const base_uint& b) 217 | { 218 | for (int i = base_uint::WIDTH-1; i >= 0; i--) 219 | { 220 | if (a.pn[i] < b.pn[i]) 221 | return true; 222 | else if (a.pn[i] > b.pn[i]) 223 | return false; 224 | } 225 | return false; 226 | } 227 | 228 | friend inline bool operator<=(const base_uint& a, const base_uint& b) 229 | { 230 | for (int i = base_uint::WIDTH-1; i >= 0; i--) 231 | { 232 | if (a.pn[i] < b.pn[i]) 233 | return true; 234 | else if (a.pn[i] > b.pn[i]) 235 | return false; 236 | } 237 | return true; 238 | } 239 | 240 | friend inline bool operator>(const base_uint& a, const base_uint& b) 241 | { 242 | for (int i = base_uint::WIDTH-1; i >= 0; i--) 243 | { 244 | if (a.pn[i] > b.pn[i]) 245 | return true; 246 | else if (a.pn[i] < b.pn[i]) 247 | return false; 248 | } 249 | return false; 250 | } 251 | 252 | friend inline bool operator>=(const base_uint& a, const base_uint& b) 253 | { 254 | for (int i = base_uint::WIDTH-1; i >= 0; i--) 255 | { 256 | if (a.pn[i] > b.pn[i]) 257 | return true; 258 | else if (a.pn[i] < b.pn[i]) 259 | return false; 260 | } 261 | return true; 262 | } 263 | 264 | friend inline bool operator==(const base_uint& a, const base_uint& b) 265 | { 266 | for (int i = 0; i < base_uint::WIDTH; i++) 267 | if (a.pn[i] != b.pn[i]) 268 | return false; 269 | return true; 270 | } 271 | 272 | friend inline bool operator==(const base_uint& a, uint64 b) 273 | { 274 | if (a.pn[0] != (unsigned int)b) 275 | return false; 276 | if (a.pn[1] != (unsigned int)(b >> 32)) 277 | return false; 278 | for (int i = 2; i < base_uint::WIDTH; i++) 279 | if (a.pn[i] != 0) 280 | return false; 281 | return true; 282 | } 283 | 284 | friend inline bool operator!=(const base_uint& a, const base_uint& b) 285 | { 286 | return (!(a == b)); 287 | } 288 | 289 | friend inline bool operator!=(const base_uint& a, uint64 b) 290 | { 291 | return (!(a == b)); 292 | } 293 | 294 | 295 | 296 | std::string GetHex() const 297 | { 298 | char psz[sizeof(pn)*2 + 1]; 299 | for (int i = 0; i < sizeof(pn); i++) 300 | sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]); 301 | return std::string(psz, psz + sizeof(pn)*2); 302 | } 303 | 304 | void SetHex(const char* psz) 305 | { 306 | for (int i = 0; i < WIDTH; i++) 307 | pn[i] = 0; 308 | 309 | // skip leading spaces 310 | while (isspace(*psz)) 311 | psz++; 312 | 313 | // skip 0x 314 | if (psz[0] == '0' && tolower(psz[1]) == 'x') 315 | psz += 2; 316 | 317 | // hex string to uint 318 | 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 }; 319 | const char* pbegin = psz; 320 | while (phexdigit[(unsigned char)*psz] || *psz == '0') 321 | psz++; 322 | psz--; 323 | unsigned char* p1 = (unsigned char*)pn; 324 | unsigned char* pend = p1 + WIDTH * 4; 325 | while (psz >= pbegin && p1 < pend) 326 | { 327 | *p1 = phexdigit[(unsigned char)*psz--]; 328 | if (psz >= pbegin) 329 | { 330 | *p1 |= (phexdigit[(unsigned char)*psz--] << 4); 331 | p1++; 332 | } 333 | } 334 | } 335 | 336 | void SetHex(const std::string& str) 337 | { 338 | SetHex(str.c_str()); 339 | } 340 | 341 | std::string ToString() const 342 | { 343 | return (GetHex()); 344 | } 345 | 346 | unsigned char* begin() 347 | { 348 | return (unsigned char*)&pn[0]; 349 | } 350 | 351 | unsigned char* end() 352 | { 353 | return (unsigned char*)&pn[WIDTH]; 354 | } 355 | 356 | unsigned int size() 357 | { 358 | return sizeof(pn); 359 | } 360 | 361 | 362 | unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const 363 | { 364 | return sizeof(pn); 365 | } 366 | 367 | template 368 | void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const 369 | { 370 | s.write((char*)pn, sizeof(pn)); 371 | } 372 | 373 | template 374 | void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) 375 | { 376 | s.read((char*)pn, sizeof(pn)); 377 | } 378 | 379 | 380 | friend class uint160; 381 | friend class uint256; 382 | friend inline int Testuint256AdHoc(std::vector vArg); 383 | }; 384 | 385 | typedef base_uint<160> base_uint160; 386 | typedef base_uint<256> base_uint256; 387 | 388 | 389 | 390 | // 391 | // uint160 and uint256 could be implemented as templates, but to keep 392 | // compile errors and debugging cleaner, they're copy and pasted. 393 | // 394 | 395 | 396 | 397 | ////////////////////////////////////////////////////////////////////////////// 398 | // 399 | // uint160 400 | // 401 | 402 | class uint160 : public base_uint160 403 | { 404 | public: 405 | typedef base_uint160 basetype; 406 | 407 | uint160() 408 | { 409 | for (int i = 0; i < WIDTH; i++) 410 | pn[i] = 0; 411 | } 412 | 413 | uint160(const basetype& b) 414 | { 415 | for (int i = 0; i < WIDTH; i++) 416 | pn[i] = b.pn[i]; 417 | } 418 | 419 | uint160& operator=(const basetype& b) 420 | { 421 | for (int i = 0; i < WIDTH; i++) 422 | pn[i] = b.pn[i]; 423 | return *this; 424 | } 425 | 426 | uint160(uint64 b) 427 | { 428 | pn[0] = (unsigned int)b; 429 | pn[1] = (unsigned int)(b >> 32); 430 | for (int i = 2; i < WIDTH; i++) 431 | pn[i] = 0; 432 | } 433 | 434 | uint160& operator=(uint64 b) 435 | { 436 | pn[0] = (unsigned int)b; 437 | pn[1] = (unsigned int)(b >> 32); 438 | for (int i = 2; i < WIDTH; i++) 439 | pn[i] = 0; 440 | return *this; 441 | } 442 | 443 | explicit uint160(const std::string& str) 444 | { 445 | SetHex(str); 446 | } 447 | 448 | explicit uint160(const std::vector& vch) 449 | { 450 | if (vch.size() == sizeof(pn)) 451 | memcpy(pn, &vch[0], sizeof(pn)); 452 | else 453 | *this = 0; 454 | } 455 | }; 456 | 457 | inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; } 458 | inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; } 459 | inline const uint160 operator<<(const base_uint160& a, unsigned int shift) { return uint160(a) <<= shift; } 460 | inline const uint160 operator>>(const base_uint160& a, unsigned int shift) { return uint160(a) >>= shift; } 461 | inline const uint160 operator<<(const uint160& a, unsigned int shift) { return uint160(a) <<= shift; } 462 | inline const uint160 operator>>(const uint160& a, unsigned int shift) { return uint160(a) >>= shift; } 463 | 464 | inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } 465 | inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } 466 | inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } 467 | inline const uint160 operator+(const base_uint160& a, const base_uint160& b) { return uint160(a) += b; } 468 | inline const uint160 operator-(const base_uint160& a, const base_uint160& b) { return uint160(a) -= b; } 469 | 470 | inline bool operator<(const base_uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } 471 | inline bool operator<=(const base_uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } 472 | inline bool operator>(const base_uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } 473 | inline bool operator>=(const base_uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } 474 | inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } 475 | inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } 476 | inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } 477 | inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } 478 | inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } 479 | inline const uint160 operator+(const base_uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } 480 | inline const uint160 operator-(const base_uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } 481 | 482 | inline bool operator<(const uint160& a, const base_uint160& b) { return (base_uint160)a < (base_uint160)b; } 483 | inline bool operator<=(const uint160& a, const base_uint160& b) { return (base_uint160)a <= (base_uint160)b; } 484 | inline bool operator>(const uint160& a, const base_uint160& b) { return (base_uint160)a > (base_uint160)b; } 485 | inline bool operator>=(const uint160& a, const base_uint160& b) { return (base_uint160)a >= (base_uint160)b; } 486 | inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } 487 | inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } 488 | inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } 489 | inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } 490 | inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } 491 | inline const uint160 operator+(const uint160& a, const base_uint160& b) { return (base_uint160)a + (base_uint160)b; } 492 | inline const uint160 operator-(const uint160& a, const base_uint160& b) { return (base_uint160)a - (base_uint160)b; } 493 | 494 | inline bool operator<(const uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } 495 | inline bool operator<=(const uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } 496 | inline bool operator>(const uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } 497 | inline bool operator>=(const uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } 498 | inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } 499 | inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } 500 | inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } 501 | inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } 502 | inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } 503 | inline const uint160 operator+(const uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } 504 | inline const uint160 operator-(const uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } 505 | 506 | 507 | 508 | 509 | 510 | 511 | ////////////////////////////////////////////////////////////////////////////// 512 | // 513 | // uint256 514 | // 515 | 516 | class uint256 : public base_uint256 517 | { 518 | public: 519 | typedef base_uint256 basetype; 520 | 521 | uint256() 522 | { 523 | for (int i = 0; i < WIDTH; i++) 524 | pn[i] = 0; 525 | } 526 | 527 | uint256(const basetype& b) 528 | { 529 | for (int i = 0; i < WIDTH; i++) 530 | pn[i] = b.pn[i]; 531 | } 532 | 533 | uint256& operator=(const basetype& b) 534 | { 535 | for (int i = 0; i < WIDTH; i++) 536 | pn[i] = b.pn[i]; 537 | return *this; 538 | } 539 | 540 | uint256(uint64 b) 541 | { 542 | pn[0] = (unsigned int)b; 543 | pn[1] = (unsigned int)(b >> 32); 544 | for (int i = 2; i < WIDTH; i++) 545 | pn[i] = 0; 546 | } 547 | 548 | uint256& operator=(uint64 b) 549 | { 550 | pn[0] = (unsigned int)b; 551 | pn[1] = (unsigned int)(b >> 32); 552 | for (int i = 2; i < WIDTH; i++) 553 | pn[i] = 0; 554 | return *this; 555 | } 556 | 557 | explicit uint256(const std::string& str) 558 | { 559 | SetHex(str); 560 | } 561 | 562 | explicit uint256(const std::vector& vch) 563 | { 564 | if (vch.size() == sizeof(pn)) 565 | memcpy(pn, &vch[0], sizeof(pn)); 566 | else 567 | *this = 0; 568 | } 569 | }; 570 | 571 | inline bool operator==(const uint256& a, uint64 b) { return (base_uint256)a == b; } 572 | inline bool operator!=(const uint256& a, uint64 b) { return (base_uint256)a != b; } 573 | inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; } 574 | inline const uint256 operator>>(const base_uint256& a, unsigned int shift) { return uint256(a) >>= shift; } 575 | inline const uint256 operator<<(const uint256& a, unsigned int shift) { return uint256(a) <<= shift; } 576 | inline const uint256 operator>>(const uint256& a, unsigned int shift) { return uint256(a) >>= shift; } 577 | 578 | inline const uint256 operator^(const base_uint256& a, const base_uint256& b) { return uint256(a) ^= b; } 579 | inline const uint256 operator&(const base_uint256& a, const base_uint256& b) { return uint256(a) &= b; } 580 | inline const uint256 operator|(const base_uint256& a, const base_uint256& b) { return uint256(a) |= b; } 581 | inline const uint256 operator+(const base_uint256& a, const base_uint256& b) { return uint256(a) += b; } 582 | inline const uint256 operator-(const base_uint256& a, const base_uint256& b) { return uint256(a) -= b; } 583 | 584 | inline bool operator<(const base_uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } 585 | inline bool operator<=(const base_uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } 586 | inline bool operator>(const base_uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } 587 | inline bool operator>=(const base_uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } 588 | inline bool operator==(const base_uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } 589 | inline bool operator!=(const base_uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } 590 | inline const uint256 operator^(const base_uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } 591 | inline const uint256 operator&(const base_uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } 592 | inline const uint256 operator|(const base_uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } 593 | inline const uint256 operator+(const base_uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } 594 | inline const uint256 operator-(const base_uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } 595 | 596 | inline bool operator<(const uint256& a, const base_uint256& b) { return (base_uint256)a < (base_uint256)b; } 597 | inline bool operator<=(const uint256& a, const base_uint256& b) { return (base_uint256)a <= (base_uint256)b; } 598 | inline bool operator>(const uint256& a, const base_uint256& b) { return (base_uint256)a > (base_uint256)b; } 599 | inline bool operator>=(const uint256& a, const base_uint256& b) { return (base_uint256)a >= (base_uint256)b; } 600 | inline bool operator==(const uint256& a, const base_uint256& b) { return (base_uint256)a == (base_uint256)b; } 601 | inline bool operator!=(const uint256& a, const base_uint256& b) { return (base_uint256)a != (base_uint256)b; } 602 | inline const uint256 operator^(const uint256& a, const base_uint256& b) { return (base_uint256)a ^ (base_uint256)b; } 603 | inline const uint256 operator&(const uint256& a, const base_uint256& b) { return (base_uint256)a & (base_uint256)b; } 604 | inline const uint256 operator|(const uint256& a, const base_uint256& b) { return (base_uint256)a | (base_uint256)b; } 605 | inline const uint256 operator+(const uint256& a, const base_uint256& b) { return (base_uint256)a + (base_uint256)b; } 606 | inline const uint256 operator-(const uint256& a, const base_uint256& b) { return (base_uint256)a - (base_uint256)b; } 607 | 608 | inline bool operator<(const uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } 609 | inline bool operator<=(const uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } 610 | inline bool operator>(const uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } 611 | inline bool operator>=(const uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } 612 | inline bool operator==(const uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } 613 | inline bool operator!=(const uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } 614 | inline const uint256 operator^(const uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } 615 | inline const uint256 operator&(const uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } 616 | inline const uint256 operator|(const uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } 617 | inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } 618 | inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } 619 | 620 | #endif 621 | -------------------------------------------------------------------------------- /netbase.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto 2 | // Copyright (c) 2009-2012 The Bitcoin developers 3 | // Distributed under the MIT/X11 software license, see the accompanying 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | #include "netbase.h" 7 | #include "util.h" 8 | 9 | #ifndef WIN32 10 | #include 11 | #endif 12 | 13 | #include "strlcpy.h" 14 | #include // for to_lower() 15 | 16 | #define printf my_printf 17 | 18 | using namespace std; 19 | 20 | // Settings 21 | typedef std::pair proxyType; 22 | static proxyType proxyInfo[NET_MAX]; 23 | static proxyType nameproxyInfo; 24 | int nConnectTimeout = 5000; 25 | bool fNameLookup = false; 26 | 27 | static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; 28 | 29 | enum Network ParseNetwork(std::string net) { 30 | boost::to_lower(net); 31 | if (net == "ipv4") return NET_IPV4; 32 | if (net == "ipv6") return NET_IPV6; 33 | if (net == "tor") return NET_TOR; 34 | if (net == "i2p") return NET_I2P; 35 | return NET_UNROUTABLE; 36 | } 37 | 38 | void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { 39 | size_t colon = in.find_last_of(':'); 40 | // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator 41 | bool fHaveColon = colon != in.npos; 42 | 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 43 | bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos); 44 | if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) { 45 | char *endp = NULL; 46 | int n = strtol(in.c_str() + colon + 1, &endp, 10); 47 | if (endp && *endp == 0 && n >= 0) { 48 | in = in.substr(0, colon); 49 | if (n > 0 && n < 0x10000) 50 | portOut = n; 51 | } 52 | } 53 | if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']') 54 | hostOut = in.substr(1, in.size()-2); 55 | else 56 | hostOut = in; 57 | } 58 | 59 | bool static LookupIntern(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions, bool fAllowLookup) 60 | { 61 | vIP.clear(); 62 | 63 | { 64 | CNetAddr addr; 65 | if (addr.SetSpecial(std::string(pszName))) { 66 | vIP.push_back(addr); 67 | return true; 68 | } 69 | } 70 | 71 | struct addrinfo aiHint; 72 | memset(&aiHint, 0, sizeof(struct addrinfo)); 73 | 74 | aiHint.ai_socktype = SOCK_STREAM; 75 | aiHint.ai_protocol = IPPROTO_TCP; 76 | #ifdef WIN32 77 | aiHint.ai_family = AF_UNSPEC; 78 | aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; 79 | #else 80 | aiHint.ai_family = AF_UNSPEC; 81 | aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; 82 | #endif 83 | struct addrinfo *aiRes = NULL; 84 | int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes); 85 | if (nErr) 86 | return false; 87 | 88 | struct addrinfo *aiTrav = aiRes; 89 | while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) 90 | { 91 | if (aiTrav->ai_family == AF_INET) 92 | { 93 | assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in)); 94 | vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr)); 95 | } 96 | 97 | if (aiTrav->ai_family == AF_INET6) 98 | { 99 | assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6)); 100 | vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr)); 101 | } 102 | 103 | aiTrav = aiTrav->ai_next; 104 | } 105 | 106 | freeaddrinfo(aiRes); 107 | 108 | return (vIP.size() > 0); 109 | } 110 | 111 | bool LookupHost(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions, bool fAllowLookup) 112 | { 113 | if (pszName[0] == 0) 114 | return false; 115 | char psz[256]; 116 | char *pszHost = psz; 117 | strlcpy(psz, pszName, sizeof(psz)); 118 | if (psz[0] == '[' && psz[strlen(psz)-1] == ']') 119 | { 120 | pszHost = psz+1; 121 | psz[strlen(psz)-1] = 0; 122 | } 123 | 124 | return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); 125 | } 126 | 127 | bool LookupHostNumeric(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions) 128 | { 129 | return LookupHost(pszName, vIP, nMaxSolutions, false); 130 | } 131 | 132 | bool Lookup(const char *pszName, std::vector& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions) 133 | { 134 | if (pszName[0] == 0) 135 | return false; 136 | int port = portDefault; 137 | std::string hostname = ""; 138 | SplitHostPort(std::string(pszName), port, hostname); 139 | 140 | std::vector vIP; 141 | bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup); 142 | if (!fRet) 143 | return false; 144 | vAddr.resize(vIP.size()); 145 | for (unsigned int i = 0; i < vIP.size(); i++) 146 | vAddr[i] = CService(vIP[i], port); 147 | return true; 148 | } 149 | 150 | bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup) 151 | { 152 | std::vector vService; 153 | bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1); 154 | if (!fRet) 155 | return false; 156 | addr = vService[0]; 157 | return true; 158 | } 159 | 160 | bool LookupNumeric(const char *pszName, CService& addr, int portDefault) 161 | { 162 | return Lookup(pszName, addr, portDefault, false); 163 | } 164 | 165 | bool static Socks4(const CService &addrDest, SOCKET& hSocket) 166 | { 167 | printf("SOCKS4 connecting %s\n", addrDest.ToString().c_str()); 168 | if (!addrDest.IsIPv4()) 169 | { 170 | closesocket(hSocket); 171 | return error("Proxy destination is not IPv4"); 172 | } 173 | char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; 174 | struct sockaddr_in addr; 175 | socklen_t len = sizeof(addr); 176 | if (!addrDest.GetSockAddr((struct sockaddr*)&addr, &len) || addr.sin_family != AF_INET) 177 | { 178 | closesocket(hSocket); 179 | return error("Cannot get proxy destination address"); 180 | } 181 | memcpy(pszSocks4IP + 2, &addr.sin_port, 2); 182 | memcpy(pszSocks4IP + 4, &addr.sin_addr, 4); 183 | char* pszSocks4 = pszSocks4IP; 184 | int nSize = sizeof(pszSocks4IP); 185 | 186 | int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL); 187 | if (ret != nSize) 188 | { 189 | closesocket(hSocket); 190 | return error("Error sending to proxy"); 191 | } 192 | char pchRet[8]; 193 | if (recv(hSocket, pchRet, 8, 0) != 8) 194 | { 195 | closesocket(hSocket); 196 | return error("Error reading proxy response"); 197 | } 198 | if (pchRet[1] != 0x5a) 199 | { 200 | closesocket(hSocket); 201 | if (pchRet[1] != 0x5b) 202 | printf("ERROR: Proxy returned error %d\n", pchRet[1]); 203 | return false; 204 | } 205 | printf("SOCKS4 connected %s\n", addrDest.ToString().c_str()); 206 | return true; 207 | } 208 | 209 | bool static Socks5(string strDest, int port, SOCKET& hSocket) 210 | { 211 | printf("SOCKS5 connecting %s\n", strDest.c_str()); 212 | if (strDest.size() > 255) 213 | { 214 | closesocket(hSocket); 215 | return error("Hostname too long"); 216 | } 217 | char pszSocks5Init[] = "\5\1\0"; 218 | char *pszSocks5 = pszSocks5Init; 219 | ssize_t nSize = sizeof(pszSocks5Init) - 1; 220 | 221 | ssize_t ret = send(hSocket, pszSocks5, nSize, MSG_NOSIGNAL); 222 | if (ret != nSize) 223 | { 224 | closesocket(hSocket); 225 | return error("Error sending to proxy"); 226 | } 227 | char pchRet1[2]; 228 | if (recv(hSocket, pchRet1, 2, 0) != 2) 229 | { 230 | closesocket(hSocket); 231 | return error("Error reading proxy response"); 232 | } 233 | if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00) 234 | { 235 | closesocket(hSocket); 236 | return error("Proxy failed to initialize"); 237 | } 238 | string strSocks5("\5\1"); 239 | strSocks5 += '\000'; strSocks5 += '\003'; 240 | strSocks5 += static_cast(std::min((int)strDest.size(), 255)); 241 | strSocks5 += strDest; 242 | strSocks5 += static_cast((port >> 8) & 0xFF); 243 | strSocks5 += static_cast((port >> 0) & 0xFF); 244 | ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL); 245 | if (ret != (ssize_t)strSocks5.size()) 246 | { 247 | closesocket(hSocket); 248 | return error("Error sending to proxy"); 249 | } 250 | char pchRet2[4]; 251 | if (recv(hSocket, pchRet2, 4, 0) != 4) 252 | { 253 | closesocket(hSocket); 254 | return error("Error reading proxy response"); 255 | } 256 | if (pchRet2[0] != 0x05) 257 | { 258 | closesocket(hSocket); 259 | return error("Proxy failed to accept request"); 260 | } 261 | if (pchRet2[1] != 0x00) 262 | { 263 | closesocket(hSocket); 264 | switch (pchRet2[1]) 265 | { 266 | case 0x01: return error("Proxy error: general failure"); 267 | case 0x02: return error("Proxy error: connection not allowed"); 268 | case 0x03: return error("Proxy error: network unreachable"); 269 | case 0x04: return error("Proxy error: host unreachable"); 270 | case 0x05: return error("Proxy error: connection refused"); 271 | case 0x06: return error("Proxy error: TTL expired"); 272 | case 0x07: return error("Proxy error: protocol error"); 273 | case 0x08: return error("Proxy error: address type not supported"); 274 | default: return error("Proxy error: unknown"); 275 | } 276 | } 277 | if (pchRet2[2] != 0x00) 278 | { 279 | closesocket(hSocket); 280 | return error("Error: malformed proxy response"); 281 | } 282 | char pchRet3[256]; 283 | switch (pchRet2[3]) 284 | { 285 | case 0x01: ret = recv(hSocket, pchRet3, 4, 0) != 4; break; 286 | case 0x04: ret = recv(hSocket, pchRet3, 16, 0) != 16; break; 287 | case 0x03: 288 | { 289 | ret = recv(hSocket, pchRet3, 1, 0) != 1; 290 | if (ret) 291 | return error("Error reading from proxy"); 292 | int nRecv = pchRet3[0]; 293 | ret = recv(hSocket, pchRet3, nRecv, 0) != nRecv; 294 | break; 295 | } 296 | default: closesocket(hSocket); return error("Error: malformed proxy response"); 297 | } 298 | if (ret) 299 | { 300 | closesocket(hSocket); 301 | return error("Error reading from proxy"); 302 | } 303 | if (recv(hSocket, pchRet3, 2, 0) != 2) 304 | { 305 | closesocket(hSocket); 306 | return error("Error reading from proxy"); 307 | } 308 | printf("SOCKS5 connected %s\n", strDest.c_str()); 309 | return true; 310 | } 311 | 312 | bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout) 313 | { 314 | hSocketRet = INVALID_SOCKET; 315 | 316 | struct sockaddr_storage sockaddr; 317 | socklen_t len = sizeof(sockaddr); 318 | if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) { 319 | printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str()); 320 | return false; 321 | } 322 | 323 | SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP); 324 | if (hSocket == INVALID_SOCKET) 325 | return false; 326 | #ifdef SO_NOSIGPIPE 327 | int set = 1; 328 | setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); 329 | #endif 330 | 331 | #ifdef WIN32 332 | u_long fNonblock = 1; 333 | if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) 334 | #else 335 | int fFlags = fcntl(hSocket, F_GETFL, 0); 336 | if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1) 337 | #endif 338 | { 339 | closesocket(hSocket); 340 | return false; 341 | } 342 | 343 | if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) 344 | { 345 | // WSAEINVAL is here because some legacy version of winsock uses it 346 | if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL) 347 | { 348 | struct timeval timeout; 349 | timeout.tv_sec = nTimeout / 1000; 350 | timeout.tv_usec = (nTimeout % 1000) * 1000; 351 | 352 | fd_set fdset; 353 | FD_ZERO(&fdset); 354 | FD_SET(hSocket, &fdset); 355 | int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout); 356 | if (nRet == 0) 357 | { 358 | printf("connection timeout\n"); 359 | closesocket(hSocket); 360 | return false; 361 | } 362 | if (nRet == SOCKET_ERROR) 363 | { 364 | printf("select() for connection failed: %i\n",WSAGetLastError()); 365 | closesocket(hSocket); 366 | return false; 367 | } 368 | socklen_t nRetSize = sizeof(nRet); 369 | #ifdef WIN32 370 | if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR) 371 | #else 372 | if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) 373 | #endif 374 | { 375 | printf("getsockopt() for connection failed: %i\n",WSAGetLastError()); 376 | closesocket(hSocket); 377 | return false; 378 | } 379 | if (nRet != 0) 380 | { 381 | printf("connect() failed after select(): %s\n",strerror(nRet)); 382 | closesocket(hSocket); 383 | return false; 384 | } 385 | } 386 | #ifdef WIN32 387 | else if (WSAGetLastError() != WSAEISCONN) 388 | #else 389 | else 390 | #endif 391 | { 392 | printf("connect() failed: %i\n",WSAGetLastError()); 393 | closesocket(hSocket); 394 | return false; 395 | } 396 | } 397 | 398 | // this isn't even strictly necessary 399 | // CNode::ConnectNode immediately turns the socket back to non-blocking 400 | // but we'll turn it back to blocking just in case 401 | #ifdef WIN32 402 | fNonblock = 0; 403 | if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) 404 | #else 405 | fFlags = fcntl(hSocket, F_GETFL, 0); 406 | if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR) 407 | #endif 408 | { 409 | closesocket(hSocket); 410 | return false; 411 | } 412 | 413 | hSocketRet = hSocket; 414 | return true; 415 | } 416 | 417 | bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) { 418 | assert(net >= 0 && net < NET_MAX); 419 | if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5) 420 | return false; 421 | if (nSocksVersion != 0 && !addrProxy.IsValid()) 422 | return false; 423 | proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion); 424 | return true; 425 | } 426 | 427 | bool GetProxy(enum Network net, CService &addrProxy) { 428 | assert(net >= 0 && net < NET_MAX); 429 | if (!proxyInfo[net].second) 430 | return false; 431 | addrProxy = proxyInfo[net].first; 432 | return true; 433 | } 434 | 435 | bool SetNameProxy(CService addrProxy, int nSocksVersion) { 436 | if (nSocksVersion != 0 && nSocksVersion != 5) 437 | return false; 438 | if (nSocksVersion != 0 && !addrProxy.IsValid()) 439 | return false; 440 | nameproxyInfo = std::make_pair(addrProxy, nSocksVersion); 441 | return true; 442 | } 443 | 444 | bool GetNameProxy() { 445 | return nameproxyInfo.second != 0; 446 | } 447 | 448 | bool IsProxy(const CNetAddr &addr) { 449 | for (int i=0; i6 && strName.substr(strName.size() - 6, 6) == ".onion") { 536 | std::vector vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str()); 537 | if (vchAddr.size() != 16-sizeof(pchOnionCat)) 538 | return false; 539 | memcpy(ip, pchOnionCat, sizeof(pchOnionCat)); 540 | for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++) 541 | ip[i + sizeof(pchOnionCat)] = vchAddr[i]; 542 | return true; 543 | } 544 | if (strName.size()>11 && strName.substr(strName.size() - 11, 11) == ".oc.b32.i2p") { 545 | std::vector vchAddr = DecodeBase32(strName.substr(0, strName.size() - 11).c_str()); 546 | if (vchAddr.size() != 16-sizeof(pchGarliCat)) 547 | return false; 548 | memcpy(ip, pchOnionCat, sizeof(pchGarliCat)); 549 | for (unsigned int i=0; i<16-sizeof(pchGarliCat); i++) 550 | ip[i + sizeof(pchGarliCat)] = vchAddr[i]; 551 | return true; 552 | } 553 | return false; 554 | } 555 | 556 | CNetAddr::CNetAddr() 557 | { 558 | Init(); 559 | } 560 | 561 | CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) 562 | { 563 | memcpy(ip, pchIPv4, 12); 564 | memcpy(ip+12, &ipv4Addr, 4); 565 | } 566 | 567 | CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr) 568 | { 569 | memcpy(ip, &ipv6Addr, 16); 570 | } 571 | 572 | CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup) 573 | { 574 | Init(); 575 | std::vector vIP; 576 | if (LookupHost(pszIp, vIP, 1, fAllowLookup)) 577 | *this = vIP[0]; 578 | } 579 | 580 | CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup) 581 | { 582 | Init(); 583 | std::vector vIP; 584 | if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup)) 585 | *this = vIP[0]; 586 | } 587 | 588 | unsigned int CNetAddr::GetByte(int n) const 589 | { 590 | return ip[15-n]; 591 | } 592 | 593 | bool CNetAddr::IsIPv4() const 594 | { 595 | return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); 596 | } 597 | 598 | bool CNetAddr::IsIPv6() const 599 | { 600 | return (!IsIPv4() && !IsTor() && !IsI2P()); 601 | } 602 | 603 | bool CNetAddr::IsRFC1918() const 604 | { 605 | return IsIPv4() && ( 606 | GetByte(3) == 10 || 607 | (GetByte(3) == 192 && GetByte(2) == 168) || 608 | (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); 609 | } 610 | 611 | bool CNetAddr::IsReserved() const 612 | { 613 | return IsIPv4() && (GetByte(3) >= 240); 614 | } 615 | 616 | bool CNetAddr::IsRFC3927() const 617 | { 618 | return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254); 619 | } 620 | 621 | bool CNetAddr::IsRFC3849() const 622 | { 623 | return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8; 624 | } 625 | 626 | bool CNetAddr::IsRFC3964() const 627 | { 628 | return (GetByte(15) == 0x20 && GetByte(14) == 0x02); 629 | } 630 | 631 | bool CNetAddr::IsRFC6052() const 632 | { 633 | static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0}; 634 | return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0); 635 | } 636 | 637 | bool CNetAddr::IsRFC4380() const 638 | { 639 | return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0); 640 | } 641 | 642 | bool CNetAddr::IsRFC4862() const 643 | { 644 | static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0}; 645 | return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0); 646 | } 647 | 648 | bool CNetAddr::IsRFC4193() const 649 | { 650 | return ((GetByte(15) & 0xFE) == 0xFC); 651 | } 652 | 653 | bool CNetAddr::IsRFC6145() const 654 | { 655 | static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0}; 656 | return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0); 657 | } 658 | 659 | bool CNetAddr::IsRFC4843() const 660 | { 661 | return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); 662 | } 663 | 664 | bool CNetAddr::IsTor() const 665 | { 666 | return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); 667 | } 668 | 669 | bool CNetAddr::IsI2P() const 670 | { 671 | return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0); 672 | } 673 | 674 | bool CNetAddr::IsLocal() const 675 | { 676 | // IPv4 loopback 677 | if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) 678 | return true; 679 | 680 | // IPv6 loopback (::1/128) 681 | static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; 682 | if (memcmp(ip, pchLocal, 16) == 0) 683 | return true; 684 | 685 | return false; 686 | } 687 | 688 | bool CNetAddr::IsMulticast() const 689 | { 690 | return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0) 691 | || (GetByte(15) == 0xFF); 692 | } 693 | 694 | bool CNetAddr::IsValid() const 695 | { 696 | // Cleanup 3-byte shifted addresses caused by garbage in size field 697 | // of addr messages from versions before 0.2.9 checksum. 698 | // Two consecutive addr messages look like this: 699 | // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26... 700 | // so if the first length field is garbled, it reads the second batch 701 | // of addr misaligned by 3 bytes. 702 | if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0) 703 | return false; 704 | 705 | // unspecified IPv6 address (::/128) 706 | unsigned char ipNone[16] = {}; 707 | if (memcmp(ip, ipNone, 16) == 0) 708 | return false; 709 | 710 | // documentation IPv6 address 711 | if (IsRFC3849()) 712 | return false; 713 | 714 | if (IsIPv4()) 715 | { 716 | // INADDR_NONE 717 | uint32_t ipNone = INADDR_NONE; 718 | if (memcmp(ip+12, &ipNone, 4) == 0) 719 | return false; 720 | 721 | // 0 722 | ipNone = 0; 723 | if (memcmp(ip+12, &ipNone, 4) == 0) 724 | return false; 725 | } 726 | 727 | return true; 728 | } 729 | 730 | bool CNetAddr::IsRoutable() const 731 | { 732 | return IsValid() && !(IsReserved() || IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsTor() && !IsI2P()) || IsRFC4843() || IsLocal()); 733 | } 734 | 735 | enum Network CNetAddr::GetNetwork() const 736 | { 737 | if (!IsRoutable()) 738 | return NET_UNROUTABLE; 739 | 740 | if (IsIPv4()) 741 | return NET_IPV4; 742 | 743 | if (IsTor()) 744 | return NET_TOR; 745 | 746 | if (IsI2P()) 747 | return NET_I2P; 748 | 749 | return NET_IPV6; 750 | } 751 | 752 | std::string CNetAddr::ToStringIP() const 753 | { 754 | if (IsTor()) 755 | return EncodeBase32(&ip[6], 10) + ".onion"; 756 | if (IsI2P()) 757 | return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p"; 758 | CService serv(*this, 0); 759 | struct sockaddr_storage sockaddr; 760 | socklen_t socklen = sizeof(sockaddr); 761 | if (serv.GetSockAddr((struct sockaddr*)&sockaddr, &socklen)) { 762 | char name[1025] = ""; 763 | if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST)) 764 | return std::string(name); 765 | } 766 | if (IsIPv4()) 767 | return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); 768 | else 769 | return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", 770 | GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12), 771 | GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8), 772 | GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4), 773 | GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0)); 774 | } 775 | 776 | std::string CNetAddr::ToString() const 777 | { 778 | return ToStringIP(); 779 | } 780 | 781 | bool operator==(const CNetAddr& a, const CNetAddr& b) 782 | { 783 | return (memcmp(a.ip, b.ip, 16) == 0); 784 | } 785 | 786 | bool operator!=(const CNetAddr& a, const CNetAddr& b) 787 | { 788 | return (memcmp(a.ip, b.ip, 16) != 0); 789 | } 790 | 791 | bool operator<(const CNetAddr& a, const CNetAddr& b) 792 | { 793 | return (memcmp(a.ip, b.ip, 16) < 0); 794 | } 795 | 796 | bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const 797 | { 798 | if (!IsIPv4()) 799 | return false; 800 | memcpy(pipv4Addr, ip+12, 4); 801 | return true; 802 | } 803 | 804 | bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const 805 | { 806 | memcpy(pipv6Addr, ip, 16); 807 | return true; 808 | } 809 | 810 | // get canonical identifier of an address' group 811 | // no two connections will be attempted to addresses with the same group 812 | std::vector CNetAddr::GetGroup() const 813 | { 814 | std::vector vchRet; 815 | int nClass = NET_IPV6; 816 | int nStartByte = 0; 817 | int nBits = 16; 818 | 819 | // all local addresses belong to the same group 820 | if (IsLocal()) 821 | { 822 | nClass = 255; 823 | nBits = 0; 824 | } 825 | 826 | // all unroutable addresses belong to the same group 827 | if (!IsRoutable()) 828 | { 829 | nClass = NET_UNROUTABLE; 830 | nBits = 0; 831 | } 832 | // for IPv4 addresses, '1' + the 16 higher-order bits of the IP 833 | // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix 834 | else if (IsIPv4() || IsRFC6145() || IsRFC6052()) 835 | { 836 | nClass = NET_IPV4; 837 | nStartByte = 12; 838 | } 839 | // for 6to4 tunnelled addresses, use the encapsulated IPv4 address 840 | else if (IsRFC3964()) 841 | { 842 | nClass = NET_IPV4; 843 | nStartByte = 2; 844 | } 845 | // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address 846 | else if (IsRFC4380()) 847 | { 848 | vchRet.push_back(NET_IPV4); 849 | vchRet.push_back(GetByte(3) ^ 0xFF); 850 | vchRet.push_back(GetByte(2) ^ 0xFF); 851 | return vchRet; 852 | } 853 | else if (IsTor()) 854 | { 855 | nClass = NET_TOR; 856 | nStartByte = 6; 857 | nBits = 4; 858 | } 859 | else if (IsI2P()) 860 | { 861 | nClass = NET_I2P; 862 | nStartByte = 6; 863 | nBits = 4; 864 | } 865 | // for he.net, use /36 groups 866 | else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70) 867 | nBits = 36; 868 | // for the rest of the IPv6 network, use /32 groups 869 | else 870 | nBits = 32; 871 | 872 | vchRet.push_back(nClass); 873 | while (nBits >= 8) 874 | { 875 | vchRet.push_back(GetByte(15 - nStartByte)); 876 | nStartByte++; 877 | nBits -= 8; 878 | } 879 | if (nBits > 0) 880 | vchRet.push_back(GetByte(15 - nStartByte) | ((1 << nBits) - 1)); 881 | 882 | return vchRet; 883 | } 884 | 885 | uint64 CNetAddr::GetHash() const 886 | { 887 | uint256 hash = Hash(&ip[0], &ip[16]); 888 | uint64 nRet; 889 | memcpy(&nRet, &hash, sizeof(nRet)); 890 | return nRet; 891 | } 892 | 893 | void CNetAddr::print() const 894 | { 895 | printf("CNetAddr(%s)\n", ToString().c_str()); 896 | } 897 | 898 | // private extensions to enum Network, only returned by GetExtNetwork, 899 | // and only used in GetReachabilityFrom 900 | static const int NET_UNKNOWN = NET_MAX + 0; 901 | static const int NET_TEREDO = NET_MAX + 1; 902 | int static GetExtNetwork(const CNetAddr *addr) 903 | { 904 | if (addr == NULL) 905 | return NET_UNKNOWN; 906 | if (addr->IsRFC4380()) 907 | return NET_TEREDO; 908 | return addr->GetNetwork(); 909 | } 910 | 911 | /** Calculates a metric for how reachable (*this) is from a given partner */ 912 | int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const 913 | { 914 | enum Reachability { 915 | REACH_UNREACHABLE, 916 | REACH_DEFAULT, 917 | REACH_TEREDO, 918 | REACH_IPV6_WEAK, 919 | REACH_IPV4, 920 | REACH_IPV6_STRONG, 921 | REACH_PRIVATE 922 | }; 923 | 924 | if (!IsRoutable()) 925 | return REACH_UNREACHABLE; 926 | 927 | int ourNet = GetExtNetwork(this); 928 | int theirNet = GetExtNetwork(paddrPartner); 929 | bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145(); 930 | 931 | switch(theirNet) { 932 | case NET_IPV4: 933 | switch(ourNet) { 934 | default: return REACH_DEFAULT; 935 | case NET_IPV4: return REACH_IPV4; 936 | } 937 | case NET_IPV6: 938 | switch(ourNet) { 939 | default: return REACH_DEFAULT; 940 | case NET_TEREDO: return REACH_TEREDO; 941 | case NET_IPV4: return REACH_IPV4; 942 | case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled 943 | } 944 | case NET_TOR: 945 | switch(ourNet) { 946 | default: return REACH_DEFAULT; 947 | case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well 948 | case NET_TOR: return REACH_PRIVATE; 949 | } 950 | case NET_I2P: 951 | switch(ourNet) { 952 | default: return REACH_DEFAULT; 953 | case NET_I2P: return REACH_PRIVATE; 954 | } 955 | case NET_TEREDO: 956 | switch(ourNet) { 957 | default: return REACH_DEFAULT; 958 | case NET_TEREDO: return REACH_TEREDO; 959 | case NET_IPV6: return REACH_IPV6_WEAK; 960 | case NET_IPV4: return REACH_IPV4; 961 | } 962 | case NET_UNKNOWN: 963 | case NET_UNROUTABLE: 964 | default: 965 | switch(ourNet) { 966 | default: return REACH_DEFAULT; 967 | case NET_TEREDO: return REACH_TEREDO; 968 | case NET_IPV6: return REACH_IPV6_WEAK; 969 | case NET_IPV4: return REACH_IPV4; 970 | case NET_I2P: return REACH_PRIVATE; // assume connections from unroutable addresses are 971 | case NET_TOR: return REACH_PRIVATE; // either from Tor/I2P, or don't care about our address 972 | } 973 | } 974 | } 975 | 976 | void CService::Init() 977 | { 978 | port = 0; 979 | } 980 | 981 | CService::CService() 982 | { 983 | Init(); 984 | } 985 | 986 | CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn) 987 | { 988 | } 989 | 990 | CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn) 991 | { 992 | } 993 | 994 | CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn) 995 | { 996 | } 997 | 998 | CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) 999 | { 1000 | assert(addr.sin_family == AF_INET); 1001 | } 1002 | 1003 | CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port)) 1004 | { 1005 | assert(addr.sin6_family == AF_INET6); 1006 | } 1007 | 1008 | bool CService::SetSockAddr(const struct sockaddr *paddr) 1009 | { 1010 | switch (paddr->sa_family) { 1011 | case AF_INET: 1012 | *this = CService(*(const struct sockaddr_in*)paddr); 1013 | return true; 1014 | case AF_INET6: 1015 | *this = CService(*(const struct sockaddr_in6*)paddr); 1016 | return true; 1017 | default: 1018 | return false; 1019 | } 1020 | } 1021 | 1022 | CService::CService(const char *pszIpPort, bool fAllowLookup) 1023 | { 1024 | Init(); 1025 | CService ip; 1026 | if (Lookup(pszIpPort, ip, 0, fAllowLookup)) 1027 | *this = ip; 1028 | } 1029 | 1030 | CService::CService(const char *pszIpPort, int portDefault, bool fAllowLookup) 1031 | { 1032 | Init(); 1033 | CService ip; 1034 | if (Lookup(pszIpPort, ip, portDefault, fAllowLookup)) 1035 | *this = ip; 1036 | } 1037 | 1038 | CService::CService(const std::string &strIpPort, bool fAllowLookup) 1039 | { 1040 | Init(); 1041 | CService ip; 1042 | if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup)) 1043 | *this = ip; 1044 | } 1045 | 1046 | CService::CService(const std::string &strIpPort, int portDefault, bool fAllowLookup) 1047 | { 1048 | Init(); 1049 | CService ip; 1050 | if (Lookup(strIpPort.c_str(), ip, portDefault, fAllowLookup)) 1051 | *this = ip; 1052 | } 1053 | 1054 | unsigned short CService::GetPort() const 1055 | { 1056 | return port; 1057 | } 1058 | 1059 | bool operator==(const CService& a, const CService& b) 1060 | { 1061 | return (CNetAddr)a == (CNetAddr)b && a.port == b.port; 1062 | } 1063 | 1064 | bool operator!=(const CService& a, const CService& b) 1065 | { 1066 | return (CNetAddr)a != (CNetAddr)b || a.port != b.port; 1067 | } 1068 | 1069 | bool operator<(const CService& a, const CService& b) 1070 | { 1071 | return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port); 1072 | } 1073 | 1074 | bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const 1075 | { 1076 | if (IsIPv4()) { 1077 | if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) 1078 | return false; 1079 | *addrlen = sizeof(struct sockaddr_in); 1080 | struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr; 1081 | memset(paddrin, 0, *addrlen); 1082 | if (!GetInAddr(&paddrin->sin_addr)) 1083 | return false; 1084 | paddrin->sin_family = AF_INET; 1085 | paddrin->sin_port = htons(port); 1086 | return true; 1087 | } 1088 | if (IsIPv6()) { 1089 | if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) 1090 | return false; 1091 | *addrlen = sizeof(struct sockaddr_in6); 1092 | struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr; 1093 | memset(paddrin6, 0, *addrlen); 1094 | if (!GetIn6Addr(&paddrin6->sin6_addr)) 1095 | return false; 1096 | paddrin6->sin6_family = AF_INET6; 1097 | paddrin6->sin6_port = htons(port); 1098 | return true; 1099 | } 1100 | return false; 1101 | } 1102 | 1103 | std::vector CService::GetKey() const 1104 | { 1105 | std::vector vKey; 1106 | vKey.resize(18); 1107 | memcpy(&vKey[0], ip, 16); 1108 | vKey[16] = port / 0x100; 1109 | vKey[17] = port & 0x0FF; 1110 | return vKey; 1111 | } 1112 | 1113 | std::string CService::ToStringPort() const 1114 | { 1115 | return strprintf("%u", port); 1116 | } 1117 | 1118 | std::string CService::ToStringIPPort() const 1119 | { 1120 | if (IsIPv4() || IsTor() || IsI2P()) { 1121 | return ToStringIP() + ":" + ToStringPort(); 1122 | } else { 1123 | return "[" + ToStringIP() + "]:" + ToStringPort(); 1124 | } 1125 | } 1126 | 1127 | std::string CService::ToString() const 1128 | { 1129 | return ToStringIPPort(); 1130 | } 1131 | 1132 | void CService::print() const 1133 | { 1134 | printf("CService(%s)\n", ToString().c_str()); 1135 | } 1136 | 1137 | void CService::SetPort(unsigned short portIn) 1138 | { 1139 | port = portIn; 1140 | } 1141 | -------------------------------------------------------------------------------- /serialize.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto 2 | // Copyright (c) 2011 The Bitcoin developers 3 | // Distributed under the MIT/X11 software license, see the accompanying 4 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. 5 | #ifndef BITCOIN_SERIALIZE_H 6 | #define BITCOIN_SERIALIZE_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #if defined(_MSC_VER) || defined(__BORLANDC__) 23 | typedef __int64 int64; 24 | typedef unsigned __int64 uint64; 25 | #else 26 | typedef long long int64; 27 | typedef unsigned long long uint64; 28 | #endif 29 | #if defined(_MSC_VER) && _MSC_VER < 1300 30 | #define for if (false) ; else for 31 | #endif 32 | 33 | #ifdef WIN32 34 | #include 35 | // This is used to attempt to keep keying material out of swap 36 | // Note that VirtualLock does not provide this as a guarantee on Windows, 37 | // but, in practice, memory that has been VirtualLock'd almost never gets written to 38 | // the pagefile except in rare circumstances where memory is extremely low. 39 | #include 40 | #define mlock(p, n) VirtualLock((p), (n)); 41 | #define munlock(p, n) VirtualUnlock((p), (n)); 42 | #else 43 | #include 44 | #include 45 | /* This comes from limits.h if it's not defined there set a sane default */ 46 | #ifndef PAGESIZE 47 | #include 48 | #define PAGESIZE sysconf(_SC_PAGESIZE) 49 | #endif 50 | #define mlock(a,b) \ 51 | mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ 52 | (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) 53 | #define munlock(a,b) \ 54 | munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ 55 | (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) 56 | #endif 57 | 58 | class CScript; 59 | class CDataStream; 60 | class CAutoFile; 61 | static const unsigned int MAX_SIZE = 0x02000000; 62 | 63 | static const int PROTOCOL_VERSION = 60000; 64 | 65 | // Used to bypass the rule against non-const reference to temporary 66 | // where it makes sense with wrappers such as CFlatData or CTxDB 67 | template 68 | inline T& REF(const T& val) 69 | { 70 | return const_cast(val); 71 | } 72 | 73 | ///////////////////////////////////////////////////////////////// 74 | // 75 | // Templates for serializing to anything that looks like a stream, 76 | // i.e. anything that supports .read(char*, int) and .write(char*, int) 77 | // 78 | 79 | enum 80 | { 81 | // primary actions 82 | SER_NETWORK = (1 << 0), 83 | SER_DISK = (1 << 1), 84 | SER_GETHASH = (1 << 2), 85 | 86 | // modifiers 87 | SER_SKIPSIG = (1 << 16), 88 | SER_BLOCKHEADERONLY = (1 << 17), 89 | }; 90 | 91 | #define IMPLEMENT_SERIALIZE(statements) \ 92 | unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const \ 93 | { \ 94 | CSerActionGetSerializeSize ser_action; \ 95 | const bool fGetSize = true; \ 96 | const bool fWrite = false; \ 97 | const bool fRead = false; \ 98 | unsigned int nSerSize = 0; \ 99 | ser_streamplaceholder s; \ 100 | s.nType = nType; \ 101 | s.nVersion = nVersion; \ 102 | {statements} \ 103 | return nSerSize; \ 104 | } \ 105 | template \ 106 | void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const \ 107 | { \ 108 | CSerActionSerialize ser_action; \ 109 | const bool fGetSize = false; \ 110 | const bool fWrite = true; \ 111 | const bool fRead = false; \ 112 | unsigned int nSerSize = 0; \ 113 | {statements} \ 114 | } \ 115 | template \ 116 | void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) \ 117 | { \ 118 | CSerActionUnserialize ser_action; \ 119 | const bool fGetSize = false; \ 120 | const bool fWrite = false; \ 121 | const bool fRead = true; \ 122 | unsigned int nSerSize = 0; \ 123 | {statements} \ 124 | } 125 | 126 | #define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) 127 | 128 | 129 | 130 | 131 | 132 | 133 | // 134 | // Basic types 135 | // 136 | #define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj)) 137 | #define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj)) 138 | 139 | inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); } 140 | inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); } 141 | inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); } 142 | inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); } 143 | inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); } 144 | inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); } 145 | inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); } 146 | inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); } 147 | inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); } 148 | inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); } 149 | inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); } 150 | inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); } 151 | inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); } 152 | 153 | template inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); } 154 | template inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); } 155 | template inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); } 156 | template inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); } 157 | template inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); } 158 | template inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); } 159 | template inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); } 160 | template inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); } 161 | template inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); } 162 | template inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); } 163 | template inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); } 164 | template inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); } 165 | template inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); } 166 | 167 | template inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); } 168 | template inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); } 169 | template inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); } 170 | template inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); } 171 | template inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); } 172 | template inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); } 173 | template inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); } 174 | template inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); } 175 | template inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); } 176 | template inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); } 177 | template inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); } 178 | template inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); } 179 | template inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); } 180 | 181 | inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } 182 | template inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); } 183 | template inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; } 184 | 185 | 186 | 187 | 188 | 189 | 190 | // 191 | // Compact size 192 | // size < 253 -- 1 byte 193 | // size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) 194 | // size <= UINT_MAX -- 5 bytes (254 + 4 bytes) 195 | // size > UINT_MAX -- 9 bytes (255 + 8 bytes) 196 | // 197 | inline unsigned int GetSizeOfCompactSize(uint64 nSize) 198 | { 199 | if (nSize < 253) return sizeof(unsigned char); 200 | else if (nSize <= USHRT_MAX) return sizeof(unsigned char) + sizeof(unsigned short); 201 | else if (nSize <= UINT_MAX) return sizeof(unsigned char) + sizeof(unsigned int); 202 | else return sizeof(unsigned char) + sizeof(uint64); 203 | } 204 | 205 | template 206 | void WriteCompactSize(Stream& os, uint64 nSize) 207 | { 208 | if (nSize < 253) 209 | { 210 | unsigned char chSize = nSize; 211 | WRITEDATA(os, chSize); 212 | } 213 | else if (nSize <= USHRT_MAX) 214 | { 215 | unsigned char chSize = 253; 216 | unsigned short xSize = nSize; 217 | WRITEDATA(os, chSize); 218 | WRITEDATA(os, xSize); 219 | } 220 | else if (nSize <= UINT_MAX) 221 | { 222 | unsigned char chSize = 254; 223 | unsigned int xSize = nSize; 224 | WRITEDATA(os, chSize); 225 | WRITEDATA(os, xSize); 226 | } 227 | else 228 | { 229 | unsigned char chSize = 255; 230 | uint64 xSize = nSize; 231 | WRITEDATA(os, chSize); 232 | WRITEDATA(os, xSize); 233 | } 234 | return; 235 | } 236 | 237 | template 238 | uint64 ReadCompactSize(Stream& is) 239 | { 240 | unsigned char chSize; 241 | READDATA(is, chSize); 242 | uint64 nSizeRet = 0; 243 | if (chSize < 253) 244 | { 245 | nSizeRet = chSize; 246 | } 247 | else if (chSize == 253) 248 | { 249 | unsigned short xSize; 250 | READDATA(is, xSize); 251 | nSizeRet = xSize; 252 | } 253 | else if (chSize == 254) 254 | { 255 | unsigned int xSize; 256 | READDATA(is, xSize); 257 | nSizeRet = xSize; 258 | } 259 | else 260 | { 261 | uint64 xSize; 262 | READDATA(is, xSize); 263 | nSizeRet = xSize; 264 | } 265 | if (nSizeRet > (uint64)MAX_SIZE) 266 | throw std::ios_base::failure("ReadCompactSize() : size too large"); 267 | return nSizeRet; 268 | } 269 | 270 | 271 | 272 | // 273 | // Wrapper for serializing arrays and POD 274 | // There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it 275 | // 276 | #define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) 277 | class CFlatData 278 | { 279 | protected: 280 | char* pbegin; 281 | char* pend; 282 | public: 283 | CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } 284 | char* begin() { return pbegin; } 285 | const char* begin() const { return pbegin; } 286 | char* end() { return pend; } 287 | const char* end() const { return pend; } 288 | 289 | unsigned int GetSerializeSize(int, int=0) const 290 | { 291 | return pend - pbegin; 292 | } 293 | 294 | template 295 | void Serialize(Stream& s, int, int=0) const 296 | { 297 | s.write(pbegin, pend - pbegin); 298 | } 299 | 300 | template 301 | void Unserialize(Stream& s, int, int=0) 302 | { 303 | s.read(pbegin, pend - pbegin); 304 | } 305 | }; 306 | 307 | 308 | 309 | // 310 | // string stored as a fixed length field 311 | // 312 | template 313 | class CFixedFieldString 314 | { 315 | protected: 316 | const std::string* pcstr; 317 | std::string* pstr; 318 | public: 319 | explicit CFixedFieldString(const std::string& str) : pcstr(&str), pstr(NULL) { } 320 | explicit CFixedFieldString(std::string& str) : pcstr(&str), pstr(&str) { } 321 | 322 | unsigned int GetSerializeSize(int, int=0) const 323 | { 324 | return LEN; 325 | } 326 | 327 | template 328 | void Serialize(Stream& s, int, int=0) const 329 | { 330 | char pszBuf[LEN]; 331 | strncpy(pszBuf, pcstr->c_str(), LEN); 332 | s.write(pszBuf, LEN); 333 | } 334 | 335 | template 336 | void Unserialize(Stream& s, int, int=0) 337 | { 338 | if (pstr == NULL) 339 | throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string"); 340 | char pszBuf[LEN+1]; 341 | s.read(pszBuf, LEN); 342 | pszBuf[LEN] = '\0'; 343 | *pstr = pszBuf; 344 | } 345 | }; 346 | 347 | 348 | 349 | 350 | 351 | // 352 | // Forward declarations 353 | // 354 | 355 | // string 356 | template unsigned int GetSerializeSize(const std::basic_string& str, int, int=0); 357 | template void Serialize(Stream& os, const std::basic_string& str, int, int=0); 358 | template void Unserialize(Stream& is, std::basic_string& str, int, int=0); 359 | 360 | // vector 361 | template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&); 362 | template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&); 363 | template inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion=PROTOCOL_VERSION); 364 | template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&); 365 | template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&); 366 | template inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion=PROTOCOL_VERSION); 367 | template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&); 368 | template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&); 369 | template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion=PROTOCOL_VERSION); 370 | 371 | // others derived from vector 372 | extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=PROTOCOL_VERSION); 373 | template void Serialize(Stream& os, const CScript& v, int nType, int nVersion=PROTOCOL_VERSION); 374 | template void Unserialize(Stream& is, CScript& v, int nType, int nVersion=PROTOCOL_VERSION); 375 | 376 | // pair 377 | template unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion=PROTOCOL_VERSION); 378 | template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion=PROTOCOL_VERSION); 379 | template void Unserialize(Stream& is, std::pair& item, int nType, int nVersion=PROTOCOL_VERSION); 380 | 381 | // 3 tuple 382 | template unsigned int GetSerializeSize(const boost::tuple& item, int nType, int nVersion=PROTOCOL_VERSION); 383 | template void Serialize(Stream& os, const boost::tuple& item, int nType, int nVersion=PROTOCOL_VERSION); 384 | template void Unserialize(Stream& is, boost::tuple& item, int nType, int nVersion=PROTOCOL_VERSION); 385 | 386 | // 4 tuple 387 | template unsigned int GetSerializeSize(const boost::tuple& item, int nType, int nVersion=PROTOCOL_VERSION); 388 | template void Serialize(Stream& os, const boost::tuple& item, int nType, int nVersion=PROTOCOL_VERSION); 389 | template void Unserialize(Stream& is, boost::tuple& item, int nType, int nVersion=PROTOCOL_VERSION); 390 | 391 | // map 392 | template unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion=PROTOCOL_VERSION); 393 | template void Serialize(Stream& os, const std::map& m, int nType, int nVersion=PROTOCOL_VERSION); 394 | template void Unserialize(Stream& is, std::map& m, int nType, int nVersion=PROTOCOL_VERSION); 395 | 396 | // set 397 | template unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion=PROTOCOL_VERSION); 398 | template void Serialize(Stream& os, const std::set& m, int nType, int nVersion=PROTOCOL_VERSION); 399 | template void Unserialize(Stream& is, std::set& m, int nType, int nVersion=PROTOCOL_VERSION); 400 | 401 | 402 | 403 | 404 | 405 | // 406 | // If none of the specialized versions above matched, default to calling member function. 407 | // "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. 408 | // The compiler will only cast int to long if none of the other templates matched. 409 | // Thanks to Boost serialization for this idea. 410 | // 411 | template 412 | inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=PROTOCOL_VERSION) 413 | { 414 | return a.GetSerializeSize((int)nType, nVersion); 415 | } 416 | 417 | template 418 | inline void Serialize(Stream& os, const T& a, long nType, int nVersion=PROTOCOL_VERSION) 419 | { 420 | a.Serialize(os, (int)nType, nVersion); 421 | } 422 | 423 | template 424 | inline void Unserialize(Stream& is, T& a, long nType, int nVersion=PROTOCOL_VERSION) 425 | { 426 | a.Unserialize(is, (int)nType, nVersion); 427 | } 428 | 429 | 430 | 431 | 432 | 433 | // 434 | // string 435 | // 436 | template 437 | unsigned int GetSerializeSize(const std::basic_string& str, int, int) 438 | { 439 | return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); 440 | } 441 | 442 | template 443 | void Serialize(Stream& os, const std::basic_string& str, int, int) 444 | { 445 | WriteCompactSize(os, str.size()); 446 | if (!str.empty()) 447 | os.write((char*)&str[0], str.size() * sizeof(str[0])); 448 | } 449 | 450 | template 451 | void Unserialize(Stream& is, std::basic_string& str, int, int) 452 | { 453 | unsigned int nSize = ReadCompactSize(is); 454 | str.resize(nSize); 455 | if (nSize != 0) 456 | is.read((char*)&str[0], nSize * sizeof(str[0])); 457 | } 458 | 459 | 460 | 461 | // 462 | // vector 463 | // 464 | template 465 | unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&) 466 | { 467 | return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); 468 | } 469 | 470 | template 471 | unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&) 472 | { 473 | unsigned int nSize = GetSizeOfCompactSize(v.size()); 474 | for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) 475 | nSize += GetSerializeSize((*vi), nType, nVersion); 476 | return nSize; 477 | } 478 | 479 | template 480 | inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion) 481 | { 482 | return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental()); 483 | } 484 | 485 | 486 | template 487 | void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&) 488 | { 489 | WriteCompactSize(os, v.size()); 490 | if (!v.empty()) 491 | os.write((char*)&v[0], v.size() * sizeof(T)); 492 | } 493 | 494 | template 495 | void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&) 496 | { 497 | WriteCompactSize(os, v.size()); 498 | for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) 499 | ::Serialize(os, (*vi), nType, nVersion); 500 | } 501 | 502 | template 503 | inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion) 504 | { 505 | Serialize_impl(os, v, nType, nVersion, boost::is_fundamental()); 506 | } 507 | 508 | 509 | template 510 | void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&) 511 | { 512 | //unsigned int nSize = ReadCompactSize(is); 513 | //v.resize(nSize); 514 | //is.read((char*)&v[0], nSize * sizeof(T)); 515 | 516 | // Limit size per read so bogus size value won't cause out of memory 517 | v.clear(); 518 | unsigned int nSize = ReadCompactSize(is); 519 | unsigned int i = 0; 520 | while (i < nSize) 521 | { 522 | unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); 523 | v.resize(i + blk); 524 | is.read((char*)&v[i], blk * sizeof(T)); 525 | i += blk; 526 | } 527 | } 528 | 529 | template 530 | void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&) 531 | { 532 | //unsigned int nSize = ReadCompactSize(is); 533 | //v.resize(nSize); 534 | //for (std::vector::iterator vi = v.begin(); vi != v.end(); ++vi) 535 | // Unserialize(is, (*vi), nType, nVersion); 536 | 537 | v.clear(); 538 | unsigned int nSize = ReadCompactSize(is); 539 | unsigned int i = 0; 540 | unsigned int nMid = 0; 541 | while (nMid < nSize) 542 | { 543 | nMid += 5000000 / sizeof(T); 544 | if (nMid > nSize) 545 | nMid = nSize; 546 | v.resize(nMid); 547 | for (; i < nMid; i++) 548 | Unserialize(is, v[i], nType, nVersion); 549 | } 550 | } 551 | 552 | template 553 | inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion) 554 | { 555 | Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental()); 556 | } 557 | 558 | 559 | 560 | // 561 | // others derived from vector 562 | // 563 | inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) 564 | { 565 | return GetSerializeSize((const std::vector&)v, nType, nVersion); 566 | } 567 | 568 | template 569 | void Serialize(Stream& os, const CScript& v, int nType, int nVersion) 570 | { 571 | Serialize(os, (const std::vector&)v, nType, nVersion); 572 | } 573 | 574 | template 575 | void Unserialize(Stream& is, CScript& v, int nType, int nVersion) 576 | { 577 | Unserialize(is, (std::vector&)v, nType, nVersion); 578 | } 579 | 580 | 581 | 582 | // 583 | // pair 584 | // 585 | template 586 | unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion) 587 | { 588 | return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); 589 | } 590 | 591 | template 592 | void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) 593 | { 594 | Serialize(os, item.first, nType, nVersion); 595 | Serialize(os, item.second, nType, nVersion); 596 | } 597 | 598 | template 599 | void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) 600 | { 601 | Unserialize(is, item.first, nType, nVersion); 602 | Unserialize(is, item.second, nType, nVersion); 603 | } 604 | 605 | 606 | 607 | // 608 | // 3 tuple 609 | // 610 | template 611 | unsigned int GetSerializeSize(const boost::tuple& item, int nType, int nVersion) 612 | { 613 | unsigned int nSize = 0; 614 | nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); 615 | nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); 616 | nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); 617 | return nSize; 618 | } 619 | 620 | template 621 | void Serialize(Stream& os, const boost::tuple& item, int nType, int nVersion) 622 | { 623 | Serialize(os, boost::get<0>(item), nType, nVersion); 624 | Serialize(os, boost::get<1>(item), nType, nVersion); 625 | Serialize(os, boost::get<2>(item), nType, nVersion); 626 | } 627 | 628 | template 629 | void Unserialize(Stream& is, boost::tuple& item, int nType, int nVersion) 630 | { 631 | Unserialize(is, boost::get<0>(item), nType, nVersion); 632 | Unserialize(is, boost::get<1>(item), nType, nVersion); 633 | Unserialize(is, boost::get<2>(item), nType, nVersion); 634 | } 635 | 636 | 637 | 638 | // 639 | // 4 tuple 640 | // 641 | template 642 | unsigned int GetSerializeSize(const boost::tuple& item, int nType, int nVersion) 643 | { 644 | unsigned int nSize = 0; 645 | nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); 646 | nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); 647 | nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); 648 | nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion); 649 | return nSize; 650 | } 651 | 652 | template 653 | void Serialize(Stream& os, const boost::tuple& item, int nType, int nVersion) 654 | { 655 | Serialize(os, boost::get<0>(item), nType, nVersion); 656 | Serialize(os, boost::get<1>(item), nType, nVersion); 657 | Serialize(os, boost::get<2>(item), nType, nVersion); 658 | Serialize(os, boost::get<3>(item), nType, nVersion); 659 | } 660 | 661 | template 662 | void Unserialize(Stream& is, boost::tuple& item, int nType, int nVersion) 663 | { 664 | Unserialize(is, boost::get<0>(item), nType, nVersion); 665 | Unserialize(is, boost::get<1>(item), nType, nVersion); 666 | Unserialize(is, boost::get<2>(item), nType, nVersion); 667 | Unserialize(is, boost::get<3>(item), nType, nVersion); 668 | } 669 | 670 | 671 | 672 | // 673 | // map 674 | // 675 | template 676 | unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion) 677 | { 678 | unsigned int nSize = GetSizeOfCompactSize(m.size()); 679 | for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) 680 | nSize += GetSerializeSize((*mi), nType, nVersion); 681 | return nSize; 682 | } 683 | 684 | template 685 | void Serialize(Stream& os, const std::map& m, int nType, int nVersion) 686 | { 687 | WriteCompactSize(os, m.size()); 688 | for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) 689 | Serialize(os, (*mi), nType, nVersion); 690 | } 691 | 692 | template 693 | void Unserialize(Stream& is, std::map& m, int nType, int nVersion) 694 | { 695 | m.clear(); 696 | unsigned int nSize = ReadCompactSize(is); 697 | typename std::map::iterator mi = m.begin(); 698 | for (unsigned int i = 0; i < nSize; i++) 699 | { 700 | std::pair item; 701 | Unserialize(is, item, nType, nVersion); 702 | mi = m.insert(mi, item); 703 | } 704 | } 705 | 706 | 707 | 708 | // 709 | // set 710 | // 711 | template 712 | unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion) 713 | { 714 | unsigned int nSize = GetSizeOfCompactSize(m.size()); 715 | for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) 716 | nSize += GetSerializeSize((*it), nType, nVersion); 717 | return nSize; 718 | } 719 | 720 | template 721 | void Serialize(Stream& os, const std::set& m, int nType, int nVersion) 722 | { 723 | WriteCompactSize(os, m.size()); 724 | for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) 725 | Serialize(os, (*it), nType, nVersion); 726 | } 727 | 728 | template 729 | void Unserialize(Stream& is, std::set& m, int nType, int nVersion) 730 | { 731 | m.clear(); 732 | unsigned int nSize = ReadCompactSize(is); 733 | typename std::set::iterator it = m.begin(); 734 | for (unsigned int i = 0; i < nSize; i++) 735 | { 736 | K key; 737 | Unserialize(is, key, nType, nVersion); 738 | it = m.insert(it, key); 739 | } 740 | } 741 | 742 | 743 | 744 | // 745 | // Support for IMPLEMENT_SERIALIZE and READWRITE macro 746 | // 747 | class CSerActionGetSerializeSize { }; 748 | class CSerActionSerialize { }; 749 | class CSerActionUnserialize { }; 750 | 751 | template 752 | inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action) 753 | { 754 | return ::GetSerializeSize(obj, nType, nVersion); 755 | } 756 | 757 | template 758 | inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) 759 | { 760 | ::Serialize(s, obj, nType, nVersion); 761 | return 0; 762 | } 763 | 764 | template 765 | inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) 766 | { 767 | ::Unserialize(s, obj, nType, nVersion); 768 | return 0; 769 | } 770 | 771 | struct ser_streamplaceholder 772 | { 773 | int nType; 774 | int nVersion; 775 | }; 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | // 786 | // Allocator that locks its contents from being paged 787 | // out of memory and clears its contents before deletion. 788 | // 789 | template 790 | struct secure_allocator : public std::allocator 791 | { 792 | // MSVC8 default copy constructor is broken 793 | typedef std::allocator base; 794 | typedef typename base::size_type size_type; 795 | typedef typename base::difference_type difference_type; 796 | typedef typename base::pointer pointer; 797 | typedef typename base::const_pointer const_pointer; 798 | typedef typename base::reference reference; 799 | typedef typename base::const_reference const_reference; 800 | typedef typename base::value_type value_type; 801 | secure_allocator() throw() {} 802 | secure_allocator(const secure_allocator& a) throw() : base(a) {} 803 | template 804 | secure_allocator(const secure_allocator& a) throw() : base(a) {} 805 | ~secure_allocator() throw() {} 806 | template struct rebind 807 | { typedef secure_allocator<_Other> other; }; 808 | 809 | T* allocate(std::size_t n, const void *hint = 0) 810 | { 811 | T *p; 812 | p = std::allocator::allocate(n, hint); 813 | if (p != NULL) 814 | mlock(p, sizeof(T) * n); 815 | return p; 816 | } 817 | 818 | void deallocate(T* p, std::size_t n) 819 | { 820 | if (p != NULL) 821 | { 822 | memset(p, 0, sizeof(T) * n); 823 | munlock(p, sizeof(T) * n); 824 | } 825 | std::allocator::deallocate(p, n); 826 | } 827 | }; 828 | 829 | 830 | 831 | // 832 | // Double ended buffer combining vector and stream-like interfaces. 833 | // >> and << read and write unformatted data using the above serialization templates. 834 | // Fills with data in linear time; some stringstream implementations take N^2 time. 835 | // 836 | class CDataStream 837 | { 838 | protected: 839 | typedef std::vector > vector_type; 840 | vector_type vch; 841 | unsigned int nReadPos; 842 | short state; 843 | short exceptmask; 844 | public: 845 | int nType; 846 | int nVersion; 847 | 848 | typedef vector_type::allocator_type allocator_type; 849 | typedef vector_type::size_type size_type; 850 | typedef vector_type::difference_type difference_type; 851 | typedef vector_type::reference reference; 852 | typedef vector_type::const_reference const_reference; 853 | typedef vector_type::value_type value_type; 854 | typedef vector_type::iterator iterator; 855 | typedef vector_type::const_iterator const_iterator; 856 | typedef vector_type::reverse_iterator reverse_iterator; 857 | 858 | explicit CDataStream(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) 859 | { 860 | Init(nTypeIn, nVersionIn); 861 | } 862 | 863 | CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend) 864 | { 865 | Init(nTypeIn, nVersionIn); 866 | } 867 | 868 | #if !defined(_MSC_VER) || _MSC_VER >= 1300 869 | CDataStream(const char* pbegin, const char* pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend) 870 | { 871 | Init(nTypeIn, nVersionIn); 872 | } 873 | #endif 874 | 875 | CDataStream(const vector_type& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end()) 876 | { 877 | Init(nTypeIn, nVersionIn); 878 | } 879 | 880 | CDataStream(const std::vector& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end()) 881 | { 882 | Init(nTypeIn, nVersionIn); 883 | } 884 | 885 | CDataStream(const std::vector& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) 886 | { 887 | Init(nTypeIn, nVersionIn); 888 | } 889 | 890 | void Init(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) 891 | { 892 | nReadPos = 0; 893 | nType = nTypeIn; 894 | nVersion = nVersionIn; 895 | state = 0; 896 | exceptmask = std::ios::badbit | std::ios::failbit; 897 | } 898 | 899 | CDataStream& operator+=(const CDataStream& b) 900 | { 901 | vch.insert(vch.end(), b.begin(), b.end()); 902 | return *this; 903 | } 904 | 905 | friend CDataStream operator+(const CDataStream& a, const CDataStream& b) 906 | { 907 | CDataStream ret = a; 908 | ret += b; 909 | return (ret); 910 | } 911 | 912 | std::string str() const 913 | { 914 | return (std::string(begin(), end())); 915 | } 916 | 917 | 918 | // 919 | // Vector subset 920 | // 921 | const_iterator begin() const { return vch.begin() + nReadPos; } 922 | iterator begin() { return vch.begin() + nReadPos; } 923 | const_iterator end() const { return vch.end(); } 924 | iterator end() { return vch.end(); } 925 | size_type size() const { return vch.size() - nReadPos; } 926 | bool empty() const { return vch.size() == nReadPos; } 927 | void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); } 928 | void reserve(size_type n) { vch.reserve(n + nReadPos); } 929 | const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } 930 | reference operator[](size_type pos) { return vch[pos + nReadPos]; } 931 | void clear() { vch.clear(); nReadPos = 0; } 932 | iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } 933 | void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } 934 | 935 | void insert(iterator it, std::vector::const_iterator first, std::vector::const_iterator last) 936 | { 937 | if (it == vch.begin() + nReadPos && last - first <= nReadPos) 938 | { 939 | // special case for inserting at the front when there's room 940 | nReadPos -= (last - first); 941 | memcpy(&vch[nReadPos], &first[0], last - first); 942 | } 943 | else 944 | vch.insert(it, first, last); 945 | } 946 | 947 | #if !defined(_MSC_VER) || _MSC_VER >= 1300 948 | void insert(iterator it, const char* first, const char* last) 949 | { 950 | if (it == vch.begin() + nReadPos && last - first <= nReadPos) 951 | { 952 | // special case for inserting at the front when there's room 953 | nReadPos -= (last - first); 954 | memcpy(&vch[nReadPos], &first[0], last - first); 955 | } 956 | else 957 | vch.insert(it, first, last); 958 | } 959 | #endif 960 | 961 | iterator erase(iterator it) 962 | { 963 | if (it == vch.begin() + nReadPos) 964 | { 965 | // special case for erasing from the front 966 | if (++nReadPos >= vch.size()) 967 | { 968 | // whenever we reach the end, we take the opportunity to clear the buffer 969 | nReadPos = 0; 970 | return vch.erase(vch.begin(), vch.end()); 971 | } 972 | return vch.begin() + nReadPos; 973 | } 974 | else 975 | return vch.erase(it); 976 | } 977 | 978 | iterator erase(iterator first, iterator last) 979 | { 980 | if (first == vch.begin() + nReadPos) 981 | { 982 | // special case for erasing from the front 983 | if (last == vch.end()) 984 | { 985 | nReadPos = 0; 986 | return vch.erase(vch.begin(), vch.end()); 987 | } 988 | else 989 | { 990 | nReadPos = (last - vch.begin()); 991 | return last; 992 | } 993 | } 994 | else 995 | return vch.erase(first, last); 996 | } 997 | 998 | inline void Compact() 999 | { 1000 | vch.erase(vch.begin(), vch.begin() + nReadPos); 1001 | nReadPos = 0; 1002 | } 1003 | 1004 | bool Rewind(size_type n) 1005 | { 1006 | // Rewind by n characters if the buffer hasn't been compacted yet 1007 | if (n > nReadPos) 1008 | return false; 1009 | nReadPos -= n; 1010 | return true; 1011 | } 1012 | 1013 | 1014 | // 1015 | // Stream subset 1016 | // 1017 | void setstate(short bits, const char* psz) 1018 | { 1019 | state |= bits; 1020 | if (state & exceptmask) 1021 | throw std::ios_base::failure(psz); 1022 | } 1023 | 1024 | bool eof() const { return size() == 0; } 1025 | bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } 1026 | bool good() const { return !eof() && (state == 0); } 1027 | void clear(short n) { state = n; } // name conflict with vector clear() 1028 | short exceptions() { return exceptmask; } 1029 | short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; } 1030 | CDataStream* rdbuf() { return this; } 1031 | int in_avail() { return size(); } 1032 | 1033 | void SetType(int n) { nType = n; } 1034 | int GetType() { return nType; } 1035 | void SetVersion(int n) { nVersion = n; } 1036 | int GetVersion() { return nVersion; } 1037 | void ReadVersion() { *this >> nVersion; } 1038 | void WriteVersion() { *this << nVersion; } 1039 | 1040 | CDataStream& read(char* pch, int nSize) 1041 | { 1042 | // Read from the beginning of the buffer 1043 | assert(nSize >= 0); 1044 | unsigned int nReadPosNext = nReadPos + nSize; 1045 | if (nReadPosNext >= vch.size()) 1046 | { 1047 | if (nReadPosNext > vch.size()) 1048 | { 1049 | setstate(std::ios::failbit, "CDataStream::read() : end of data"); 1050 | memset(pch, 0, nSize); 1051 | nSize = vch.size() - nReadPos; 1052 | } 1053 | memcpy(pch, &vch[nReadPos], nSize); 1054 | nReadPos = 0; 1055 | vch.clear(); 1056 | return (*this); 1057 | } 1058 | memcpy(pch, &vch[nReadPos], nSize); 1059 | nReadPos = nReadPosNext; 1060 | return (*this); 1061 | } 1062 | 1063 | CDataStream& ignore(int nSize) 1064 | { 1065 | // Ignore from the beginning of the buffer 1066 | assert(nSize >= 0); 1067 | unsigned int nReadPosNext = nReadPos + nSize; 1068 | if (nReadPosNext >= vch.size()) 1069 | { 1070 | if (nReadPosNext > vch.size()) 1071 | { 1072 | setstate(std::ios::failbit, "CDataStream::ignore() : end of data"); 1073 | nSize = vch.size() - nReadPos; 1074 | } 1075 | nReadPos = 0; 1076 | vch.clear(); 1077 | return (*this); 1078 | } 1079 | nReadPos = nReadPosNext; 1080 | return (*this); 1081 | } 1082 | 1083 | CDataStream& write(const char* pch, int nSize) 1084 | { 1085 | // Write to the end of the buffer 1086 | assert(nSize >= 0); 1087 | vch.insert(vch.end(), pch, pch + nSize); 1088 | return (*this); 1089 | } 1090 | 1091 | template 1092 | void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const 1093 | { 1094 | // Special case: stream << stream concatenates like stream += stream 1095 | if (!vch.empty()) 1096 | s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); 1097 | } 1098 | 1099 | template 1100 | unsigned int GetSerializeSize(const T& obj) 1101 | { 1102 | // Tells the size of the object if serialized to this stream 1103 | return ::GetSerializeSize(obj, nType, nVersion); 1104 | } 1105 | 1106 | template 1107 | CDataStream& operator<<(const T& obj) 1108 | { 1109 | // Serialize to this stream 1110 | ::Serialize(*this, obj, nType, nVersion); 1111 | return (*this); 1112 | } 1113 | 1114 | template 1115 | CDataStream& operator>>(T& obj) 1116 | { 1117 | // Unserialize from this stream 1118 | ::Unserialize(*this, obj, nType, nVersion); 1119 | return (*this); 1120 | } 1121 | }; 1122 | 1123 | #ifdef TESTCDATASTREAM 1124 | // VC6sp6 1125 | // CDataStream: 1126 | // n=1000 0 seconds 1127 | // n=2000 0 seconds 1128 | // n=4000 0 seconds 1129 | // n=8000 0 seconds 1130 | // n=16000 0 seconds 1131 | // n=32000 0 seconds 1132 | // n=64000 1 seconds 1133 | // n=128000 1 seconds 1134 | // n=256000 2 seconds 1135 | // n=512000 4 seconds 1136 | // n=1024000 8 seconds 1137 | // n=2048000 16 seconds 1138 | // n=4096000 32 seconds 1139 | // stringstream: 1140 | // n=1000 1 seconds 1141 | // n=2000 1 seconds 1142 | // n=4000 13 seconds 1143 | // n=8000 87 seconds 1144 | // n=16000 400 seconds 1145 | // n=32000 1660 seconds 1146 | // n=64000 6749 seconds 1147 | // n=128000 27241 seconds 1148 | // n=256000 109804 seconds 1149 | #include 1150 | int main(int argc, char *argv[]) 1151 | { 1152 | vector vch(0xcc, 250); 1153 | printf("CDataStream:\n"); 1154 | for (int n = 1000; n <= 4500000; n *= 2) 1155 | { 1156 | CDataStream ss; 1157 | time_t nStart = time(NULL); 1158 | for (int i = 0; i < n; i++) 1159 | ss.write((char*)&vch[0], vch.size()); 1160 | printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); 1161 | } 1162 | printf("stringstream:\n"); 1163 | for (int n = 1000; n <= 4500000; n *= 2) 1164 | { 1165 | stringstream ss; 1166 | time_t nStart = time(NULL); 1167 | for (int i = 0; i < n; i++) 1168 | ss.write((char*)&vch[0], vch.size()); 1169 | printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); 1170 | } 1171 | } 1172 | #endif 1173 | 1174 | 1175 | 1176 | 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | // 1184 | // Automatic closing wrapper for FILE* 1185 | // - Will automatically close the file when it goes out of scope if not null. 1186 | // - If you're returning the file pointer, return file.release(). 1187 | // - If you need to close the file early, use file.fclose() instead of fclose(file). 1188 | // 1189 | class CAutoFile 1190 | { 1191 | protected: 1192 | FILE* file; 1193 | short state; 1194 | short exceptmask; 1195 | public: 1196 | int nType; 1197 | int nVersion; 1198 | 1199 | typedef FILE element_type; 1200 | 1201 | CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=PROTOCOL_VERSION) 1202 | { 1203 | file = filenew; 1204 | nType = nTypeIn; 1205 | nVersion = nVersionIn; 1206 | state = 0; 1207 | exceptmask = std::ios::badbit | std::ios::failbit; 1208 | } 1209 | 1210 | ~CAutoFile() 1211 | { 1212 | fclose(); 1213 | } 1214 | 1215 | void fclose() 1216 | { 1217 | if (file != NULL && file != stdin && file != stdout && file != stderr) 1218 | ::fclose(file); 1219 | file = NULL; 1220 | } 1221 | 1222 | FILE* release() { FILE* ret = file; file = NULL; return ret; } 1223 | operator FILE*() { return file; } 1224 | FILE* operator->() { return file; } 1225 | FILE& operator*() { return *file; } 1226 | FILE** operator&() { return &file; } 1227 | FILE* operator=(FILE* pnew) { return file = pnew; } 1228 | bool operator!() { return (file == NULL); } 1229 | 1230 | 1231 | // 1232 | // Stream subset 1233 | // 1234 | void setstate(short bits, const char* psz) 1235 | { 1236 | state |= bits; 1237 | if (state & exceptmask) 1238 | throw std::ios_base::failure(psz); 1239 | } 1240 | 1241 | bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } 1242 | bool good() const { return state == 0; } 1243 | void clear(short n = 0) { state = n; } 1244 | short exceptions() { return exceptmask; } 1245 | short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; } 1246 | 1247 | void SetType(int n) { nType = n; } 1248 | int GetType() { return nType; } 1249 | void SetVersion(int n) { nVersion = n; } 1250 | int GetVersion() { return nVersion; } 1251 | void ReadVersion() { *this >> nVersion; } 1252 | void WriteVersion() { *this << nVersion; } 1253 | 1254 | CAutoFile& read(char* pch, int nSize) 1255 | { 1256 | if (!file) 1257 | throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); 1258 | if (fread(pch, 1, nSize, file) != nSize) 1259 | setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); 1260 | return (*this); 1261 | } 1262 | 1263 | CAutoFile& write(const char* pch, int nSize) 1264 | { 1265 | if (!file) 1266 | throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); 1267 | if (fwrite(pch, 1, nSize, file) != nSize) 1268 | setstate(std::ios::failbit, "CAutoFile::write : write failed"); 1269 | return (*this); 1270 | } 1271 | 1272 | template 1273 | unsigned int GetSerializeSize(const T& obj) 1274 | { 1275 | // Tells the size of the object if serialized to this stream 1276 | return ::GetSerializeSize(obj, nType, nVersion); 1277 | } 1278 | 1279 | template 1280 | CAutoFile& operator<<(const T& obj) 1281 | { 1282 | // Serialize to this stream 1283 | if (!file) 1284 | throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL"); 1285 | ::Serialize(*this, obj, nType, nVersion); 1286 | return (*this); 1287 | } 1288 | 1289 | template 1290 | CAutoFile& operator>>(T& obj) 1291 | { 1292 | // Unserialize from this stream 1293 | if (!file) 1294 | throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL"); 1295 | ::Unserialize(*this, obj, nType, nVersion); 1296 | return (*this); 1297 | } 1298 | }; 1299 | 1300 | #endif 1301 | --------------------------------------------------------------------------------