2017-11-09 19:34:51 +01:00
/*
* This file is part of the Flowee project
* Copyright (C) 2009-2010 Satoshi Nakamoto
* Copyright (C) 2009-2015 The Bitcoin Core developers
* Copyright (C) 2017 Peter Tschipper <peter.tschipper@gmailcom>
* Copyright (C) 2017 Tom Zander <tomz@freedommail.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2010-08-29 16:58:15 +00:00
2013-05-27 19:55:01 -04:00
# if defined(HAVE_CONFIG_H)
2018-01-16 10:47:52 +00:00
# include "config/flowee-config.h"
2013-05-27 19:55:01 -04:00
# endif
2011-05-14 16:20:30 -05:00
# include "net.h"
2018-02-12 14:15:24 +01:00
# include "SettingsDefaults.h"
2013-04-13 00:13:08 -05:00
2012-01-04 23:39:45 +01:00
# include "addrman.h"
2013-04-13 00:13:08 -05:00
# include "chainparams.h"
2019-03-29 21:39:08 +01:00
# include <clientversion.h>
2015-09-02 17:03:27 +02:00
# include "consensus/consensus.h"
2016-12-28 13:20:24 +01:00
# include "Application.h"
2019-03-29 21:39:08 +01:00
# include <crypto/common.h>
# include <hash.h>
# include <primitives/transaction.h>
2015-04-02 12:04:59 -04:00
# include "scheduler.h"
2018-02-10 22:48:07 +01:00
# include "UiInterface.h"
2019-03-29 21:39:08 +01:00
# include <utilstrencodings.h>
2019-08-24 13:20:37 +02:00
# include "serverutil.h"
2016-07-20 12:40:07 +02:00
# include "thinblock.h"
2017-06-16 12:52:26 +02:00
# include "policy/policy.h"
2013-04-13 00:13:08 -05:00
2011-10-07 11:02:21 -04:00
# ifdef WIN32
2017-08-17 20:53:23 -06:00
# include <cstring>
2013-04-13 00:13:08 -05:00
# else
2013-07-17 16:51:40 +08:00
# include <fcntl.h>
# endif
2011-03-26 13:01:27 +01:00
# ifdef USE_UPNP
# include <miniupnpc/miniupnpc.h>
2013-04-13 00:13:08 -05:00
# include <miniupnpc/miniwget.h>
2011-03-26 13:01:27 +01:00
# include <miniupnpc/upnpcommands.h>
# include <miniupnpc/upnperrors.h>
# endif
2014-01-30 10:55:55 +01:00
# include <boost/filesystem.hpp>
2014-08-21 16:11:09 +02:00
# include <boost/thread.hpp>
2014-01-30 10:55:55 +01:00
2017-08-17 20:53:23 -06:00
# include <cmath>
2015-04-08 11:20:00 -07:00
2013-06-24 00:23:28 +02:00
// Dump addresses to peers.dat every 15 minutes (900s)
# define DUMP_ADDRESSES_INTERVAL 900
2013-04-13 00:13:08 -05:00
# if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
2013-05-27 19:55:01 -04:00
# define MSG_NOSIGNAL 0
# endif
2013-06-24 00:23:28 +02:00
2014-06-24 09:03:18 +02:00
// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
# ifdef WIN32
# ifndef PROTECTION_LEVEL_UNRESTRICTED
# define PROTECTION_LEVEL_UNRESTRICTED 10
# endif
# ifndef IPV6_PROTECTION_LEVEL
# define IPV6_PROTECTION_LEVEL 23
# endif
# endif
2014-06-21 13:34:36 +02:00
namespace {
2018-03-16 18:32:50 +01:00
# ifndef NDEBUG
const int MAX_OUTBOUND_CONNECTIONS = 4 ;
# else
2018-02-16 12:26:19 +01:00
const int MAX_OUTBOUND_CONNECTIONS = 28 ;
2018-03-16 18:32:50 +01:00
# endif
2014-06-21 13:34:36 +02:00
struct ListenSocket {
SOCKET socket ;
bool whitelisted ;
ListenSocket ( SOCKET socket , bool whitelisted ) : socket ( socket ) , whitelisted ( whitelisted ) { }
} ;
2019-08-24 13:20:37 +02:00
void FileCommit ( FILE * fileout )
{
fflush ( fileout ) ; // harmless if redundantly called
# ifdef WIN32
HANDLE hFile = ( HANDLE ) _get_osfhandle ( _fileno ( fileout ) ) ;
FlushFileBuffers ( hFile ) ;
# else
# if defined(__linux__) || defined(__NetBSD__)
fdatasync ( fileno ( fileout ) ) ;
# elif defined(__APPLE__) && defined(F_FULLFSYNC)
fcntl ( fileno ( fileout ) , F_FULLFSYNC , 0 ) ;
# else
fsync ( fileno ( fileout ) ) ;
# endif
# endif
}
bool RenameOver ( boost : : filesystem : : path src , boost : : filesystem : : path dest )
{
# ifdef WIN32
return MoveFileExA ( src . string ( ) . c_str ( ) , dest . string ( ) . c_str ( ) ,
MOVEFILE_REPLACE_EXISTING ) ! = 0 ;
# else
int rc = std : : rename ( src . string ( ) . c_str ( ) , dest . string ( ) . c_str ( ) ) ;
return ( rc = = 0 ) ;
# endif /* WIN32 */
}
2014-06-21 13:34:36 +02:00
}
2010-08-29 16:58:15 +00:00
//
// Global state variables
//
2012-05-24 19:02:21 +02:00
bool fDiscover = true ;
2014-05-29 12:33:17 +02:00
bool fListen = true ;
2018-12-30 13:33:25 +01:00
uint64_t nLocalServices = NODE_NETWORK | NODE_BITCOIN_CASH ;
2014-05-05 13:22:28 +02:00
CCriticalSection cs_mapLocalHost ;
2017-08-15 10:32:47 -06:00
std : : map < CNetAddr , LocalServiceInfo > mapLocalHost ;
2016-11-22 12:54:44 +01:00
static bool vfLimited [ CNetAddr : : NET_MAX ] = { } ;
2011-08-11 13:41:01 +02:00
static CNode * pnodeLocalHost = NULL ;
2013-04-13 00:13:08 -05:00
uint64_t nLocalHostNonce = 0 ;
2014-06-21 13:34:36 +02:00
static std : : vector < ListenSocket > vhListenSocket ;
2012-01-04 23:39:45 +01:00
CAddrMan addrman ;
2018-02-12 14:15:24 +01:00
int nMaxConnections = Settings : : DefaultMaxPeerConnections ;
2014-09-18 14:08:43 +02:00
bool fAddressesInitialized = false ;
2010-08-29 16:58:15 +00:00
2017-08-15 10:32:47 -06:00
std : : vector < CNode * > vNodes ;
2010-08-29 16:58:15 +00:00
CCriticalSection cs_vNodes ;
2017-08-15 10:32:47 -06:00
std : : map < CInv , CDataStream > mapRelay ;
std : : deque < std : : pair < int64_t , CInv > > vRelayExpiration ;
2010-08-29 16:58:15 +00:00
CCriticalSection cs_mapRelay ;
2016-04-11 12:52:29 -04:00
limitedmap < uint256 , int64_t > mapAlreadyAskedFor ( MAX_INV_SZ ) ;
2010-08-29 16:58:15 +00:00
2017-08-15 10:32:47 -06:00
static std : : deque < std : : string > vOneShots ;
2012-04-24 02:15:00 +02:00
CCriticalSection cs_vOneShots ;
2010-08-29 16:58:15 +00:00
2017-08-15 10:32:47 -06:00
std : : set < CNetAddr > setservAddNodeAddresses ;
2011-12-16 19:48:03 -05:00
CCriticalSection cs_setservAddNodeAddresses ;
2017-08-15 10:32:47 -06:00
std : : vector < std : : string > vAddedNodes ;
2012-07-02 19:55:16 +02:00
CCriticalSection cs_vAddedNodes ;
2013-11-18 01:25:17 +01:00
NodeId nLastNodeId = 0 ;
CCriticalSection cs_nLastNodeId ;
2012-05-10 18:44:07 +02:00
static CSemaphore * semOutbound = NULL ;
2015-04-05 02:35:37 -07:00
boost : : condition_variable messageHandlerCondition ;
2010-08-29 16:58:15 +00:00
2013-06-05 20:21:41 -07:00
// Signals for message handling
static CNodeSignals g_signals ;
CNodeSignals & GetNodeSignals ( ) { return g_signals ; }
2013-01-07 08:07:51 -08:00
2015-05-31 15:36:44 +02:00
void AddOneShot ( const std : : string & strDest )
2012-04-24 02:15:00 +02:00
{
LOCK ( cs_vOneShots ) ;
vOneShots . push_back ( strDest ) ;
}
2011-04-21 10:45:08 -04:00
unsigned short GetListenPort ( )
{
2013-05-07 15:16:25 +02:00
return ( unsigned short ) ( GetArg ( " -port " , Params ( ) . GetDefaultPort ( ) ) ) ;
2011-04-21 10:45:08 -04:00
}
2010-08-29 16:58:15 +00:00
2012-02-12 13:45:24 +01:00
// find 'best' local address for a particular peer
2012-05-10 20:35:13 +02:00
bool GetLocal ( CService & addr , const CNetAddr * paddrPeer )
2012-02-12 13:45:24 +01:00
{
2014-05-29 12:33:17 +02:00
if ( ! fListen )
2012-02-12 13:45:24 +01:00
return false ;
2010-08-29 16:58:15 +00:00
2012-05-13 00:41:24 +02:00
int nBestScore = - 1 ;
2012-02-12 13:45:24 +01:00
int nBestReachability = - 1 ;
{
LOCK ( cs_mapLocalHost ) ;
2017-08-15 10:32:47 -06:00
for ( std : : map < CNetAddr , LocalServiceInfo > : : iterator it = mapLocalHost . begin ( ) ; it ! = mapLocalHost . end ( ) ; it + + )
2012-02-12 13:45:24 +01:00
{
2012-05-13 00:41:24 +02:00
int nScore = ( * it ) . second . nScore ;
2012-02-12 13:45:24 +01:00
int nReachability = ( * it ) . first . GetReachabilityFrom ( paddrPeer ) ;
2012-05-13 00:41:24 +02:00
if ( nReachability > nBestReachability | | ( nReachability = = nBestReachability & & nScore > nBestScore ) )
2012-02-12 13:45:24 +01:00
{
2012-05-13 00:41:24 +02:00
addr = CService ( ( * it ) . first , ( * it ) . second . nPort ) ;
2012-02-12 13:45:24 +01:00
nBestReachability = nReachability ;
2012-05-13 00:41:24 +02:00
nBestScore = nScore ;
2012-02-12 13:45:24 +01:00
}
}
}
2012-05-13 00:41:24 +02:00
return nBestScore > = 0 ;
2012-02-12 13:45:24 +01:00
}
2015-01-23 23:40:50 -05:00
//! Convert the pnSeeds6 array into usable address objects.
static std : : vector < CAddress > convertSeed6 ( const std : : vector < SeedSpec6 > & vSeedsIn )
{
// It'll only connect to one or two seed nodes because once it connects,
// it'll get a pile of addresses with newer timestamps.
// Seed nodes are given a random 'last seen time' of between one and two
// weeks ago.
const int64_t nOneWeek = 7 * 24 * 60 * 60 ;
std : : vector < CAddress > vSeedsOut ;
vSeedsOut . reserve ( vSeedsIn . size ( ) ) ;
for ( std : : vector < SeedSpec6 > : : const_iterator i ( vSeedsIn . begin ( ) ) ; i ! = vSeedsIn . end ( ) ; + + i )
{
struct in6_addr ip ;
memcpy ( & ip , i - > addr , sizeof ( ip ) ) ;
CAddress addr ( CService ( ip , i - > port ) ) ;
addr . nTime = GetTime ( ) - GetRand ( nOneWeek ) - nOneWeek ;
vSeedsOut . push_back ( addr ) ;
}
return vSeedsOut ;
}
2012-02-12 13:45:24 +01:00
// get best local address for a particular peer as a CAddress
2014-07-20 23:32:25 -07:00
// Otherwise, return the unroutable 0.0.0.0 but filled in with
// the normal parameters, since the IP may be changed to a useful
// one by discovery.
2012-02-12 13:45:24 +01:00
CAddress GetLocalAddress ( const CNetAddr * paddrPeer )
{
2014-07-20 23:32:25 -07:00
CAddress ret ( CService ( " 0.0.0.0 " , GetListenPort ( ) ) , 0 ) ;
2012-05-10 20:35:13 +02:00
CService addr ;
2012-02-12 13:45:24 +01:00
if ( GetLocal ( addr , paddrPeer ) )
{
2012-05-10 20:35:13 +02:00
ret = CAddress ( addr ) ;
2012-02-12 13:45:24 +01:00
}
2014-07-20 23:32:25 -07:00
ret . nServices = nLocalServices ;
ret . nTime = GetAdjustedTime ( ) ;
2012-02-12 13:45:24 +01:00
return ret ;
}
2010-08-29 16:58:15 +00:00
2014-07-20 23:32:25 -07:00
int GetnScore ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
2014-07-20 23:32:25 -07:00
LOCK ( cs_mapLocalHost ) ;
if ( mapLocalHost . count ( addr ) = = LOCAL_NONE )
return 0 ;
return mapLocalHost [ addr ] . nScore ;
}
// Is our peer's addrLocal potentially useful as an external IP source?
bool IsPeerAddrLocalGood ( CNode * pnode )
{
return fDiscover & & pnode - > addr . IsRoutable ( ) & & pnode - > addrLocal . IsRoutable ( ) & &
! IsLimited ( pnode - > addrLocal . GetNetwork ( ) ) ;
}
// pushes our own address to a peer
2016-02-12 11:35:32 -07:00
void AdvertiseLocal ( CNode * pnode )
2014-07-20 23:32:25 -07:00
{
if ( fListen & & pnode - > fSuccessfullyConnected )
2012-02-12 13:45:24 +01:00
{
2014-07-20 23:32:25 -07:00
CAddress addrLocal = GetLocalAddress ( & pnode - > addr ) ;
// If discovery is enabled, sometimes give our peer the address it
// tells us that it sees us as in case it has a better idea of our
// address than we do.
if ( IsPeerAddrLocalGood ( pnode ) & & ( ! addrLocal . IsRoutable ( ) | |
GetRand ( ( GetnScore ( addrLocal ) > LOCAL_MANUAL ) ? 8 : 2 ) = = 0 ) )
2012-02-12 13:45:24 +01:00
{
2014-07-20 23:32:25 -07:00
addrLocal . SetIP ( pnode - > addrLocal ) ;
}
2017-08-17 10:05:11 +02:00
if ( addrLocal . IsRoutable ( ) ) {
logDebug ( Log : : Net ) < < " AdvertiseLocal: advertising address " < < addrLocal ;
2014-07-20 23:32:25 -07:00
pnode - > PushAddress ( addrLocal ) ;
2012-02-12 13:45:24 +01:00
}
}
}
// learn a new local address
2012-05-10 20:35:13 +02:00
bool AddLocal ( const CService & addr , int nScore )
2012-02-12 13:45:24 +01:00
{
if ( ! addr . IsRoutable ( ) )
return false ;
2012-05-24 19:02:21 +02:00
if ( ! fDiscover & & nScore < LOCAL_MANUAL )
2012-05-13 14:11:53 +02:00
return false ;
2012-05-13 23:50:49 +02:00
if ( IsLimited ( addr ) )
2012-05-13 15:11:51 +02:00
return false ;
2018-11-20 21:07:53 +01:00
logCritical ( Log : : Net ) < < " AddLocal " < < addr < < " with score: " < < nScore ;
2012-02-12 13:45:24 +01:00
{
LOCK ( cs_mapLocalHost ) ;
2012-05-13 00:41:24 +02:00
bool fAlready = mapLocalHost . count ( addr ) > 0 ;
LocalServiceInfo & info = mapLocalHost [ addr ] ;
if ( ! fAlready | | nScore > = info . nScore ) {
2012-08-29 02:33:25 +02:00
info . nScore = nScore + ( fAlready ? 1 : 0 ) ;
info . nPort = addr . GetPort ( ) ;
2012-05-13 00:41:24 +02:00
}
2012-02-12 13:45:24 +01:00
}
return true ;
}
2012-05-13 01:26:14 +02:00
bool AddLocal ( const CNetAddr & addr , int nScore )
2012-05-10 20:35:13 +02:00
{
2012-05-13 01:26:14 +02:00
return AddLocal ( CService ( addr , GetListenPort ( ) ) , nScore ) ;
2012-05-10 20:35:13 +02:00
}
2018-08-10 18:07:35 +03:00
void RemoveLocal ( const CService & addr )
2015-09-08 17:48:45 +02:00
{
LOCK ( cs_mapLocalHost ) ;
2018-11-20 21:07:53 +01:00
logCritical ( Log : : Net ) < < " RemoveLocal " < < addr ;
2015-09-08 17:48:45 +02:00
mapLocalHost . erase ( addr ) ;
}
2012-05-04 16:46:22 +02:00
/** Make a particular network entirely off-limits (no automatic connects to it) */
2016-11-22 12:54:44 +01:00
void SetLimited ( CNetAddr : : Network net , bool fLimited )
2012-05-04 16:46:22 +02:00
{
2016-11-22 12:54:44 +01:00
if ( net = = CNetAddr : : NET_UNROUTABLE )
2012-05-14 17:15:58 +02:00
return ;
2012-05-04 16:46:22 +02:00
LOCK ( cs_mapLocalHost ) ;
vfLimited [ net ] = fLimited ;
}
2016-11-22 12:54:44 +01:00
bool IsLimited ( CNetAddr : : Network net )
2012-05-04 16:46:22 +02:00
{
LOCK ( cs_mapLocalHost ) ;
2012-05-14 17:15:58 +02:00
return vfLimited [ net ] ;
}
bool IsLimited ( const CNetAddr & addr )
{
return IsLimited ( addr . GetNetwork ( ) ) ;
2012-05-04 16:46:22 +02:00
}
/** vote for a local address */
2012-05-10 20:35:13 +02:00
bool SeenLocal ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
{
LOCK ( cs_mapLocalHost ) ;
if ( mapLocalHost . count ( addr ) = = 0 )
return false ;
2012-05-13 00:41:24 +02:00
mapLocalHost [ addr ] . nScore + + ;
2012-02-12 13:45:24 +01:00
}
return true ;
}
2014-07-20 23:32:25 -07:00
2012-05-04 16:46:22 +02:00
/** check whether a given address is potentially local */
2012-05-10 20:35:13 +02:00
bool IsLocal ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
LOCK ( cs_mapLocalHost ) ;
return mapLocalHost . count ( addr ) > 0 ;
}
2010-08-29 16:58:15 +00:00
2014-07-30 15:31:36 +02:00
/** check whether a given network is one we can probably connect to */
2016-11-22 12:54:44 +01:00
bool IsReachable ( CNetAddr : : Network net )
2012-04-10 20:22:04 +02:00
{
LOCK ( cs_mapLocalHost ) ;
2016-02-17 22:44:32 -08:00
return ! vfLimited [ net ] ;
2012-04-10 20:22:04 +02:00
}
2010-08-29 16:58:15 +00:00
2012-05-04 16:46:22 +02:00
/** check whether a given address is in a network we can probably connect to */
2012-04-10 20:22:04 +02:00
bool IsReachable ( const CNetAddr & addr )
{
2016-11-22 12:54:44 +01:00
CNetAddr : : Network net = addr . GetNetwork ( ) ;
2014-07-30 15:31:36 +02:00
return IsReachable ( net ) ;
2012-04-10 20:22:04 +02:00
}
2010-08-29 16:58:15 +00:00
2012-01-03 23:33:31 +01:00
void AddressCurrentlyConnected ( const CService & addr )
2010-08-29 16:58:15 +00:00
{
2012-01-04 23:39:45 +01:00
addrman . Connected ( addr ) ;
2010-08-29 16:58:15 +00:00
}
2013-04-13 00:13:08 -05:00
uint64_t CNode : : nTotalBytesRecv = 0 ;
uint64_t CNode : : nTotalBytesSent = 0 ;
2013-08-23 02:09:32 +10:00
CCriticalSection CNode : : cs_totalBytesRecv ;
CCriticalSection CNode : : cs_totalBytesSent ;
2010-08-29 16:58:15 +00:00
2015-09-02 17:03:27 +02:00
uint64_t CNode : : nMaxOutboundLimit = 0 ;
uint64_t CNode : : nMaxOutboundTotalBytesSentInCycle = 0 ;
uint64_t CNode : : nMaxOutboundTimeframe = 60 * 60 * 24 ; //1 day
uint64_t CNode : : nMaxOutboundCycleStartTime = 0 ;
2012-01-03 23:33:31 +01:00
CNode * FindNode ( const CNetAddr & ip )
2010-08-29 16:58:15 +00:00
{
2013-04-04 11:30:55 +02:00
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes )
2013-04-04 11:30:55 +02:00
if ( ( CNetAddr ) pnode - > addr = = ip )
return ( pnode ) ;
2010-08-29 16:58:15 +00:00
return NULL ;
}
2015-05-25 20:03:51 +02:00
CNode * FindNode ( const CSubNet & subNet )
{
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes )
2015-05-25 20:03:51 +02:00
if ( subNet . Match ( ( CNetAddr ) pnode - > addr ) )
return ( pnode ) ;
return NULL ;
}
2014-07-24 16:29:41 +02:00
CNode * FindNode ( const std : : string & addrName )
2012-04-19 17:38:03 +02:00
{
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes )
2012-04-19 17:38:03 +02:00
if ( pnode - > addrName = = addrName )
return ( pnode ) ;
return NULL ;
}
2012-01-03 23:33:31 +01:00
CNode * FindNode ( const CService & addr )
2010-08-29 16:58:15 +00:00
{
2013-04-04 11:30:55 +02:00
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes )
2013-04-04 11:30:55 +02:00
if ( ( CService ) pnode - > addr = = addr )
return ( pnode ) ;
2010-08-29 16:58:15 +00:00
return NULL ;
}
2018-01-15 15:26:12 +00:00
CNode * FindNode ( int nodeId )
{
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodes )
if ( pnode - > id = = nodeId )
return ( pnode ) ;
return nullptr ;
}
2013-03-29 00:43:31 +01:00
CNode * ConnectNode ( CAddress addrConnect , const char * pszDest )
2010-08-29 16:58:15 +00:00
{
2012-04-24 02:15:00 +02:00
if ( pszDest = = NULL ) {
2012-02-12 13:45:24 +01:00
if ( IsLocal ( addrConnect ) )
2012-04-19 17:38:03 +02:00
return NULL ;
2010-08-29 16:58:15 +00:00
2012-04-19 17:38:03 +02:00
// Look for an existing connection
CNode * pnode = FindNode ( ( CService ) addrConnect ) ;
if ( pnode )
{
2013-03-29 00:43:31 +01:00
pnode - > AddRef ( ) ;
2012-04-19 17:38:03 +02:00
return pnode ;
}
2010-08-29 16:58:15 +00:00
}
2017-07-23 22:16:30 +02:00
logInfo ( Log : : Net ) < < Log : : precision ( 1 ) < < Log : : Fixed < < " trying connection " < < ( pszDest ? pszDest : addrConnect . ToString ( ) )
2017-10-06 16:34:20 +02:00
< < " lastseen: " < < ( addrConnect . nTime = = 0 ? - 1 : ( GetAdjustedTime ( ) - addrConnect . nTime ) / 3600.0 )
2017-07-23 22:16:30 +02:00
< < " hrs " ;
2010-08-29 16:58:15 +00:00
// Connect
SOCKET hSocket ;
2014-12-02 17:43:42 +01:00
bool proxyConnectionFailed = false ;
if ( pszDest ? ConnectSocketByName ( addrConnect , hSocket , pszDest , Params ( ) . GetDefaultPort ( ) , nConnectTimeout , & proxyConnectionFailed ) :
ConnectSocket ( addrConnect , hSocket , nConnectTimeout , & proxyConnectionFailed ) )
2010-08-29 16:58:15 +00:00
{
2015-07-09 18:23:27 -04:00
if ( ! IsSelectableSocket ( hSocket ) ) {
2018-11-20 21:07:53 +01:00
logCritical ( Log : : Net ) < < " Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?) " ;
2015-07-09 18:23:27 -04:00
CloseSocket ( hSocket ) ;
return NULL ;
}
2012-04-19 17:38:03 +02:00
addrman . Attempt ( addrConnect ) ;
2010-08-29 16:58:15 +00:00
// Add node
2012-04-19 17:38:03 +02:00
CNode * pnode = new CNode ( hSocket , addrConnect , pszDest ? pszDest : " " , false ) ;
2017-07-30 18:56:23 +02:00
pnode - > PushVersion ( ) ;
2012-04-19 17:38:03 +02:00
2017-07-30 18:56:23 +02:00
pnode - > AddRef ( ) ;
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_vNodes ) ;
2010-08-29 16:58:15 +00:00
vNodes . push_back ( pnode ) ;
2012-04-06 18:39:12 +02:00
}
2010-08-29 16:58:15 +00:00
pnode - > nTimeConnected = GetTime ( ) ;
2014-02-26 17:55:04 -08:00
2010-08-29 16:58:15 +00:00
return pnode ;
2014-12-02 17:43:42 +01:00
} else if ( ! proxyConnectionFailed ) {
// If connecting to the node failed, and failure is not caused by a problem connecting to
// the proxy, mark this as an attempt.
addrman . Attempt ( addrConnect ) ;
2010-08-29 16:58:15 +00:00
}
2014-05-24 11:14:52 +02:00
return NULL ;
2010-08-29 16:58:15 +00:00
}
void CNode : : CloseSocketDisconnect ( )
{
fDisconnect = true ;
if ( hSocket ! = INVALID_SOCKET )
{
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " disconnecting peer " < < id ;
2014-07-10 12:13:03 +02:00
CloseSocket ( hSocket ) ;
2010-08-29 16:58:15 +00:00
}
2013-04-05 00:43:04 +02:00
// in case this fails, we'll empty the recv buffer when the CNode is deleted
TRY_LOCK ( cs_vRecvMsg , lockRecv ) ;
if ( lockRecv )
vRecvMsg . clear ( ) ;
2010-08-29 16:58:15 +00:00
}
2011-12-16 16:26:14 -05:00
void CNode : : PushVersion ( )
{
2013-10-10 23:07:44 +02:00
int nBestHeight = g_signals . GetHeight ( ) . get_value_or ( 0 ) ;
2013-04-13 00:13:08 -05:00
int64_t nTime = ( fInbound ? GetAdjustedTime ( ) : GetTime ( ) ) ;
2012-05-24 19:02:21 +02:00
CAddress addrYou = ( addr . IsRoutable ( ) & & ! IsProxy ( addr ) ? addr : CAddress ( CService ( " 0.0.0.0 " , 0 ) ) ) ;
2012-02-12 13:45:24 +01:00
CAddress addrMe = GetLocalAddress ( & addr ) ;
2014-06-24 14:27:32 +02:00
GetRandBytes ( ( unsigned char * ) & nLocalHostNonce , sizeof ( nLocalHostNonce ) ) ;
2014-02-26 17:55:04 -08:00
if ( fLogIPs )
2017-07-23 22:16:30 +02:00
logInfo ( Log : : Net ) < < " send version message: version " < < PROTOCOL_VERSION < < " blocks " < < nBestHeight < < " us " < < addrMe < < " them " < < addrYou < < " peer " < < id ;
2014-02-26 17:55:04 -08:00
else
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " send version message: version " < < PROTOCOL_VERSION < < " blocks " < < nBestHeight < < " us " < < addrMe < < " peer " < < id ;
2015-12-07 15:31:32 +01:00
PushMessage ( NetMsgType : : VERSION , PROTOCOL_VERSION , nLocalServices , nTime , addrYou , addrMe ,
2018-02-12 14:15:24 +01:00
nLocalHostNonce , Application : : userAgent ( ) , nBestHeight , ! GetBoolArg ( " -blocksonly " , Settings : : DefaultBlocksOnly ) ) ;
2011-12-16 16:26:14 -05:00
}
2015-06-26 21:38:33 +02:00
banmap_t CNode : : setBanned ;
2011-09-06 16:09:04 -04:00
CCriticalSection CNode : : cs_setBanned ;
2015-06-19 15:27:37 +02:00
bool CNode : : setBannedIsDirty ;
2011-09-06 16:09:04 -04:00
void CNode : : ClearBanned ( )
{
2015-06-19 13:31:33 +02:00
LOCK ( cs_setBanned ) ;
2011-09-06 16:09:04 -04:00
setBanned . clear ( ) ;
2015-06-19 15:27:37 +02:00
setBannedIsDirty = true ;
2011-09-06 16:09:04 -04:00
}
2012-01-03 23:33:31 +01:00
bool CNode : : IsBanned ( CNetAddr ip )
2011-09-06 16:09:04 -04:00
{
bool fResult = false ;
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_setBanned ) ;
2015-06-26 21:38:33 +02:00
for ( banmap_t : : iterator it = setBanned . begin ( ) ; it ! = setBanned . end ( ) ; it + + )
2015-05-25 20:03:51 +02:00
{
CSubNet subNet = ( * it ) . first ;
2015-06-26 21:38:33 +02:00
CBanEntry banEntry = ( * it ) . second ;
2015-05-25 20:03:51 +02:00
2015-06-26 21:38:33 +02:00
if ( subNet . Match ( ip ) & & GetTime ( ) < banEntry . nBanUntil )
2015-05-25 20:03:51 +02:00
fResult = true ;
}
}
return fResult ;
}
bool CNode : : IsBanned ( CSubNet subnet )
{
bool fResult = false ;
{
LOCK ( cs_setBanned ) ;
2015-06-26 21:38:33 +02:00
banmap_t : : iterator i = setBanned . find ( subnet ) ;
2011-09-06 16:09:04 -04:00
if ( i ! = setBanned . end ( ) )
{
2015-06-26 21:38:33 +02:00
CBanEntry banEntry = ( * i ) . second ;
if ( GetTime ( ) < banEntry . nBanUntil )
2011-09-06 16:09:04 -04:00
fResult = true ;
}
}
return fResult ;
}
2015-06-26 21:38:33 +02:00
void CNode : : Ban ( const CNetAddr & addr , const BanReason & banReason , int64_t bantimeoffset , bool sinceUnixEpoch ) {
2015-06-29 20:37:22 +02:00
CSubNet subNet ( addr ) ;
2015-06-26 21:38:33 +02:00
Ban ( subNet , banReason , bantimeoffset , sinceUnixEpoch ) ;
2015-05-25 20:03:51 +02:00
}
2015-06-26 21:38:33 +02:00
void CNode : : Ban ( const CSubNet & subNet , const BanReason & banReason , int64_t bantimeoffset , bool sinceUnixEpoch ) {
CBanEntry banEntry ( GetTime ( ) ) ;
banEntry . banReason = banReason ;
if ( bantimeoffset < = 0 )
{
2018-02-12 14:15:24 +01:00
bantimeoffset = GetArg ( " -bantime " , Settings : : DefaultMisbehavingBantime ) ;
2015-06-26 21:38:33 +02:00
sinceUnixEpoch = false ;
}
banEntry . nBanUntil = ( sinceUnixEpoch ? 0 : GetTime ( ) ) + bantimeoffset ;
2015-05-19 10:07:23 +02:00
LOCK ( cs_setBanned ) ;
2015-06-26 21:38:33 +02:00
if ( setBanned [ subNet ] . nBanUntil < banEntry . nBanUntil )
setBanned [ subNet ] = banEntry ;
2015-06-19 15:27:37 +02:00
setBannedIsDirty = true ;
2011-09-06 16:09:04 -04:00
}
2015-05-19 10:07:23 +02:00
bool CNode : : Unban ( const CNetAddr & addr ) {
2015-06-29 20:37:22 +02:00
CSubNet subNet ( addr ) ;
2015-05-25 20:03:51 +02:00
return Unban ( subNet ) ;
}
bool CNode : : Unban ( const CSubNet & subNet ) {
2015-05-19 10:07:23 +02:00
LOCK ( cs_setBanned ) ;
2015-05-25 20:03:51 +02:00
if ( setBanned . erase ( subNet ) )
2015-06-19 15:27:37 +02:00
{
setBannedIsDirty = true ;
2015-05-19 10:07:23 +02:00
return true ;
2015-06-19 15:27:37 +02:00
}
2015-05-19 10:07:23 +02:00
return false ;
}
2015-06-26 21:38:33 +02:00
void CNode : : GetBanned ( banmap_t & banMap )
2015-05-19 10:07:23 +02:00
{
LOCK ( cs_setBanned ) ;
banMap = setBanned ; //create a thread safe copy
}
2015-06-26 21:38:33 +02:00
void CNode : : SetBanned ( const banmap_t & banMap )
2015-06-19 15:27:37 +02:00
{
LOCK ( cs_setBanned ) ;
setBanned = banMap ;
setBannedIsDirty = true ;
}
void CNode : : SweepBanned ( )
{
int64_t now = GetTime ( ) ;
LOCK ( cs_setBanned ) ;
2015-06-26 21:38:33 +02:00
banmap_t : : iterator it = setBanned . begin ( ) ;
2015-06-19 15:27:37 +02:00
while ( it ! = setBanned . end ( ) )
{
2015-06-26 21:38:33 +02:00
CBanEntry banEntry = ( * it ) . second ;
if ( now > banEntry . nBanUntil )
2015-06-19 15:27:37 +02:00
{
setBanned . erase ( it + + ) ;
setBannedIsDirty = true ;
}
else
+ + it ;
}
}
bool CNode : : BannedSetIsDirty ( )
{
LOCK ( cs_setBanned ) ;
return setBannedIsDirty ;
}
void CNode : : SetBannedSetDirty ( bool dirty )
{
LOCK ( cs_setBanned ) ; //reuse setBanned lock for the isDirty flag
setBannedIsDirty = dirty ;
}
2014-06-21 13:34:36 +02:00
std : : vector < CSubNet > CNode : : vWhitelistedRange ;
CCriticalSection CNode : : cs_vWhitelistedRange ;
bool CNode : : IsWhitelistedRange ( const CNetAddr & addr ) {
LOCK ( cs_vWhitelistedRange ) ;
2018-12-30 15:33:11 +01:00
for ( const CSubNet & subnet : vWhitelistedRange ) {
2014-06-21 13:34:36 +02:00
if ( subnet . Match ( addr ) )
return true ;
}
return false ;
}
void CNode : : AddWhitelistedRange ( const CSubNet & subnet ) {
LOCK ( cs_vWhitelistedRange ) ;
vWhitelistedRange . push_back ( subnet ) ;
}
2012-06-29 17:24:53 -04:00
# undef X
# define X(name) stats.name = name
void CNode : : copyStats ( CNodeStats & stats )
{
2013-11-18 01:25:17 +01:00
stats . nodeid = this - > GetId ( ) ;
2012-06-29 17:24:53 -04:00
X ( nServices ) ;
2015-11-20 18:51:44 -05:00
X ( fRelayTxes ) ;
2012-06-29 17:24:53 -04:00
X ( nLastSend ) ;
X ( nLastRecv ) ;
X ( nTimeConnected ) ;
2014-12-15 11:06:15 +01:00
X ( nTimeOffset ) ;
2012-06-29 17:24:53 -04:00
X ( addrName ) ;
X ( nVersion ) ;
2013-11-26 12:52:21 +01:00
X ( cleanSubVer ) ;
2012-06-29 17:24:53 -04:00
X ( fInbound ) ;
X ( nStartingHeight ) ;
2013-04-07 19:31:13 +02:00
X ( nSendBytes ) ;
X ( nRecvBytes ) ;
2014-06-21 13:34:36 +02:00
X ( fWhitelisted ) ;
2013-11-15 12:24:34 +01:00
2013-08-22 04:34:33 -07:00
// It is common for nodes with good ping times to suddenly become lagged,
// due to a new block arriving or other large transfer.
// Merely reporting pingtime might fool the caller into thinking the node was still responsive,
// since pingtime does not update until the ping is complete, which might take a while.
// So, if a ping is taking an unusually long time in flight,
// the caller can immediately detect that this is happening.
2013-04-13 00:13:08 -05:00
int64_t nPingUsecWait = 0 ;
2013-08-22 04:34:33 -07:00
if ( ( 0 ! = nPingNonceSent ) & & ( 0 ! = nPingUsecStart ) ) {
nPingUsecWait = GetTimeMicros ( ) - nPingUsecStart ;
}
2013-11-15 12:24:34 +01:00
2013-08-22 04:34:33 -07:00
// Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
stats . dPingTime = ( ( ( double ) nPingUsecTime ) / 1e6 ) ;
2015-09-03 13:06:13 -07:00
stats . dPingMin = ( ( ( double ) nMinPingUsecTime ) / 1e6 ) ;
2013-08-22 04:34:33 -07:00
stats . dPingWait = ( ( ( double ) nPingUsecWait ) / 1e6 ) ;
2013-11-15 12:24:34 +01:00
2013-08-21 22:50:19 -07:00
// Leave string empty if addrLocal invalid (not filled in yet)
stats . addrLocal = addrLocal . IsValid ( ) ? addrLocal . ToString ( ) : " " ;
2012-06-29 17:24:53 -04:00
}
# undef X
2010-08-29 16:58:15 +00:00
2012-11-15 19:41:12 -05:00
// requires LOCK(cs_vRecvMsg)
bool CNode : : ReceiveMsgBytes ( const char * pch , unsigned int nBytes )
{
while ( nBytes > 0 ) {
// get current incomplete message, or create a new one
2013-03-01 01:41:28 +01:00
if ( vRecvMsg . empty ( ) | |
2012-11-15 19:41:12 -05:00
vRecvMsg . back ( ) . complete ( ) )
2018-04-15 22:35:34 +02:00
vRecvMsg . push_back ( CNetMessage ( Params ( ) . magic ( ) , SER_NETWORK , nRecvVersion ) ) ;
2012-11-15 19:41:12 -05:00
CNetMessage & msg = vRecvMsg . back ( ) ;
// absorb network data
int handled ;
if ( ! msg . in_data )
handled = msg . readHeader ( pch , nBytes ) ;
else
handled = msg . readData ( pch , nBytes ) ;
if ( handled < 0 )
2019-04-20 08:56:35 +02:00
return false ;
2012-11-15 19:41:12 -05:00
2017-07-23 22:16:30 +02:00
if ( msg . in_data & & msg . hdr . nMessageSize > ( uint32_t ) Policy : : blockSizeAcceptLimit ( ) + 20000 ) {
2019-04-20 08:56:35 +02:00
logCritical ( Log : : Net ) . nospace ( ) < < " Oversized message from peer: " < < GetId ( )
< < " disconnecting. ( " < < msg . hdr . nMessageSize < < " bytes) " ;
2015-03-05 04:01:22 -08:00
return false ;
}
2012-11-15 19:41:12 -05:00
pch + = handled ;
nBytes - = handled ;
2014-07-06 16:06:46 +02:00
2015-04-05 02:35:37 -07:00
if ( msg . complete ( ) ) {
2014-07-06 16:06:46 +02:00
msg . nTime = GetTimeMicros ( ) ;
2015-04-05 02:35:37 -07:00
messageHandlerCondition . notify_one ( ) ;
}
2012-11-15 19:41:12 -05:00
}
return true ;
}
int CNetMessage : : readHeader ( const char * pch , unsigned int nBytes )
{
// copy data to temporary parsing buffer
unsigned int nRemaining = 24 - nHdrPos ;
unsigned int nCopy = std : : min ( nRemaining , nBytes ) ;
memcpy ( & hdrbuf [ nHdrPos ] , pch , nCopy ) ;
nHdrPos + = nCopy ;
// if header incomplete, exit
if ( nHdrPos < 24 )
return nCopy ;
// deserialize to CMessageHeader
try {
hdrbuf > > hdr ;
}
2014-12-07 13:29:06 +01:00
catch ( const std : : exception & ) {
2012-11-15 19:41:12 -05:00
return - 1 ;
}
// reject messages larger than MAX_SIZE
if ( hdr . nMessageSize > MAX_SIZE )
return - 1 ;
// switch state to reading message data
in_data = true ;
return nCopy ;
}
int CNetMessage : : readData ( const char * pch , unsigned int nBytes )
{
unsigned int nRemaining = hdr . nMessageSize - nDataPos ;
unsigned int nCopy = std : : min ( nRemaining , nBytes ) ;
2014-06-21 17:00:38 +02:00
if ( vRecv . size ( ) < nDataPos + nCopy ) {
// Allocate up to 256 KiB ahead, but never more than the total message size.
vRecv . resize ( std : : min ( hdr . nMessageSize , nDataPos + nCopy + 256 * 1024 ) ) ;
}
2012-11-15 19:41:12 -05:00
memcpy ( & vRecv [ nDataPos ] , pch , nCopy ) ;
nDataPos + = nCopy ;
return nCopy ;
}
2010-08-29 16:58:15 +00:00
2012-11-15 18:04:52 -05:00
// requires LOCK(cs_vSend)
void SocketSendData ( CNode * pnode )
{
2019-08-24 15:01:22 +02:00
std : : deque < std : : vector < char > > : : iterator it = pnode - > vSendMsg . begin ( ) ;
2012-11-15 18:04:52 -05:00
2013-03-24 16:52:24 +01:00
while ( it ! = pnode - > vSendMsg . end ( ) ) {
2019-08-24 15:01:22 +02:00
const std : : vector < char > & data = * it ;
2013-03-24 16:52:24 +01:00
assert ( data . size ( ) > pnode - > nSendOffset ) ;
int nBytes = send ( pnode - > hSocket , & data [ pnode - > nSendOffset ] , data . size ( ) - pnode - > nSendOffset , MSG_NOSIGNAL | MSG_DONTWAIT ) ;
if ( nBytes > 0 ) {
pnode - > nLastSend = GetTime ( ) ;
2013-04-07 19:31:13 +02:00
pnode - > nSendBytes + = nBytes ;
2013-03-24 16:52:24 +01:00
pnode - > nSendOffset + = nBytes ;
2013-08-23 02:09:32 +10:00
pnode - > RecordBytesSent ( nBytes ) ;
2013-03-24 16:52:24 +01:00
if ( pnode - > nSendOffset = = data . size ( ) ) {
pnode - > nSendOffset = 0 ;
pnode - > nSendSize - = data . size ( ) ;
it + + ;
} else {
// could not send full message; stop sending more
break ;
}
} else {
if ( nBytes < 0 ) {
// error
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS )
{
2018-11-20 21:07:53 +01:00
logInfo ( Log : : Net ) < < " socket send error " < < NetworkErrorString ( nErr ) ;
2013-03-24 16:52:24 +01:00
pnode - > CloseSocketDisconnect ( ) ;
}
}
// couldn't send anything at all
break ;
2012-11-15 18:04:52 -05:00
}
}
2013-03-24 16:52:24 +01:00
if ( it = = pnode - > vSendMsg . end ( ) ) {
assert ( pnode - > nSendOffset = = 0 ) ;
assert ( pnode - > nSendSize = = 0 ) ;
}
pnode - > vSendMsg . erase ( pnode - > vSendMsg . begin ( ) , it ) ;
2012-11-15 18:04:52 -05:00
}
2010-08-29 16:58:15 +00:00
2017-08-15 10:32:47 -06:00
static std : : list < CNode * > vNodesDisconnected ;
2013-03-29 02:17:10 +01:00
2015-08-20 17:29:04 -07:00
class CNodeRef {
public :
2015-08-25 16:30:02 -07:00
CNodeRef ( CNode * pnode ) : _pnode ( pnode ) {
LOCK ( cs_vNodes ) ;
_pnode - > AddRef ( ) ;
}
~ CNodeRef ( ) {
LOCK ( cs_vNodes ) ;
_pnode - > Release ( ) ;
}
2015-08-20 17:29:04 -07:00
CNode & operator * ( ) const { return * _pnode ; } ;
CNode * operator - > ( ) const { return _pnode ; } ;
2015-08-25 15:33:29 -07:00
CNodeRef & operator = ( const CNodeRef & other )
{
if ( this ! = & other ) {
2015-08-25 16:30:02 -07:00
LOCK ( cs_vNodes ) ;
2015-08-25 15:33:29 -07:00
_pnode - > Release ( ) ;
_pnode = other . _pnode ;
_pnode - > AddRef ( ) ;
}
return * this ;
}
CNodeRef ( const CNodeRef & other ) :
_pnode ( other . _pnode )
{
2015-08-25 16:30:02 -07:00
LOCK ( cs_vNodes ) ;
2015-08-25 15:33:29 -07:00
_pnode - > AddRef ( ) ;
}
2015-08-20 17:29:04 -07:00
private :
CNode * _pnode ;
} ;
static bool ReverseCompareNodeMinPingTime ( const CNodeRef & a , const CNodeRef & b )
2015-08-13 02:58:58 -07:00
{
return a - > nMinPingUsecTime > b - > nMinPingUsecTime ;
}
2015-08-20 17:29:04 -07:00
static bool ReverseCompareNodeTimeConnected ( const CNodeRef & a , const CNodeRef & b )
2015-08-13 02:58:58 -07:00
{
return a - > nTimeConnected > b - > nTimeConnected ;
}
class CompareNetGroupKeyed
{
std : : vector < unsigned char > vchSecretKey ;
public :
CompareNetGroupKeyed ( )
{
vchSecretKey . resize ( 32 , 0 ) ;
GetRandBytes ( vchSecretKey . data ( ) , vchSecretKey . size ( ) ) ;
}
2015-08-20 17:29:04 -07:00
bool operator ( ) ( const CNodeRef & a , const CNodeRef & b )
2015-08-13 02:58:58 -07:00
{
std : : vector < unsigned char > vchGroupA , vchGroupB ;
CSHA256 hashA , hashB ;
std : : vector < unsigned char > vchA ( 32 ) , vchB ( 32 ) ;
vchGroupA = a - > addr . GetGroup ( ) ;
vchGroupB = b - > addr . GetGroup ( ) ;
hashA . Write ( begin_ptr ( vchGroupA ) , vchGroupA . size ( ) ) ;
hashB . Write ( begin_ptr ( vchGroupB ) , vchGroupB . size ( ) ) ;
hashA . Write ( begin_ptr ( vchSecretKey ) , vchSecretKey . size ( ) ) ;
hashB . Write ( begin_ptr ( vchSecretKey ) , vchSecretKey . size ( ) ) ;
hashA . Finalize ( begin_ptr ( vchA ) ) ;
hashB . Finalize ( begin_ptr ( vchB ) ) ;
return vchA < vchB ;
}
} ;
2015-08-13 17:22:35 -07:00
static bool AttemptToEvictConnection ( bool fPreferNewConnection ) {
2015-08-20 17:29:04 -07:00
std : : vector < CNodeRef > vEvictionCandidates ;
2015-08-13 02:58:58 -07:00
{
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * node : vNodes ) {
2015-08-13 02:58:58 -07:00
if ( node - > fWhitelisted )
continue ;
if ( ! node - > fInbound )
continue ;
if ( node - > fDisconnect )
continue ;
2015-08-20 17:29:04 -07:00
vEvictionCandidates . push_back ( CNodeRef ( node ) ) ;
2015-08-13 02:58:58 -07:00
}
}
2015-08-22 15:15:39 -07:00
if ( vEvictionCandidates . empty ( ) ) return false ;
2015-08-13 02:58:58 -07:00
// Protect connections with certain characteristics
2015-08-20 16:47:49 -07:00
// Deterministically select 4 peers to protect by netgroup.
// An attacker cannot predict which netgroups will be protected.
2015-08-13 02:58:58 -07:00
static CompareNetGroupKeyed comparerNetGroupKeyed ;
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , comparerNetGroupKeyed ) ;
vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std : : min ( 4 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ;
2015-08-22 15:15:39 -07:00
if ( vEvictionCandidates . empty ( ) ) return false ;
2015-08-20 16:47:49 -07:00
// Protect the 8 nodes with the best ping times.
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
2015-08-13 02:58:58 -07:00
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , ReverseCompareNodeMinPingTime ) ;
vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std : : min ( 8 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ;
2015-08-22 15:15:39 -07:00
if ( vEvictionCandidates . empty ( ) ) return false ;
2015-08-25 16:31:13 -07:00
// Protect the half of the remaining nodes which have been connected the longest.
2015-08-20 16:47:49 -07:00
// This replicates the existing implicit behavior.
2015-08-13 02:58:58 -07:00
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , ReverseCompareNodeTimeConnected ) ;
2015-08-22 15:15:39 -07:00
vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - static_cast < int > ( vEvictionCandidates . size ( ) / 2 ) , vEvictionCandidates . end ( ) ) ;
2015-08-13 02:58:58 -07:00
2015-08-22 15:15:39 -07:00
if ( vEvictionCandidates . empty ( ) ) return false ;
2015-08-13 02:58:58 -07:00
2015-11-23 03:48:54 +00:00
// Identify the network group with the most connections and youngest member.
// (vEvictionCandidates is already sorted by reverse connect time)
2015-08-25 17:06:15 -07:00
std : : vector < unsigned char > naMostConnections ;
2015-08-13 02:58:58 -07:00
unsigned int nMostConnections = 0 ;
2015-11-23 03:48:54 +00:00
int64_t nMostConnectionsTime = 0 ;
2015-08-25 17:06:15 -07:00
std : : map < std : : vector < unsigned char > , std : : vector < CNodeRef > > mapAddrCounts ;
2018-12-30 15:33:11 +01:00
for ( const CNodeRef & node : vEvictionCandidates ) {
2015-08-25 17:06:15 -07:00
mapAddrCounts [ node - > addr . GetGroup ( ) ] . push_back ( node ) ;
2015-11-23 03:48:54 +00:00
int64_t grouptime = mapAddrCounts [ node - > addr . GetGroup ( ) ] [ 0 ] - > nTimeConnected ;
size_t groupsize = mapAddrCounts [ node - > addr . GetGroup ( ) ] . size ( ) ;
2015-08-13 02:58:58 -07:00
2015-11-23 03:48:54 +00:00
if ( groupsize > nMostConnections | | ( groupsize = = nMostConnections & & grouptime > nMostConnectionsTime ) ) {
nMostConnections = groupsize ;
nMostConnectionsTime = grouptime ;
2015-08-25 17:06:15 -07:00
naMostConnections = node - > addr . GetGroup ( ) ;
2015-08-13 02:58:58 -07:00
}
}
2015-08-25 17:06:15 -07:00
// Reduce to the network group with the most connections
2015-08-13 02:58:58 -07:00
vEvictionCandidates = mapAddrCounts [ naMostConnections ] ;
2015-11-23 03:48:54 +00:00
// Do not disconnect peers if there is only one unprotected connection from their network group.
2015-08-13 02:58:58 -07:00
if ( vEvictionCandidates . size ( ) < = 1 )
2015-08-13 17:22:35 -07:00
// unless we prefer the new connection (for whitelisted peers)
if ( ! fPreferNewConnection )
return false ;
2015-08-13 02:58:58 -07:00
2015-11-23 03:48:54 +00:00
// Disconnect from the network group with the most connections
2015-08-13 02:58:58 -07:00
vEvictionCandidates [ 0 ] - > fDisconnect = true ;
return true ;
}
2015-08-13 02:00:10 -07:00
static void AcceptConnection ( const ListenSocket & hListenSocket ) {
struct sockaddr_storage sockaddr ;
socklen_t len = sizeof ( sockaddr ) ;
SOCKET hSocket = accept ( hListenSocket . socket , ( struct sockaddr * ) & sockaddr , & len ) ;
CAddress addr ;
int nInbound = 0 ;
int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS ;
if ( hSocket ! = INVALID_SOCKET )
if ( ! addr . SetSockAddr ( ( const struct sockaddr * ) & sockaddr ) )
2018-11-20 21:07:53 +01:00
logCritical ( Log : : Net ) < < " Accept connection via unknown socket family " ;
2015-08-13 02:00:10 -07:00
bool whitelisted = hListenSocket . whitelisted | | CNode : : IsWhitelistedRange ( addr ) ;
{
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes )
2015-08-13 02:00:10 -07:00
if ( pnode - > fInbound )
nInbound + + ;
}
2018-11-20 21:07:53 +01:00
if ( hSocket = = INVALID_SOCKET ) {
2015-08-13 02:00:10 -07:00
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK )
2018-11-20 21:07:53 +01:00
logCritical ( Log : : Net ) < < " socket error accept failed: " < < NetworkErrorString ( nErr ) ;
2015-08-13 02:16:46 -07:00
return ;
2015-08-13 02:00:10 -07:00
}
2015-08-13 02:16:46 -07:00
2018-11-20 21:07:53 +01:00
if ( ! IsSelectableSocket ( hSocket ) ) {
logCritical ( Log : : Net ) < < " connection from " < < addr < < " dropped: non-selectable socket " ;
2015-08-13 02:00:10 -07:00
CloseSocket ( hSocket ) ;
2015-08-13 02:16:46 -07:00
return ;
2015-08-13 02:00:10 -07:00
}
2015-08-13 02:16:46 -07:00
2015-10-21 23:52:29 +00:00
// According to the internet TCP_NODELAY is not carried into accepted sockets
// on all platforms. Set it again here just to be sure.
int set = 1 ;
# ifdef WIN32
setsockopt ( hSocket , IPPROTO_TCP , TCP_NODELAY , ( const char * ) & set , sizeof ( int ) ) ;
# else
setsockopt ( hSocket , IPPROTO_TCP , TCP_NODELAY , ( void * ) & set , sizeof ( int ) ) ;
# endif
2018-11-20 21:07:53 +01:00
if ( CNode : : IsBanned ( addr ) & & ! whitelisted ) {
logInfo ( Log : : Net ) < < " connection from " < < addr < < " dropped (banned) " ;
2015-08-13 02:19:17 -07:00
CloseSocket ( hSocket ) ;
return ;
}
2018-11-20 21:07:53 +01:00
if ( nInbound > = nMaxInbound ) {
2015-08-13 17:22:35 -07:00
if ( ! AttemptToEvictConnection ( whitelisted ) ) {
2015-08-13 02:58:58 -07:00
// No connection to evict, disconnect the new connection
2018-11-20 21:07:53 +01:00
logInfo ( Log : : Net ) < < " failed to find an eviction candidate - connection dropped (full) " ;
2015-08-13 02:58:58 -07:00
CloseSocket ( hSocket ) ;
return ;
}
2015-08-13 02:00:10 -07:00
}
2015-08-13 02:16:46 -07:00
CNode * pnode = new CNode ( hSocket , addr , " " , true ) ;
pnode - > AddRef ( ) ;
pnode - > fWhitelisted = whitelisted ;
2018-11-20 21:07:53 +01:00
logInfo ( Log : : Net ) < < " connection from " < < addr < < " accepted " ;
2015-08-13 02:16:46 -07:00
2015-08-13 02:00:10 -07:00
{
2015-08-13 02:16:46 -07:00
LOCK ( cs_vNodes ) ;
vNodes . push_back ( pnode ) ;
2015-08-13 02:00:10 -07:00
}
}
2013-03-06 22:31:26 -05:00
void ThreadSocketHandler ( )
2010-08-29 16:58:15 +00:00
{
2012-04-22 14:01:25 -04:00
unsigned int nPrevNodeCount = 0 ;
2016-07-21 14:00:44 +02:00
while ( true )
{
2010-08-29 16:58:15 +00:00
//
// Disconnect nodes
//
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2010-08-29 16:58:15 +00:00
// Disconnect unused nodes
2017-08-15 10:32:47 -06:00
std : : vector < CNode * > vNodesCopy = vNodes ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodesCopy ) {
2010-08-29 16:58:15 +00:00
if ( pnode - > fDisconnect | |
2013-03-24 16:52:24 +01:00
( pnode - > GetRefCount ( ) < = 0 & & pnode - > vRecvMsg . empty ( ) & & pnode - > nSendSize = = 0 & & pnode - > ssSend . empty ( ) ) )
2010-08-29 16:58:15 +00:00
{
// remove from vNodes
vNodes . erase ( remove ( vNodes . begin ( ) , vNodes . end ( ) , pnode ) , vNodes . end ( ) ) ;
2012-05-10 18:44:07 +02:00
// release outbound grant (if any)
pnode - > grantOutbound . Release ( ) ;
2012-04-04 16:01:57 +02:00
2010-08-29 16:58:15 +00:00
// close socket and cleanup
pnode - > CloseSocketDisconnect ( ) ;
// hold in disconnected pool until all refs are released
if ( pnode - > fNetworkNode | | pnode - > fInbound )
pnode - > Release ( ) ;
vNodesDisconnected . push_back ( pnode ) ;
2017-04-19 13:00:23 +02:00
if ( pnode - > nVersion ! = 0 ) {
bool xthinCapable = pnode - > nServices & NODE_XTHIN ;
CAddrInfo * info = addrman . Find ( pnode - > addr ) ;
2017-10-06 16:34:20 +02:00
if ( info )
2017-04-19 13:00:23 +02:00
info - > setKnowsXThin ( xthinCapable ) ;
}
2010-08-29 16:58:15 +00:00
}
}
2013-07-25 02:25:25 +02:00
}
{
2010-08-29 16:58:15 +00:00
// Delete disconnected nodes
2017-08-15 10:32:47 -06:00
std : : list < CNode * > vNodesDisconnectedCopy = vNodesDisconnected ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodesDisconnectedCopy ) {
2010-08-29 16:58:15 +00:00
// wait until threads are done using it
if ( pnode - > GetRefCount ( ) < = 0 )
{
bool fDelete = false ;
2012-04-06 18:39:12 +02:00
{
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
if ( lockSend )
{
2012-11-15 19:41:12 -05:00
TRY_LOCK ( pnode - > cs_vRecvMsg , lockRecv ) ;
2012-04-06 18:39:12 +02:00
if ( lockRecv )
{
2012-10-03 19:03:43 +02:00
TRY_LOCK ( pnode - > cs_inventory , lockInv ) ;
if ( lockInv )
fDelete = true ;
2012-04-06 18:39:12 +02:00
}
}
}
2010-08-29 16:58:15 +00:00
if ( fDelete )
{
vNodesDisconnected . remove ( pnode ) ;
delete pnode ;
}
}
}
}
2013-08-23 02:09:32 +10:00
if ( vNodes . size ( ) ! = nPrevNodeCount ) {
2010-08-29 16:58:15 +00:00
nPrevNodeCount = vNodes . size ( ) ;
2013-08-23 02:09:32 +10:00
uiInterface . NotifyNumConnectionsChanged ( nPrevNodeCount ) ;
2010-08-29 16:58:15 +00:00
}
//
// Find which sockets have data to receive
//
struct timeval timeout ;
timeout . tv_sec = 0 ;
timeout . tv_usec = 50000 ; // frequency to poll pnode->vSend
fd_set fdsetRecv ;
fd_set fdsetSend ;
fd_set fdsetError ;
FD_ZERO ( & fdsetRecv ) ;
FD_ZERO ( & fdsetSend ) ;
FD_ZERO ( & fdsetError ) ;
SOCKET hSocketMax = 0 ;
2012-09-05 16:01:28 -04:00
bool have_fds = false ;
2010-12-22 14:08:00 +01:00
2018-12-30 15:33:11 +01:00
for ( const ListenSocket & hListenSocket : vhListenSocket ) {
2014-06-21 13:34:36 +02:00
FD_SET ( hListenSocket . socket , & fdsetRecv ) ;
2017-08-15 10:32:47 -06:00
hSocketMax = std : : max ( hSocketMax , hListenSocket . socket ) ;
2012-09-05 16:01:28 -04:00
have_fds = true ;
2012-05-11 15:28:59 +02:00
}
2014-06-24 09:09:45 +02:00
2010-08-29 16:58:15 +00:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes ) {
2011-06-24 20:09:24 +02:00
if ( pnode - > hSocket = = INVALID_SOCKET )
2010-08-29 16:58:15 +00:00
continue ;
2013-04-30 18:42:01 +02:00
FD_SET ( pnode - > hSocket , & fdsetError ) ;
2017-08-15 10:32:47 -06:00
hSocketMax = std : : max ( hSocketMax , pnode - > hSocket ) ;
2013-04-30 18:42:01 +02:00
have_fds = true ;
// Implement the following logic:
// * If there is data to send, select() for sending data. As this only
// happens when optimistic write failed, we choose to first drain the
// write buffer in this case before receiving more. This avoids
// needlessly queueing received data, if the remote peer is not themselves
// receiving data. This means properly utilizing TCP flow control signalling.
// * Otherwise, if there is no (complete) message in the receive buffer,
// or there is space left in the buffer, select() for receiving data.
// * (if neither of the above applies, there is certainly one message
// in the receiver buffer ready to be processed).
// Together, that means that at least one of the following is always possible,
// so we don't deadlock:
// * We send some data.
// * We wait for data to be received (and disconnect after timeout).
// * We process a message in the buffer (message handler thread).
2012-04-06 18:39:12 +02:00
{
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
2013-04-30 18:42:01 +02:00
if ( lockSend & & ! pnode - > vSendMsg . empty ( ) ) {
FD_SET ( pnode - > hSocket , & fdsetSend ) ;
continue ;
2012-11-15 18:20:26 -05:00
}
2012-04-06 18:39:12 +02:00
}
2013-04-30 18:42:01 +02:00
{
TRY_LOCK ( pnode - > cs_vRecvMsg , lockRecv ) ;
if ( lockRecv & & (
pnode - > vRecvMsg . empty ( ) | | ! pnode - > vRecvMsg . front ( ) . complete ( ) | |
pnode - > GetTotalRecvSize ( ) < = ReceiveFloodSize ( ) ) )
FD_SET ( pnode - > hSocket , & fdsetRecv ) ;
}
2010-08-29 16:58:15 +00:00
}
}
2012-09-05 16:01:28 -04:00
int nSelect = select ( have_fds ? hSocketMax + 1 : 0 ,
& fdsetRecv , & fdsetSend , & fdsetError , & timeout ) ;
2013-03-06 22:31:26 -05:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 16:58:15 +00:00
if ( nSelect = = SOCKET_ERROR )
{
2012-09-05 16:01:28 -04:00
if ( have_fds )
2011-06-07 00:48:37 +02:00
{
2012-09-05 16:01:28 -04:00
int nErr = WSAGetLastError ( ) ;
2018-11-20 21:07:53 +01:00
logDebug ( ) < < " socket select error " < < NetworkErrorString ( nErr ) ;
2012-04-15 16:52:09 -04:00
for ( unsigned int i = 0 ; i < = hSocketMax ; i + + )
2011-06-07 00:48:37 +02:00
FD_SET ( i , & fdsetRecv ) ;
}
2010-08-29 16:58:15 +00:00
FD_ZERO ( & fdsetSend ) ;
FD_ZERO ( & fdsetError ) ;
2013-03-07 14:25:21 -05:00
MilliSleep ( timeout . tv_usec / 1000 ) ;
2010-08-29 16:58:15 +00:00
}
//
// Accept new connections
//
2018-12-30 15:33:11 +01:00
for ( const ListenSocket & hListenSocket : vhListenSocket ) {
2014-06-21 13:34:36 +02:00
if ( hListenSocket . socket ! = INVALID_SOCKET & & FD_ISSET ( hListenSocket . socket , & fdsetRecv ) )
2014-06-24 09:09:45 +02:00
{
2015-08-13 02:00:10 -07:00
AcceptConnection ( hListenSocket ) ;
2010-08-29 16:58:15 +00:00
}
}
//
// Service each socket
//
2017-08-15 10:32:47 -06:00
std : : vector < CNode * > vNodesCopy ;
2010-08-29 16:58:15 +00:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2010-08-29 16:58:15 +00:00
vNodesCopy = vNodes ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 16:58:15 +00:00
pnode - > AddRef ( ) ;
}
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodesCopy ) {
2013-03-06 22:31:26 -05:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 16:58:15 +00:00
//
// Receive
//
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
if ( FD_ISSET ( pnode - > hSocket , & fdsetRecv ) | | FD_ISSET ( pnode - > hSocket , & fdsetError ) )
{
2012-11-15 19:41:12 -05:00
TRY_LOCK ( pnode - > cs_vRecvMsg , lockRecv ) ;
2012-04-06 18:39:12 +02:00
if ( lockRecv )
2010-08-29 16:58:15 +00:00
{
2013-04-30 18:42:01 +02:00
{
2011-02-16 13:18:11 -05:00
// typical socket buffer is 8K-64K
char pchBuf [ 0x10000 ] ;
int nBytes = recv ( pnode - > hSocket , pchBuf , sizeof ( pchBuf ) , MSG_DONTWAIT ) ;
if ( nBytes > 0 )
2010-08-29 16:58:15 +00:00
{
2012-11-15 19:41:12 -05:00
if ( ! pnode - > ReceiveMsgBytes ( pchBuf , nBytes ) )
pnode - > CloseSocketDisconnect ( ) ;
2011-02-16 13:18:11 -05:00
pnode - > nLastRecv = GetTime ( ) ;
2013-04-07 19:31:13 +02:00
pnode - > nRecvBytes + = nBytes ;
2013-08-23 02:09:32 +10:00
pnode - > RecordBytesRecv ( nBytes ) ;
2011-02-16 13:18:11 -05:00
}
else if ( nBytes = = 0 )
{
// socket closed gracefully
2010-08-29 16:58:15 +00:00
if ( ! pnode - > fDisconnect )
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " socket closed " ;
2010-08-29 16:58:15 +00:00
pnode - > CloseSocketDisconnect ( ) ;
}
2011-02-16 13:18:11 -05:00
else if ( nBytes < 0 )
{
// error
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS )
{
if ( ! pnode - > fDisconnect )
2018-03-19 22:41:13 +01:00
logDebug ( Log : : Net ) < < " socket recv error " < < NetworkErrorString ( nErr ) ;
2011-02-16 13:18:11 -05:00
pnode - > CloseSocketDisconnect ( ) ;
}
}
2010-08-29 16:58:15 +00:00
}
}
}
//
// Send
//
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
if ( FD_ISSET ( pnode - > hSocket , & fdsetSend ) )
{
2012-04-06 18:39:12 +02:00
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
if ( lockSend )
2012-11-15 18:04:52 -05:00
SocketSendData ( pnode ) ;
2010-08-29 16:58:15 +00:00
}
//
// Inactivity checking
//
2013-10-15 00:34:20 +02:00
int64_t nTime = GetTime ( ) ;
if ( nTime - pnode - > nTimeConnected > 60 )
2010-08-29 16:58:15 +00:00
{
if ( pnode - > nLastRecv = = 0 | | pnode - > nLastSend = = 0 )
{
2014-02-26 17:55:04 -08:00
LogPrint ( " net " , " socket no message in first 60 seconds, %d %d from %d \n " , pnode - > nLastRecv ! = 0 , pnode - > nLastSend ! = 0 , pnode - > id ) ;
2010-08-29 16:58:15 +00:00
pnode - > fDisconnect = true ;
}
2013-10-15 00:34:20 +02:00
else if ( nTime - pnode - > nLastSend > TIMEOUT_INTERVAL )
2010-08-29 16:58:15 +00:00
{
2018-03-19 22:41:13 +01:00
logWarning ( Log : : Net ) < < " socket sending timeout: " < < ( nTime - pnode - > nLastSend ) ;
2010-08-29 16:58:15 +00:00
pnode - > fDisconnect = true ;
}
2013-10-15 00:34:20 +02:00
else if ( nTime - pnode - > nLastRecv > ( pnode - > nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90 * 60 ) )
2010-08-29 16:58:15 +00:00
{
2018-03-19 22:41:13 +01:00
logWarning ( Log : : Net ) < < " socket receive timeout: " < < ( nTime - pnode - > nLastRecv ) ;
2013-10-15 00:34:20 +02:00
pnode - > fDisconnect = true ;
}
else if ( pnode - > nPingNonceSent & & pnode - > nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros ( ) )
{
2018-03-19 22:41:13 +01:00
logWarning ( Log : : Net ) < < " ping timeout: " < < ( 0.000001 * ( GetTimeMicros ( ) - pnode - > nPingUsecStart ) ) ;
2010-08-29 16:58:15 +00:00
pnode - > fDisconnect = true ;
}
}
}
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 16:58:15 +00:00
pnode - > Release ( ) ;
}
}
}
2011-03-26 13:01:27 +01:00
# ifdef USE_UPNP
2013-03-06 22:31:26 -05:00
void ThreadMapPort ( )
2011-03-26 13:01:27 +01:00
{
2012-09-05 23:36:19 +02:00
std : : string port = strprintf ( " %u " , GetListenPort ( ) ) ;
2011-03-26 13:01:27 +01:00
const char * multicastif = 0 ;
const char * minissdpdpath = 0 ;
struct UPNPDev * devlist = 0 ;
char lanaddr [ 64 ] ;
2011-12-10 11:52:50 -05:00
# ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 ) ;
2015-08-23 23:53:49 +03:00
# elif MINIUPNPC_API_VERSION < 14
2011-12-10 11:52:50 -05:00
/* miniupnpc 1.6 */
int error = 0 ;
2011-08-12 00:20:07 +02:00
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 , 0 , & error ) ;
2015-08-23 23:53:49 +03:00
# else
/* miniupnpc 1.9.20150730 */
int error = 0 ;
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 , 0 , 2 , & error ) ;
2011-12-10 11:52:50 -05:00
# endif
2011-03-26 13:01:27 +01:00
struct UPNPUrls urls ;
struct IGDdatas data ;
int r ;
2011-04-16 11:35:45 -07:00
r = UPNP_GetValidIGD ( devlist , & urls , & data , lanaddr , sizeof ( lanaddr ) ) ;
if ( r = = 1 )
2011-03-26 13:01:27 +01:00
{
2012-05-24 19:02:21 +02:00
if ( fDiscover ) {
2012-02-09 22:41:42 -05:00
char externalIPAddress [ 40 ] ;
r = UPNP_GetExternalIPAddress ( urls . controlURL , data . first . servicetype , externalIPAddress ) ;
if ( r ! = UPNPCOMMAND_SUCCESS )
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) < < " UPnP: GetExternalIPAddress() returned " < < r ;
2012-02-09 22:41:42 -05:00
else
{
if ( externalIPAddress [ 0 ] )
{
2018-08-08 16:56:56 +03:00
logInfo ( Log : : Net ) < < " UPnP: ExternalIPAddress = " < < externalIPAddress ;
2012-02-19 20:44:35 +01:00
AddLocal ( CNetAddr ( externalIPAddress ) , LOCAL_UPNP ) ;
2012-02-09 22:41:42 -05:00
}
else
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) < < " UPnP: GetExternalIPAddress failed. " ;
2012-02-09 22:41:42 -05:00
}
}
2017-08-15 10:32:47 -06:00
std : : string strDesc = " Bitcoin " + FormatFullVersion ( ) ;
2011-08-12 00:20:07 +02:00
2013-03-06 22:31:26 -05:00
try {
2013-07-31 14:06:44 +10:00
while ( true ) {
2012-01-31 17:36:25 -05:00
# ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
r = UPNP_AddPortMapping ( urls . controlURL , data . first . servicetype ,
2012-09-03 08:23:34 +02:00
port . c_str ( ) , port . c_str ( ) , lanaddr , strDesc . c_str ( ) , " TCP " , 0 ) ;
2012-01-31 17:36:25 -05:00
# else
/* miniupnpc 1.6 */
r = UPNP_AddPortMapping ( urls . controlURL , data . first . servicetype ,
2012-09-03 08:23:34 +02:00
port . c_str ( ) , port . c_str ( ) , lanaddr , strDesc . c_str ( ) , " TCP " , 0 , " 0 " ) ;
2012-01-31 17:36:25 -05:00
# endif
if ( r ! = UPNPCOMMAND_SUCCESS )
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) . nospace ( ) < < " AddPortMapping( " < < port < < " , " < < port < < " , " < < lanaddr
< < " ) failed with code " < < r < < " ( " < < strupnperror ( r ) < < " ) " ;
2012-01-31 17:36:25 -05:00
else
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) < < " UPnP Port Mapping successful. " ;
2013-03-06 22:31:26 -05:00
MilliSleep ( 20 * 60 * 1000 ) ; // Refresh every 20 minutes
2012-01-31 17:36:25 -05:00
}
2013-03-06 22:31:26 -05:00
}
2014-12-07 13:29:06 +01:00
catch ( const boost : : thread_interrupted & )
2013-03-06 22:31:26 -05:00
{
r = UPNP_DeletePortMapping ( urls . controlURL , data . first . servicetype , port . c_str ( ) , " TCP " , 0 ) ;
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) < < " UPNP_DeletePortMapping() returned: " < < r ;
2013-03-06 22:31:26 -05:00
freeUPNPDevlist ( devlist ) ; devlist = 0 ;
FreeUPNPUrls ( & urls ) ;
throw ;
2011-03-26 13:01:27 +01:00
}
} else {
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) < < " No valid UPnP IGDs found " ;
2011-03-26 13:01:27 +01:00
freeUPNPDevlist ( devlist ) ; devlist = 0 ;
2011-04-16 11:35:45 -07:00
if ( r ! = 0 )
FreeUPNPUrls ( & urls ) ;
2011-03-26 13:01:27 +01:00
}
}
2013-03-06 22:31:26 -05:00
void MapPort ( bool fUseUPnP )
2011-03-26 13:01:27 +01:00
{
2013-03-06 22:31:26 -05:00
static boost : : thread * upnp_thread = NULL ;
if ( fUseUPnP )
2011-03-26 13:01:27 +01:00
{
2013-03-06 22:31:26 -05:00
if ( upnp_thread ) {
upnp_thread - > interrupt ( ) ;
upnp_thread - > join ( ) ;
delete upnp_thread ;
}
2019-10-10 16:18:53 +02:00
upnp_thread = new boost : : thread ( std : : bind ( & TraceThread < void ( * ) ( ) > , " upnp " , & ThreadMapPort ) ) ;
2013-03-06 22:31:26 -05:00
}
else if ( upnp_thread ) {
upnp_thread - > interrupt ( ) ;
upnp_thread - > join ( ) ;
delete upnp_thread ;
upnp_thread = NULL ;
2011-03-26 13:01:27 +01:00
}
}
2013-03-06 22:31:26 -05:00
2011-08-09 12:38:17 -04:00
# else
2013-03-06 22:31:26 -05:00
void MapPort ( bool )
2011-08-09 12:38:17 -04:00
{
// Intentionally left blank.
}
2011-03-26 13:01:27 +01:00
# endif
2013-03-06 22:31:26 -05:00
void ThreadDNSAddressSeed ( )
2011-11-21 12:25:00 -05:00
{
2014-07-29 11:04:46 -04:00
// goal: only query DNS seeds if address need is acute
if ( ( addrman . size ( ) > 0 ) & &
2018-02-12 14:15:24 +01:00
( ! GetBoolArg ( " -forcednsseed " , Settings : : DefaultForceDnsSeed ) ) ) {
2014-07-29 11:04:46 -04:00
MilliSleep ( 11 * 1000 ) ;
LOCK ( cs_vNodes ) ;
if ( vNodes . size ( ) > = 2 ) {
2018-11-20 21:07:53 +01:00
logInfo ( Log : : Net ) < < " P2P peers available. Skipped DNS seeding. " ;
2014-07-29 11:04:46 -04:00
return ;
}
}
2017-08-15 10:32:47 -06:00
const std : : vector < CDNSSeedData > & vSeeds = Params ( ) . DNSSeeds ( ) ;
2011-03-08 22:40:50 -05:00
int found = 0 ;
2018-11-20 21:07:53 +01:00
logInfo ( Log : : Net ) < < " Loading addresses from DNS seeds (could take a while) " ;
2011-03-08 22:40:50 -05:00
2018-12-30 15:33:11 +01:00
for ( const CDNSSeedData & seed : vSeeds ) {
2013-01-29 23:13:17 -05:00
if ( HaveNameProxy ( ) ) {
2013-05-07 15:16:25 +02:00
AddOneShot ( seed . host ) ;
2013-01-29 23:13:17 -05:00
} else {
2017-08-15 10:32:47 -06:00
std : : vector < CNetAddr > vIPs ;
std : : vector < CAddress > vAdd ;
2013-05-07 15:16:25 +02:00
if ( LookupHost ( seed . host . c_str ( ) , vIPs ) )
2013-01-29 23:13:17 -05:00
{
2018-12-30 15:33:11 +01:00
for ( const CNetAddr & ip : vIPs ) {
2013-01-29 23:13:17 -05:00
int nOneDay = 24 * 3600 ;
2013-05-07 15:16:25 +02:00
CAddress addr = CAddress ( CService ( ip , Params ( ) . GetDefaultPort ( ) ) ) ;
2013-01-29 23:13:17 -05:00
addr . nTime = GetTime ( ) - 3 * nOneDay - GetRand ( 4 * nOneDay ) ; // use a random age between 3 and 7 days old
vAdd . push_back ( addr ) ;
found + + ;
2011-05-02 15:34:42 +02:00
}
2011-03-08 22:40:50 -05:00
}
2013-05-07 15:16:25 +02:00
addrman . Add ( vAdd , CNetAddr ( seed . name , true ) ) ;
2011-03-08 22:40:50 -05:00
}
}
2018-11-20 21:07:53 +01:00
logInfo ( Log : : Net ) < < found < < " addresses found from DNS seeds " ;
2011-03-08 22:40:50 -05:00
}
2010-08-29 16:58:15 +00:00
2012-01-04 23:39:45 +01:00
void DumpAddresses ( )
{
2013-04-13 00:13:08 -05:00
int64_t nStart = GetTimeMillis ( ) ;
2012-05-16 22:11:19 -04:00
2017-04-19 13:00:23 +02:00
{
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodes ) {
if ( pnode - > fDisconnect | | pnode - > nVersion = = 0 )
continue ;
bool xthinCapable = pnode - > nServices & NODE_XTHIN ;
CAddrInfo * info = addrman . Find ( pnode - > addr ) ;
2017-10-06 16:34:20 +02:00
if ( info )
2017-04-19 13:00:23 +02:00
info - > setKnowsXThin ( xthinCapable ) ;
}
}
2012-01-04 23:39:45 +01:00
CAddrDB adb ;
2012-05-16 22:11:19 -04:00
adb . Write ( addrman ) ;
2018-11-20 21:07:53 +01:00
logInfo ( Log : : Net ) < < " Flushed " < < addrman . size ( ) < < " addresses to peers.dat " < < ( GetTimeMillis ( ) - nStart ) < < " ms " ;
2012-01-04 23:39:45 +01:00
}
2010-08-29 16:58:15 +00:00
2015-06-19 15:27:37 +02:00
void DumpData ( )
{
DumpAddresses ( ) ;
if ( CNode : : BannedSetIsDirty ( ) )
{
DumpBanlist ( ) ;
CNode : : SetBannedSetDirty ( false ) ;
}
}
2012-04-24 02:15:00 +02:00
void static ProcessOneShot ( )
{
2017-08-15 10:32:47 -06:00
std : : string strDest ;
2012-04-24 02:15:00 +02:00
{
LOCK ( cs_vOneShots ) ;
if ( vOneShots . empty ( ) )
return ;
strDest = vOneShots . front ( ) ;
vOneShots . pop_front ( ) ;
}
CAddress addr ;
2012-05-10 18:44:07 +02:00
CSemaphoreGrant grant ( * semOutbound , true ) ;
if ( grant ) {
if ( ! OpenNetworkConnection ( addr , & grant , strDest . c_str ( ) , true ) )
AddOneShot ( strDest ) ;
}
2012-04-24 02:15:00 +02:00
}
2013-03-06 22:31:26 -05:00
void ThreadOpenConnections ( )
2010-08-29 16:58:15 +00:00
{
// Connect to specific addresses
2016-07-21 14:00:44 +02:00
if ( mapArgs . count ( " -connect " ) & & mapMultiArgs [ " -connect " ] . size ( ) > 0 )
{
2013-04-13 00:13:08 -05:00
for ( int64_t nLoop = 0 ; ; nLoop + + )
2010-08-29 16:58:15 +00:00
{
2012-04-24 02:15:00 +02:00
ProcessOneShot ( ) ;
2018-12-30 15:33:11 +01:00
for ( const std : : string & strAddr : mapMultiArgs [ " -connect " ] ) {
2012-04-24 02:15:00 +02:00
CAddress addr ;
2019-06-17 22:07:17 +02:00
if ( OpenNetworkConnection ( addr , NULL , strAddr . c_str ( ) ) ) {
CNode * node = FindNode ( std : : string ( strAddr ) ) ;
if ( node )
node - > fWhitelisted = true ;
}
2010-08-29 16:58:15 +00:00
for ( int i = 0 ; i < 10 & & i < nLoop ; i + + )
{
2013-03-07 14:25:21 -05:00
MilliSleep ( 500 ) ;
2010-08-29 16:58:15 +00:00
}
}
2013-03-07 14:25:21 -05:00
MilliSleep ( 500 ) ;
2010-08-29 16:58:15 +00:00
}
}
2017-04-19 13:00:23 +02:00
const int maxOutBound = std : : min ( MAX_OUTBOUND_CONNECTIONS , nMaxConnections ) ;
2018-02-12 14:15:24 +01:00
const int minXThinNodesConf = IsThinBlocksEnabled ( ) ? std : : min ( maxOutBound , ( int ) GetArg ( " -min-thin-peers " , Settings : : DefaultMinThinPeers ) ) : 0 ;
2010-08-29 16:58:15 +00:00
// Initiate network connections
2013-04-13 00:13:08 -05:00
int64_t nStart = GetTime ( ) ;
2017-04-19 13:00:23 +02:00
int nDisconnects = 0 ;
while ( true ) {
2017-10-04 15:08:40 +02:00
int minXThinNodes = minXThinNodesConf ;
2012-04-24 02:15:00 +02:00
ProcessOneShot ( ) ;
2013-03-07 14:25:21 -05:00
MilliSleep ( 500 ) ;
2012-02-15 21:17:15 +01:00
2017-04-19 13:00:23 +02:00
// Only connect out to one peer per network group (/16 for IPv4).
// Do this here so we don't have to mutex vNodes inside mapAddresses mutex.
// And also must do this before the semaphore grant so that we don't have to block
// if the grants are all taken and we want to disconnect a node in the event that
// we don't have enough connections to XTHIN capable nodes yet.
std : : set < std : : vector < unsigned char > > setConnected ;
int nThinBlockCapable = 0 ;
{
CNode * ptemp = nullptr ;
int autoConnectedOutboundNodes = 0 ;
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodes ) {
if ( pnode - > fDisconnect | | pnode - > nVersion = = 0 )
continue ;
if ( pnode - > fAutoOutbound ) {
setConnected . insert ( pnode - > addr . GetGroup ( ) ) ;
+ + autoConnectedOutboundNodes ;
2017-07-23 22:17:20 +02:00
if ( minXThinNodes > 0 & & pnode - > ThinBlockCapable ( ) )
2017-04-19 13:00:23 +02:00
+ + nThinBlockCapable ;
else if ( ! ptemp )
ptemp = pnode ;
}
}
2017-07-23 22:17:20 +02:00
// Disconnect a node that is not compatible if all outbound slots are full and we
// have not yet connected to enough nodes.
2017-10-04 15:08:40 +02:00
if ( ptemp & & autoConnectedOutboundNodes > = maxOutBound & & nThinBlockCapable < minXThinNodes ) {
2017-04-19 13:00:23 +02:00
ptemp - > fDisconnect = true ;
nDisconnects + + ;
2017-07-23 22:17:20 +02:00
logWarning ( Log : : Net ) . nospace ( ) < < " Not enough capable peers xthin ( "
< < nThinBlockCapable < < " / " < < minXThinNodes
2017-10-04 15:08:40 +02:00
< < " ) disconnecting ` " < < ptemp - > cleanSubVer < < " ', id: "
2017-07-23 22:17:20 +02:00
< < ptemp - > id < < " (disconnect-count: " < < nDisconnects < < " ) " ;
2017-04-19 13:00:23 +02:00
}
}
2013-03-06 22:31:26 -05:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 16:58:15 +00:00
2017-04-19 13:00:23 +02:00
// The loop above may have skipped peers which have not yet disconnected or identified themselves,
// as such we should take the grant a little less serious in case we still are waiting to fill our
// slots and check counts again after a little timeout.
CSemaphoreGrant grant ( * semOutbound , /* try_lock */ nThinBlockCapable < minXThinNodes ) ;
if ( ! grant ) {
MilliSleep ( 4500 ) ;
continue ;
}
2013-05-07 15:16:25 +02:00
// Add seed nodes if DNS seeds are all down (an infrastructure attack?).
if ( addrman . size ( ) = = 0 & & ( GetTime ( ) - nStart > 60 ) ) {
static bool done = false ;
if ( ! done ) {
2018-03-19 22:41:13 +01:00
logDebug ( Log : : Net ) < < " Adding fixed seed nodes as DNS doesn't seem to be available. " ;
2015-01-23 23:40:50 -05:00
addrman . Add ( convertSeed6 ( Params ( ) . FixedSeeds ( ) ) , CNetAddr ( " 127.0.0.1 " ) ) ;
2013-05-07 15:16:25 +02:00
done = true ;
2012-01-03 01:28:15 +01:00
}
}
2010-08-29 16:58:15 +00:00
//
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect ;
2013-04-13 00:13:08 -05:00
int64_t nANow = GetAdjustedTime ( ) ;
2011-10-03 23:41:47 -04:00
2012-01-04 23:39:45 +01:00
int nTries = 0 ;
2013-07-31 14:06:44 +10:00
while ( true )
2010-08-29 16:58:15 +00:00
{
2015-04-19 11:10:13 -07:00
CAddrInfo addr = addrman . Select ( ) ;
2010-08-29 16:58:15 +00:00
2012-01-04 23:39:45 +01:00
// if we selected an invalid address, restart
2012-03-31 17:58:25 +02:00
if ( ! addr . IsValid ( ) | | setConnected . count ( addr . GetGroup ( ) ) | | IsLocal ( addr ) )
2012-01-04 23:39:45 +01:00
break ;
2010-08-29 16:58:15 +00:00
2012-08-21 17:32:04 +02:00
// If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
// stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
// already-connected network ranges, ...) before trying new addrman addresses.
2012-01-04 23:39:45 +01:00
nTries + + ;
2012-08-21 17:32:04 +02:00
if ( nTries > 100 )
break ;
2010-08-29 16:58:15 +00:00
2012-05-04 16:46:22 +02:00
if ( IsLimited ( addr ) )
continue ;
2012-01-04 23:39:45 +01:00
// only consider very recently tried nodes after 30 failed attempts
if ( nANow - addr . nLastTry < 600 & & nTries < 30 )
continue ;
2010-08-29 16:58:15 +00:00
2012-01-04 23:39:45 +01:00
// do not allow non-default ports, unless after 50 invalid addresses selected already
2013-05-07 15:16:25 +02:00
if ( addr . GetPort ( ) ! = Params ( ) . GetDefaultPort ( ) & & nTries < 50 )
2012-01-04 23:39:45 +01:00
continue ;
2010-08-29 16:58:15 +00:00
2012-01-04 23:39:45 +01:00
addrConnect = addr ;
2017-10-06 16:34:20 +02:00
addrConnect . nTime = addr . getLastSuccess ( ) ;
2012-01-04 23:39:45 +01:00
break ;
2010-08-29 16:58:15 +00:00
}
2017-04-19 13:00:23 +02:00
if ( addrConnect . IsValid ( ) ) {
2012-05-10 18:44:07 +02:00
OpenNetworkConnection ( addrConnect , & grant ) ;
2017-04-19 13:00:23 +02:00
LOCK ( cs_vNodes ) ;
CNode * pnode = FindNode ( ( CService ) addrConnect ) ;
// We need to use a separate outbound flag so as not to differentiate these outbound¬
// nodes with ones that were added using -addnode -connect-thinblock or -connect.
if ( pnode )
pnode - > fAutoOutbound = true ;
}
2010-08-29 16:58:15 +00:00
}
}
2013-03-06 22:31:26 -05:00
void ThreadOpenAddedConnections ( )
2011-12-16 19:48:03 -05:00
{
2012-07-02 19:55:16 +02:00
{
LOCK ( cs_vAddedNodes ) ;
vAddedNodes = mapMultiArgs [ " -addnode " ] ;
}
2011-12-16 19:48:03 -05:00
2012-09-23 12:55:05 +02:00
if ( HaveNameProxy ( ) ) {
2013-03-06 22:31:26 -05:00
while ( true ) {
2017-08-15 10:32:47 -06:00
std : : list < std : : string > lAddresses ( 0 ) ;
2012-07-02 19:55:16 +02:00
{
LOCK ( cs_vAddedNodes ) ;
2018-12-30 15:33:11 +01:00
for ( const std : : string & strAddNode : vAddedNodes )
2012-07-02 19:55:16 +02:00
lAddresses . push_back ( strAddNode ) ;
}
2018-12-30 15:33:11 +01:00
for ( const std : : string & strAddNode : lAddresses ) {
2012-04-19 17:38:03 +02:00
CAddress addr ;
2012-05-10 18:44:07 +02:00
CSemaphoreGrant grant ( * semOutbound ) ;
OpenNetworkConnection ( addr , & grant , strAddNode . c_str ( ) ) ;
2013-03-07 14:25:21 -05:00
MilliSleep ( 500 ) ;
2012-04-19 17:38:03 +02:00
}
2013-03-07 14:25:21 -05:00
MilliSleep ( 120000 ) ; // Retry every 2 minutes
2012-04-19 17:38:03 +02:00
}
}
2012-07-02 21:11:57 +02:00
for ( unsigned int i = 0 ; true ; i + + )
2011-12-16 19:48:03 -05:00
{
2017-08-15 10:32:47 -06:00
std : : list < std : : string > lAddresses ( 0 ) ;
2012-07-02 19:55:16 +02:00
{
LOCK ( cs_vAddedNodes ) ;
2018-12-30 15:33:11 +01:00
for ( const std : : string & strAddNode : vAddedNodes )
2012-07-02 19:55:16 +02:00
lAddresses . push_back ( strAddNode ) ;
}
2017-08-15 10:32:47 -06:00
std : : list < std : : vector < CService > > lservAddressesToAdd ( 0 ) ;
2018-12-30 15:33:11 +01:00
for ( const std : : string & strAddNode : lAddresses ) {
2017-08-15 10:32:47 -06:00
std : : vector < CService > vservNode ( 0 ) ;
2013-05-07 15:16:25 +02:00
if ( Lookup ( strAddNode . c_str ( ) , vservNode , Params ( ) . GetDefaultPort ( ) , fNameLookup , 0 ) )
2012-07-02 19:55:16 +02:00
{
lservAddressesToAdd . push_back ( vservNode ) ;
{
LOCK ( cs_setservAddNodeAddresses ) ;
2018-12-30 15:33:11 +01:00
for ( const CService & serv : vservNode )
2012-07-02 19:55:16 +02:00
setservAddNodeAddresses . insert ( serv ) ;
}
}
}
2011-12-16 19:48:03 -05:00
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
2012-04-19 17:38:03 +02:00
// (keeping in mind that addnode entries can have many IPs if fNameLookup)
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes )
2017-08-15 10:32:47 -06:00
for ( std : : list < std : : vector < CService > > : : iterator it = lservAddressesToAdd . begin ( ) ; it ! = lservAddressesToAdd . end ( ) ; it + + )
2018-12-30 15:33:11 +01:00
for ( const CService & addrNode : * ( it ) )
2011-12-16 19:48:03 -05:00
if ( pnode - > addr = = addrNode )
{
2012-07-02 19:55:16 +02:00
it = lservAddressesToAdd . erase ( it ) ;
2011-12-16 19:48:03 -05:00
it - - ;
break ;
}
2012-04-06 18:39:12 +02:00
}
2018-12-30 15:33:11 +01:00
for ( std : : vector < CService > & vserv : lservAddressesToAdd ) {
2012-05-10 18:44:07 +02:00
CSemaphoreGrant grant ( * semOutbound ) ;
2012-07-02 21:11:57 +02:00
OpenNetworkConnection ( CAddress ( vserv [ i % vserv . size ( ) ] ) , & grant ) ;
2013-03-07 14:25:21 -05:00
MilliSleep ( 500 ) ;
2011-12-16 19:48:03 -05:00
}
2013-03-07 14:25:21 -05:00
MilliSleep ( 120000 ) ; // Retry every 2 minutes
2011-12-16 19:48:03 -05:00
}
}
2012-07-26 00:48:39 +00:00
// if successful, this moves the passed grant to the constructed node
2014-05-24 11:14:52 +02:00
bool OpenNetworkConnection ( const CAddress & addrConnect , CSemaphoreGrant * grantOutbound , const char * pszDest , bool fOneShot )
2010-08-29 16:58:15 +00:00
{
//
// Initiate outbound network connection
//
2013-03-06 22:31:26 -05:00
boost : : this_thread : : interruption_point ( ) ;
2014-05-24 11:14:52 +02:00
if ( ! pszDest ) {
2012-02-12 13:45:24 +01:00
if ( IsLocal ( addrConnect ) | |
FindNode ( ( CNetAddr ) addrConnect ) | | CNode : : IsBanned ( addrConnect ) | |
2014-07-21 15:00:42 +02:00
FindNode ( addrConnect . ToStringIPPort ( ) ) )
2012-04-19 17:38:03 +02:00
return false ;
2015-05-31 15:44:22 +02:00
} else if ( FindNode ( std : : string ( pszDest ) ) )
2010-08-29 16:58:15 +00:00
return false ;
2014-05-24 11:14:52 +02:00
CNode * pnode = ConnectNode ( addrConnect , pszDest ) ;
2013-03-06 22:31:26 -05:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 16:58:15 +00:00
if ( ! pnode )
return false ;
2012-05-10 18:44:07 +02:00
if ( grantOutbound )
grantOutbound - > MoveTo ( pnode - > grantOutbound ) ;
2010-08-29 16:58:15 +00:00
pnode - > fNetworkNode = true ;
2012-04-24 02:15:00 +02:00
if ( fOneShot )
pnode - > fOneShot = true ;
2010-08-29 16:58:15 +00:00
return true ;
}
2013-03-06 22:31:26 -05:00
void ThreadMessageHandler ( )
2010-08-29 16:58:15 +00:00
{
2015-04-05 02:35:37 -07:00
boost : : mutex condition_mutex ;
boost : : unique_lock < boost : : mutex > lock ( condition_mutex ) ;
2015-05-31 15:44:22 +02:00
2010-08-29 16:58:15 +00:00
SetThreadPriority ( THREAD_PRIORITY_BELOW_NORMAL ) ;
2013-03-06 22:31:26 -05:00
while ( true )
2010-08-29 16:58:15 +00:00
{
2017-08-15 10:32:47 -06:00
std : : vector < CNode * > vNodesCopy ;
2010-08-29 16:58:15 +00:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2016-07-18 14:59:07 +02:00
vNodesCopy . reserve ( vNodes . size ( ) ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes ) {
2019-08-11 15:29:05 +02:00
vNodesCopy . push_back ( pnode ) ;
pnode - > AddRef ( ) ;
2013-04-05 00:43:04 +02:00
}
2010-08-29 16:58:15 +00:00
}
2016-07-18 14:59:07 +02:00
bool fSleep = true ;
2013-11-15 12:24:34 +01:00
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodesCopy ) {
2013-03-01 01:41:28 +01:00
if ( pnode - > fDisconnect )
continue ;
2010-08-29 16:58:15 +00:00
// Receive messages
2012-04-06 18:39:12 +02:00
{
2012-11-15 19:41:12 -05:00
TRY_LOCK ( pnode - > cs_vRecvMsg , lockRecv ) ;
2012-04-06 18:39:12 +02:00
if ( lockRecv )
2013-10-28 13:20:21 -07:00
{
2013-06-05 20:21:41 -07:00
if ( ! g_signals . ProcessMessages ( pnode ) )
2012-11-15 19:41:12 -05:00
pnode - > CloseSocketDisconnect ( ) ;
2013-11-15 12:24:34 +01:00
2013-10-28 13:20:21 -07:00
if ( pnode - > nSendSize < SendBufferSize ( ) )
{
if ( ! pnode - > vRecvGetData . empty ( ) | | ( ! pnode - > vRecvMsg . empty ( ) & & pnode - > vRecvMsg [ 0 ] . complete ( ) ) )
{
fSleep = false ;
}
}
}
2012-04-06 18:39:12 +02:00
}
2013-03-06 22:31:26 -05:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 16:58:15 +00:00
// Send messages
2012-04-06 18:39:12 +02:00
{
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
2013-06-05 20:21:41 -07:00
if ( lockSend )
2015-04-08 11:20:00 -07:00
g_signals . SendMessages ( pnode ) ;
2012-04-06 18:39:12 +02:00
}
2013-03-06 22:31:26 -05:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 16:58:15 +00:00
}
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 16:58:15 +00:00
pnode - > Release ( ) ;
}
2013-11-15 12:24:34 +01:00
2013-10-28 13:20:21 -07:00
if ( fSleep )
2018-07-26 20:00:58 +00:00
messageHandlerCondition . timed_wait ( lock , boost : : posix_time : : microsec_clock : : universal_time ( ) + boost : : posix_time : : milliseconds ( 50 ) ) ;
2010-08-29 16:58:15 +00:00
}
}
2017-08-15 10:32:47 -06:00
bool BindListenPort ( const CService & addrBind , std : : string & strError , bool fWhitelisted )
2010-08-29 16:58:15 +00:00
{
strError = " " ;
int nOne = 1 ;
// Create socket for listening for incoming connections
2012-05-11 15:28:59 +02:00
struct sockaddr_storage sockaddr ;
socklen_t len = sizeof ( sockaddr ) ;
if ( ! addrBind . GetSockAddr ( ( struct sockaddr * ) & sockaddr , & len ) )
{
2018-03-19 22:41:13 +01:00
logCritical ( Log : : Net ) < < " Error: Bind address family for " < < addrBind < < " not supported " ;
2012-05-11 15:28:59 +02:00
return false ;
}
SOCKET hListenSocket = socket ( ( ( struct sockaddr * ) & sockaddr ) - > sa_family , SOCK_STREAM , IPPROTO_TCP ) ;
2010-08-29 16:58:15 +00:00
if ( hListenSocket = = INVALID_SOCKET )
{
2018-03-19 22:41:13 +01:00
logCritical ( Log : : Net ) < < " Error: Couldn't open socket for incoming connections. Socket returned error " < < NetworkErrorString ( WSAGetLastError ( ) ) ;
2010-08-29 16:58:15 +00:00
return false ;
}
2015-07-09 18:23:27 -04:00
if ( ! IsSelectableSocket ( hListenSocket ) )
{
2018-03-19 22:41:13 +01:00
logCritical ( Log : : Net ) < < " Error: Couldn't create a listenable socket for incoming connections " ;
2015-07-09 18:23:27 -04:00
return false ;
}
2010-08-29 16:58:15 +00:00
2014-06-24 09:03:18 +02:00
# ifndef WIN32
2011-08-07 12:18:05 -04:00
# ifdef SO_NOSIGPIPE
2010-08-29 16:58:15 +00:00
// Different way of disabling SIGPIPE on BSD
setsockopt ( hListenSocket , SOL_SOCKET , SO_NOSIGPIPE , ( void * ) & nOne , sizeof ( int ) ) ;
# endif
// Allow binding if the port is still in TIME_WAIT state after
2015-08-20 15:50:13 -04:00
// the program was closed and restarted.
2010-08-29 16:58:15 +00:00
setsockopt ( hListenSocket , SOL_SOCKET , SO_REUSEADDR , ( void * ) & nOne , sizeof ( int ) ) ;
2015-10-21 23:52:29 +00:00
// Disable Nagle's algorithm
setsockopt ( hListenSocket , IPPROTO_TCP , TCP_NODELAY , ( void * ) & nOne , sizeof ( int ) ) ;
2015-08-20 15:50:13 -04:00
# else
setsockopt ( hListenSocket , SOL_SOCKET , SO_REUSEADDR , ( const char * ) & nOne , sizeof ( int ) ) ;
2015-10-21 23:52:29 +00:00
setsockopt ( hListenSocket , IPPROTO_TCP , TCP_NODELAY , ( const char * ) & nOne , sizeof ( int ) ) ;
2010-08-29 16:58:15 +00:00
# endif
2012-07-26 00:48:39 +00:00
// Set to non-blocking, incoming connections will also inherit this
2014-07-09 11:00:00 +02:00
if ( ! SetSocketNonBlocking ( hListenSocket , true ) ) {
2018-03-19 22:41:13 +01:00
logCritical ( Log : : Net ) < < " BindListenPort: Setting listening socket to non-blocking failed, error " < < NetworkErrorString ( WSAGetLastError ( ) ) ;
2010-08-29 16:58:15 +00:00
return false ;
}
2012-05-11 15:28:59 +02:00
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if ( addrBind . IsIPv6 ( ) ) {
# ifdef IPV6_V6ONLY
2013-07-13 13:05:04 +02:00
# ifdef WIN32
setsockopt ( hListenSocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( const char * ) & nOne , sizeof ( int ) ) ;
# else
2012-05-11 15:28:59 +02:00
setsockopt ( hListenSocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( void * ) & nOne , sizeof ( int ) ) ;
2012-03-31 17:58:25 +02:00
# endif
2013-07-13 13:05:04 +02:00
# endif
2012-05-11 15:28:59 +02:00
# ifdef WIN32
2014-06-24 09:03:18 +02:00
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED ;
setsockopt ( hListenSocket , IPPROTO_IPV6 , IPV6_PROTECTION_LEVEL , ( const char * ) & nProtLevel , sizeof ( int ) ) ;
2012-05-11 15:28:59 +02:00
# endif
}
if ( : : bind ( hListenSocket , ( struct sockaddr * ) & sockaddr , len ) = = SOCKET_ERROR )
2010-08-29 16:58:15 +00:00
{
int nErr = WSAGetLastError ( ) ;
if ( nErr = = WSAEADDRINUSE )
2018-03-19 22:41:13 +01:00
logCritical ( Log : : Net ) < < " Unable to bind to " < < addrBind < < " on this computer. The Hub is probably already running. " ;
2010-08-29 16:58:15 +00:00
else
2018-03-19 22:41:13 +01:00
logCritical ( Log : : Net ) < < " Unable to bind to " < < addrBind < < " on this computer (bind returned error " < < NetworkErrorString ( nErr ) < < " ) " ;
2014-07-17 22:33:58 +02:00
CloseSocket ( hListenSocket ) ;
2010-08-29 16:58:15 +00:00
return false ;
}
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Net ) < < " Bound to " < < addrBind ;
2010-08-29 16:58:15 +00:00
// Listen for incoming connections
if ( listen ( hListenSocket , SOMAXCONN ) = = SOCKET_ERROR )
{
2018-03-19 22:41:13 +01:00
logCritical ( Log : : Net ) < < " Error: Listening for incoming connections failed. Listen returned error " < < NetworkErrorString ( WSAGetLastError ( ) ) ;
2014-07-17 22:33:58 +02:00
CloseSocket ( hListenSocket ) ;
2010-08-29 16:58:15 +00:00
return false ;
}
2014-06-21 13:34:36 +02:00
vhListenSocket . push_back ( ListenSocket ( hListenSocket , fWhitelisted ) ) ;
2012-05-11 15:28:59 +02:00
2014-06-21 13:34:36 +02:00
if ( addrBind . IsRoutable ( ) & & fDiscover & & ! fWhitelisted )
2012-05-11 15:28:59 +02:00
AddLocal ( addrBind , LOCAL_BIND ) ;
2010-08-29 16:58:15 +00:00
return true ;
}
2013-12-09 14:08:51 +10:00
void static Discover ( boost : : thread_group & threadGroup )
2010-08-29 16:58:15 +00:00
{
2012-05-24 19:02:21 +02:00
if ( ! fDiscover )
2012-02-19 20:44:35 +01:00
return ;
2010-08-29 16:58:15 +00:00
2011-10-07 11:02:21 -04:00
# ifdef WIN32
2012-07-26 00:48:39 +00:00
// Get local host IP
2014-11-13 15:23:15 +01:00
char pszHostName [ 256 ] = " " ;
2010-08-29 16:58:15 +00:00
if ( gethostname ( pszHostName , sizeof ( pszHostName ) ) ! = SOCKET_ERROR )
{
2017-08-15 10:32:47 -06:00
std : : vector < CNetAddr > vaddr ;
2012-01-03 23:33:31 +01:00
if ( LookupHost ( pszHostName , vaddr ) )
2012-05-01 01:44:59 +02:00
{
2018-12-30 15:33:11 +01:00
for ( const CNetAddr & addr : vaddr ) {
2014-11-13 15:20:57 +01:00
if ( AddLocal ( addr , LOCAL_IF ) )
LogPrintf ( " %s: %s - %s \n " , __func__ , pszHostName , addr . ToString ( ) ) ;
2012-05-01 01:44:59 +02:00
}
}
2010-08-29 16:58:15 +00:00
}
# else
// Get local host ip
struct ifaddrs * myaddrs ;
if ( getifaddrs ( & myaddrs ) = = 0 )
{
for ( struct ifaddrs * ifa = myaddrs ; ifa ! = NULL ; ifa = ifa - > ifa_next )
{
if ( ifa - > ifa_addr = = NULL ) continue ;
if ( ( ifa - > ifa_flags & IFF_UP ) = = 0 ) continue ;
if ( strcmp ( ifa - > ifa_name , " lo " ) = = 0 ) continue ;
if ( strcmp ( ifa - > ifa_name , " lo0 " ) = = 0 ) continue ;
if ( ifa - > ifa_addr - > sa_family = = AF_INET )
{
struct sockaddr_in * s4 = ( struct sockaddr_in * ) ( ifa - > ifa_addr ) ;
2012-02-12 13:45:24 +01:00
CNetAddr addr ( s4 - > sin_addr ) ;
2012-03-31 17:58:25 +02:00
if ( AddLocal ( addr , LOCAL_IF ) )
2014-11-13 15:20:57 +01:00
LogPrintf ( " %s: IPv4 %s: %s \n " , __func__ , ifa - > ifa_name , addr . ToString ( ) ) ;
2018-03-19 22:41:13 +01:00
logDebug ( Log : : Net ) < < " Discover: IPv4 " < < ifa - > ifa_name < < addr ;
2010-08-29 16:58:15 +00:00
}
else if ( ifa - > ifa_addr - > sa_family = = AF_INET6 )
{
struct sockaddr_in6 * s6 = ( struct sockaddr_in6 * ) ( ifa - > ifa_addr ) ;
2012-02-12 13:45:24 +01:00
CNetAddr addr ( s6 - > sin6_addr ) ;
2012-03-31 17:58:25 +02:00
if ( AddLocal ( addr , LOCAL_IF ) )
2018-03-19 22:41:13 +01:00
logDebug ( Log : : Net ) < < " Discover: IPv6 " < < ifa - > ifa_name < < addr ;
2010-08-29 16:58:15 +00:00
}
}
freeifaddrs ( myaddrs ) ;
}
# endif
2012-02-19 20:44:35 +01:00
}
2015-04-02 12:04:59 -04:00
void StartNode ( boost : : thread_group & threadGroup , CScheduler & scheduler )
2012-02-19 20:44:35 +01:00
{
2014-09-18 14:08:43 +02:00
uiInterface . InitMessage ( _ ( " Loading addresses... " ) ) ;
// Load addresses for peers.dat
{
CAddrDB adb ;
2016-03-16 12:54:30 -04:00
if ( adb . Read ( addrman ) ) {
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Addrman ) < < " Loaded " < < addrman . size ( ) < < " addresses from peers.dat " ;
2016-03-16 12:54:30 -04:00
} else {
addrman . Clear ( ) ; // Addrman can be in an inconsistent state after failure, reset it
2018-03-19 22:41:13 +01:00
logWarning ( Log : : Addrman ) < < " Invalid or missing peers.dat; recreating " ;
2016-03-16 12:54:30 -04:00
}
2014-09-18 14:08:43 +02:00
}
2015-06-19 15:27:37 +02:00
//try to read stored banlist
CBanDB bandb ;
2015-06-26 21:38:33 +02:00
banmap_t banmap ;
2015-06-19 15:27:37 +02:00
if ( ! bandb . Read ( banmap ) )
2018-03-19 22:41:13 +01:00
logWarning ( Log : : Addrman ) < < " Could not read banlist.dat, starting with empty list. " ;
2015-06-19 15:27:37 +02:00
CNode : : SetBanned ( banmap ) ; //thread save setter
CNode : : SetBannedSetDirty ( false ) ; //no need to write down just read or nonexistent data
CNode : : SweepBanned ( ) ; //sweap out unused entries
2018-03-19 22:41:13 +01:00
logInfo ( Log : : Addrman ) < < " Loaded " < < addrman . size ( ) < < " addresses from peers.dat " ;
2014-09-18 14:08:43 +02:00
fAddressesInitialized = true ;
2012-05-10 18:44:07 +02:00
if ( semOutbound = = NULL ) {
// initialize semaphore
2017-08-15 10:32:47 -06:00
int nMaxOutbound = std : : min ( MAX_OUTBOUND_CONNECTIONS , nMaxConnections ) ;
2012-05-10 18:44:07 +02:00
semOutbound = new CSemaphore ( nMaxOutbound ) ;
}
2012-02-19 20:44:35 +01:00
if ( pnodeLocalHost = = NULL )
pnodeLocalHost = new CNode ( INVALID_SOCKET , CAddress ( CService ( " 127.0.0.1 " , 0 ) , nLocalServices ) ) ;
2013-12-09 14:08:51 +10:00
Discover ( threadGroup ) ;
2010-08-29 16:58:15 +00:00
//
// Start threads
//
2018-03-19 22:41:13 +01:00
if ( GetBoolArg ( " -dnsseed " , true ) )
2019-10-10 16:18:53 +02:00
threadGroup . create_thread ( std : : bind ( & TraceThread < void ( * ) ( ) > , " dnsseed " , & ThreadDNSAddressSeed ) ) ;
2011-11-21 12:25:00 -05:00
2011-03-26 13:01:27 +01:00
// Map ports with UPnP
2014-05-05 21:06:14 +02:00
MapPort ( GetBoolArg ( " -upnp " , DEFAULT_UPNP ) ) ;
2011-03-26 13:01:27 +01:00
2010-08-29 16:58:15 +00:00
// Send and receive from sockets, accept connections
2019-10-10 16:18:53 +02:00
threadGroup . create_thread ( std : : bind ( & TraceThread < void ( * ) ( ) > , " net " , & ThreadSocketHandler ) ) ;
2010-08-29 16:58:15 +00:00
2011-12-16 19:48:03 -05:00
// Initiate outbound connections from -addnode
2019-10-10 16:18:53 +02:00
threadGroup . create_thread ( std : : bind ( & TraceThread < void ( * ) ( ) > , " addcon " , & ThreadOpenAddedConnections ) ) ;
2011-12-16 19:48:03 -05:00
2010-08-29 16:58:15 +00:00
// Initiate outbound connections
2019-10-10 16:18:53 +02:00
threadGroup . create_thread ( std : : bind ( & TraceThread < void ( * ) ( ) > , " opencon " , & ThreadOpenConnections ) ) ;
2010-08-29 16:58:15 +00:00
// Process messages
2019-10-10 16:18:53 +02:00
threadGroup . create_thread ( std : : bind ( & TraceThread < void ( * ) ( ) > , " msghand " , & ThreadMessageHandler ) ) ;
2010-08-29 16:58:15 +00:00
2012-01-04 23:39:45 +01:00
// Dump network addresses
2015-06-19 15:27:37 +02:00
scheduler . scheduleEvery ( & DumpData , DUMP_ADDRESSES_INTERVAL ) ;
2010-08-29 16:58:15 +00:00
}
bool StopNode ( )
{
2018-11-20 21:07:53 +01:00
logCritical ( Log : : Net ) < < " StopNode() " ;
2013-03-06 22:31:26 -05:00
MapPort ( false ) ;
2012-05-12 17:44:14 +02:00
if ( semOutbound )
for ( int i = 0 ; i < MAX_OUTBOUND_CONNECTIONS ; i + + )
semOutbound - > post ( ) ;
2014-09-18 14:08:43 +02:00
if ( fAddressesInitialized )
{
2015-06-19 15:27:37 +02:00
DumpData ( ) ;
2014-09-18 14:08:43 +02:00
fAddressesInitialized = false ;
}
2013-03-29 02:17:10 +01:00
2010-08-29 16:58:15 +00:00
return true ;
}
class CNetCleanup
{
public :
2014-05-24 11:14:52 +02:00
CNetCleanup ( ) { }
2010-08-29 16:58:15 +00:00
~ CNetCleanup ( )
{
// Close sockets
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes )
2010-08-29 16:58:15 +00:00
if ( pnode - > hSocket ! = INVALID_SOCKET )
2014-07-10 12:13:03 +02:00
CloseSocket ( pnode - > hSocket ) ;
2018-12-30 15:33:11 +01:00
for ( ListenSocket & hListenSocket : vhListenSocket )
2014-06-21 13:34:36 +02:00
if ( hListenSocket . socket ! = INVALID_SOCKET )
2014-07-10 12:13:03 +02:00
if ( ! CloseSocket ( hListenSocket . socket ) )
2019-03-23 18:40:48 +01:00
// keep on debug level as its too dangerous to log in shutdown.
logDebug ( Log : : Net ) < < " CloseSocket(hListenSocket) failed with error " < < NetworkErrorString ( WSAGetLastError ( ) ) ;
2010-08-29 16:58:15 +00:00
2013-03-29 02:17:10 +01:00
// clean up some globals (to help leak detection)
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes )
2013-03-29 02:17:10 +01:00
delete pnode ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodesDisconnected )
2013-03-29 02:17:10 +01:00
delete pnode ;
vNodes . clear ( ) ;
vNodesDisconnected . clear ( ) ;
2014-06-22 14:52:38 +02:00
vhListenSocket . clear ( ) ;
2013-03-29 02:17:10 +01:00
delete semOutbound ;
semOutbound = NULL ;
delete pnodeLocalHost ;
pnodeLocalHost = NULL ;
2011-10-07 11:02:21 -04:00
# ifdef WIN32
2010-08-29 16:58:15 +00:00
// Shutdown Windows Sockets
WSACleanup ( ) ;
# endif
}
}
instance_of_cnetcleanup ;
2012-08-13 05:26:30 +02:00
2014-06-09 10:02:00 +02:00
void RelayTransaction ( const CTransaction & tx )
2012-08-13 05:26:30 +02:00
{
CDataStream ss ( SER_NETWORK , PROTOCOL_VERSION ) ;
ss . reserve ( 10000 ) ;
ss < < tx ;
2014-06-09 10:02:00 +02:00
RelayTransaction ( tx , ss ) ;
2012-08-13 05:26:30 +02:00
}
2014-06-09 10:02:00 +02:00
void RelayTransaction ( const CTransaction & tx , const CDataStream & ss )
2012-08-13 05:26:30 +02:00
{
2014-06-09 10:02:00 +02:00
CInv inv ( MSG_TX , tx . GetHash ( ) ) ;
2012-08-13 05:26:30 +02:00
{
LOCK ( cs_mapRelay ) ;
// Expire old relay messages
while ( ! vRelayExpiration . empty ( ) & & vRelayExpiration . front ( ) . first < GetTime ( ) )
{
mapRelay . erase ( vRelayExpiration . front ( ) . second ) ;
vRelayExpiration . pop_front ( ) ;
}
// Save original serialized message so newer versions are preserved
mapRelay . insert ( std : : make_pair ( inv , ss ) ) ;
vRelayExpiration . push_back ( std : : make_pair ( GetTime ( ) + 15 * 60 , inv ) ) ;
}
LOCK ( cs_vNodes ) ;
2018-12-30 15:33:11 +01:00
for ( CNode * pnode : vNodes ) {
2012-08-20 21:10:25 -04:00
if ( ! pnode - > fRelayTxes )
continue ;
2012-08-13 05:26:30 +02:00
LOCK ( pnode - > cs_filter ) ;
if ( pnode - > pfilter )
{
2014-06-09 10:02:00 +02:00
if ( pnode - > pfilter - > IsRelevantAndUpdate ( tx ) )
2012-08-13 05:26:30 +02:00
pnode - > PushInventory ( inv ) ;
} else
pnode - > PushInventory ( inv ) ;
}
}
2013-08-23 02:09:32 +10:00
2013-04-13 00:13:08 -05:00
void CNode : : RecordBytesRecv ( uint64_t bytes )
2013-08-23 02:09:32 +10:00
{
LOCK ( cs_totalBytesRecv ) ;
nTotalBytesRecv + = bytes ;
}
2013-04-13 00:13:08 -05:00
void CNode : : RecordBytesSent ( uint64_t bytes )
2013-08-23 02:09:32 +10:00
{
LOCK ( cs_totalBytesSent ) ;
nTotalBytesSent + = bytes ;
2015-09-02 17:03:27 +02:00
uint64_t now = GetTime ( ) ;
if ( nMaxOutboundCycleStartTime + nMaxOutboundTimeframe < now )
{
// timeframe expired, reset cycle
nMaxOutboundCycleStartTime = now ;
nMaxOutboundTotalBytesSentInCycle = 0 ;
}
// TODO, exclude whitebind peers
nMaxOutboundTotalBytesSentInCycle + = bytes ;
}
void CNode : : SetMaxOutboundTarget ( uint64_t limit )
{
LOCK ( cs_totalBytesSent ) ;
2017-08-14 15:01:24 +02:00
uint64_t recommendedMinimum = ( nMaxOutboundTimeframe / 600 ) * MAX_LEGACY_BLOCK_SIZE ;
2015-09-02 17:03:27 +02:00
nMaxOutboundLimit = limit ;
2015-11-06 00:05:06 +01:00
if ( limit > 0 & & limit < recommendedMinimum )
2018-11-20 21:07:53 +01:00
logCritical ( Log : : Net ) . nospace ( ) < < " Max outbound target is very small ( " < < nMaxOutboundLimit < < " bytes) and will be overshot. Recommended minimum is " < < recommendedMinimum < < " bytes. " ;
2015-09-02 17:03:27 +02:00
}
uint64_t CNode : : GetMaxOutboundTarget ( )
{
LOCK ( cs_totalBytesSent ) ;
return nMaxOutboundLimit ;
}
uint64_t CNode : : GetMaxOutboundTimeframe ( )
{
LOCK ( cs_totalBytesSent ) ;
return nMaxOutboundTimeframe ;
}
uint64_t CNode : : GetMaxOutboundTimeLeftInCycle ( )
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundLimit = = 0 )
return 0 ;
if ( nMaxOutboundCycleStartTime = = 0 )
return nMaxOutboundTimeframe ;
uint64_t cycleEndTime = nMaxOutboundCycleStartTime + nMaxOutboundTimeframe ;
uint64_t now = GetTime ( ) ;
return ( cycleEndTime < now ) ? 0 : cycleEndTime - GetTime ( ) ;
}
void CNode : : SetMaxOutboundTimeframe ( uint64_t timeframe )
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundTimeframe ! = timeframe )
{
// reset measure-cycle in case of changing
// the timeframe
nMaxOutboundCycleStartTime = GetTime ( ) ;
}
nMaxOutboundTimeframe = timeframe ;
}
bool CNode : : OutboundTargetReached ( bool historicalBlockServingLimit )
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundLimit = = 0 )
return false ;
if ( historicalBlockServingLimit )
{
// keep a large enought buffer to at least relay each block once
uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle ( ) ;
2017-08-14 15:01:24 +02:00
uint64_t buffer = timeLeftInCycle / 600 * MAX_LEGACY_BLOCK_SIZE ;
2015-09-02 17:03:27 +02:00
if ( buffer > = nMaxOutboundLimit | | nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit - buffer )
return true ;
}
else if ( nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit )
return true ;
return false ;
}
uint64_t CNode : : GetOutboundTargetBytesLeft ( )
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundLimit = = 0 )
return 0 ;
return ( nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit ) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle ;
2013-08-23 02:09:32 +10:00
}
2013-04-13 00:13:08 -05:00
uint64_t CNode : : GetTotalBytesRecv ( )
2013-08-23 02:09:32 +10:00
{
LOCK ( cs_totalBytesRecv ) ;
return nTotalBytesRecv ;
}
2013-04-13 00:13:08 -05:00
uint64_t CNode : : GetTotalBytesSent ( )
2013-08-23 02:09:32 +10:00
{
LOCK ( cs_totalBytesSent ) ;
return nTotalBytesSent ;
}
2013-10-28 16:28:00 +10:00
void CNode : : Fuzz ( int nChance )
{
if ( ! fSuccessfullyConnected ) return ; // Don't fuzz initial handshake
if ( GetRand ( nChance ) ! = 0 ) return ; // Fuzz 1 of every nChance messages
switch ( GetRand ( 3 ) )
{
case 0 :
// xor a random byte with a random value:
if ( ! ssSend . empty ( ) ) {
CDataStream : : size_type pos = GetRand ( ssSend . size ( ) ) ;
ssSend [ pos ] ^ = ( unsigned char ) ( GetRand ( 256 ) ) ;
}
break ;
case 1 :
// delete a random byte:
if ( ! ssSend . empty ( ) ) {
CDataStream : : size_type pos = GetRand ( ssSend . size ( ) ) ;
ssSend . erase ( ssSend . begin ( ) + pos ) ;
}
break ;
case 2 :
// insert a random byte at a random position
{
CDataStream : : size_type pos = GetRand ( ssSend . size ( ) ) ;
char ch = ( char ) GetRand ( 256 ) ;
ssSend . insert ( ssSend . begin ( ) + pos , ch ) ;
}
break ;
}
// Chance of more than one change half the time:
// (more changes exponentially less likely):
Fuzz ( 2 ) ;
}
2013-11-29 16:33:34 +01:00
//
// CAddrDB
//
CAddrDB : : CAddrDB ( )
{
pathAddr = GetDataDir ( ) / " peers.dat " ;
}
2017-08-01 13:07:18 +02:00
CAddrDB : : CAddrDB ( const boost : : filesystem : : path & peersFilename )
{
pathAddr = peersFilename ;
}
2013-11-29 16:33:34 +01:00
bool CAddrDB : : Write ( const CAddrMan & addr )
{
// Generate random temporary filename
unsigned short randv = 0 ;
2014-06-24 14:27:32 +02:00
GetRandBytes ( ( unsigned char * ) & randv , sizeof ( randv ) ) ;
2013-11-29 16:33:34 +01:00
std : : string tmpfn = strprintf ( " peers.dat.%04x " , randv ) ;
// serialize addresses, checksum data up to that point, then append csum
CDataStream ssPeers ( SER_DISK , CLIENT_VERSION ) ;
2017-08-01 13:07:18 +02:00
ssPeers < < FLATDATA ( Params ( ) . magic ( ) ) ;
2013-11-29 16:33:34 +01:00
ssPeers < < addr ;
uint256 hash = Hash ( ssPeers . begin ( ) , ssPeers . end ( ) ) ;
ssPeers < < hash ;
// open temp output file, and associate with CAutoFile
boost : : filesystem : : path pathTmp = GetDataDir ( ) / tmpfn ;
FILE * file = fopen ( pathTmp . string ( ) . c_str ( ) , " wb " ) ;
2014-09-25 19:25:19 -04:00
CAutoFile fileout ( file , SER_DISK , CLIENT_VERSION ) ;
2014-10-13 20:48:34 -03:00
if ( fileout . IsNull ( ) )
2015-01-08 11:44:25 +01:00
return error ( " %s: Failed to open file %s " , __func__ , pathTmp . string ( ) ) ;
2013-11-29 16:33:34 +01:00
// Write and commit header, data
try {
fileout < < ssPeers ;
}
2014-12-07 13:29:06 +01:00
catch ( const std : : exception & e ) {
2015-01-08 11:44:25 +01:00
return error ( " %s: Serialize or I/O error - %s " , __func__ , e . what ( ) ) ;
2013-11-29 16:33:34 +01:00
}
2014-10-20 12:45:50 +02:00
FileCommit ( fileout . Get ( ) ) ;
2013-11-29 16:33:34 +01:00
fileout . fclose ( ) ;
// replace existing peers.dat, if any, with new peers.dat.XXXX
if ( ! RenameOver ( pathTmp , pathAddr ) )
2015-01-08 11:44:25 +01:00
return error ( " %s: Rename-into-place failed " , __func__ ) ;
2013-11-29 16:33:34 +01:00
return true ;
}
bool CAddrDB : : Read ( CAddrMan & addr )
{
// open input file, and associate with CAutoFile
FILE * file = fopen ( pathAddr . string ( ) . c_str ( ) , " rb " ) ;
2014-09-25 19:25:19 -04:00
CAutoFile filein ( file , SER_DISK , CLIENT_VERSION ) ;
2014-10-13 20:48:34 -03:00
if ( filein . IsNull ( ) )
2015-01-08 11:44:25 +01:00
return error ( " %s: Failed to open file %s " , __func__ , pathAddr . string ( ) ) ;
2013-11-29 16:33:34 +01:00
// use file size to size memory buffer
2015-06-26 15:21:59 +02:00
uint64_t fileSize = boost : : filesystem : : file_size ( pathAddr ) ;
uint64_t dataSize = 0 ;
2014-01-30 10:55:55 +01:00
// Don't try to resize to a negative number if file is small
2015-06-26 15:21:59 +02:00
if ( fileSize > = sizeof ( uint256 ) )
dataSize = fileSize - sizeof ( uint256 ) ;
2017-08-15 10:32:47 -06:00
std : : vector < unsigned char > vchData ;
2013-11-29 16:33:34 +01:00
vchData . resize ( dataSize ) ;
uint256 hashIn ;
// read data and checksum from file
try {
filein . read ( ( char * ) & vchData [ 0 ] , dataSize ) ;
filein > > hashIn ;
}
2014-12-07 13:29:06 +01:00
catch ( const std : : exception & e ) {
2015-01-08 11:44:25 +01:00
return error ( " %s: Deserialize or I/O error - %s " , __func__ , e . what ( ) ) ;
2013-11-29 16:33:34 +01:00
}
filein . fclose ( ) ;
CDataStream ssPeers ( vchData , SER_DISK , CLIENT_VERSION ) ;
// verify stored checksum matches input data
uint256 hashTmp = Hash ( ssPeers . begin ( ) , ssPeers . end ( ) ) ;
if ( hashIn ! = hashTmp )
2015-01-08 11:44:25 +01:00
return error ( " %s: Checksum mismatch, data corrupted " , __func__ ) ;
2013-11-29 16:33:34 +01:00
2016-03-16 12:54:30 -04:00
return Read ( addr , ssPeers ) ;
}
bool CAddrDB : : Read ( CAddrMan & addr , CDataStream & ssPeers )
{
2013-11-29 16:33:34 +01:00
unsigned char pchMsgTmp [ 4 ] ;
try {
// de-serialize file header (network specific magic number) and ..
ssPeers > > FLATDATA ( pchMsgTmp ) ;
// ... verify the network matches ours
2017-08-01 13:07:18 +02:00
if ( memcmp ( pchMsgTmp , Params ( ) . magic ( ) , sizeof ( pchMsgTmp ) ) )
2015-01-08 11:44:25 +01:00
return error ( " %s: Invalid network magic number " , __func__ ) ;
2013-11-29 16:33:34 +01:00
// de-serialize address data into one CAddrMan object
ssPeers > > addr ;
}
2014-12-07 13:29:06 +01:00
catch ( const std : : exception & e ) {
2016-03-16 12:54:30 -04:00
// de-serialization has failed, ensure addrman is left in a clean state
addr . Clear ( ) ;
2015-01-08 11:44:25 +01:00
return error ( " %s: Deserialize or I/O error - %s " , __func__ , e . what ( ) ) ;
2013-11-29 16:33:34 +01:00
}
return true ;
}
2014-08-21 05:17:21 +02:00
2018-02-12 14:15:24 +01:00
unsigned int ReceiveFloodSize ( ) { return 1000 * GetArg ( " -maxreceivebuffer " , Settings : : DefaultMaxReceiveBuffer ) ; }
unsigned int SendBufferSize ( ) { return 1000 * GetArg ( " -maxsendbuffer " , Settings : : DefaultMaxSendBuffer ) ; }
2014-08-21 05:17:21 +02:00
2015-05-31 15:36:44 +02:00
CNode : : CNode ( SOCKET hSocketIn , const CAddress & addrIn , const std : : string & addrNameIn , bool fInboundIn ) :
2015-04-25 08:19:57 -07:00
ssSend ( SER_NETWORK , INIT_PROTO_VERSION ) ,
2017-02-08 17:28:21 +01:00
addrFromPort ( 0 ) ,
2015-07-20 04:43:34 +09:00
addrKnown ( 5000 , 0.001 ) ,
2015-11-26 05:25:30 +00:00
filterInventoryKnown ( 50000 , 0.000001 )
2014-08-21 05:17:21 +02:00
{
nServices = 0 ;
hSocket = hSocketIn ;
nRecvVersion = INIT_PROTO_VERSION ;
nLastSend = 0 ;
nLastRecv = 0 ;
nSendBytes = 0 ;
nRecvBytes = 0 ;
nTimeConnected = GetTime ( ) ;
2014-12-15 11:06:15 +01:00
nTimeOffset = 0 ;
2014-08-21 05:17:21 +02:00
addr = addrIn ;
addrName = addrNameIn = = " " ? addr . ToStringIPPort ( ) : addrNameIn ;
nVersion = 0 ;
strSubVer = " " ;
fWhitelisted = false ;
fOneShot = false ;
fClient = false ; // set by version message
fInbound = fInboundIn ;
fNetworkNode = false ;
2017-04-19 13:00:23 +02:00
fAutoOutbound = false ;
2014-08-21 05:17:21 +02:00
fSuccessfullyConnected = false ;
fDisconnect = false ;
nRefCount = 0 ;
nSendSize = 0 ;
nSendOffset = 0 ;
2014-12-15 09:11:16 +01:00
hashContinue = uint256 ( ) ;
2014-08-21 05:17:21 +02:00
nStartingHeight = - 1 ;
2015-11-26 05:25:30 +00:00
filterInventoryKnown . reset ( ) ;
2014-08-21 05:17:21 +02:00
fGetAddr = false ;
2015-04-08 11:20:00 -07:00
nNextLocalAddrSend = 0 ;
nNextAddrSend = 0 ;
nNextInvSend = 0 ;
2014-08-21 05:17:21 +02:00
fRelayTxes = false ;
2016-04-11 01:09:34 +00:00
fSentAddr = false ;
2014-08-21 05:17:21 +02:00
pfilter = new CBloomFilter ( ) ;
2016-04-25 14:36:03 +01:00
pThinBlockFilter = new CBloomFilter ( ) ;
2014-08-21 05:17:21 +02:00
nPingNonceSent = 0 ;
nPingUsecStart = 0 ;
nPingUsecTime = 0 ;
fPingQueued = false ;
2015-09-04 15:43:21 +02:00
nMinPingUsecTime = std : : numeric_limits < int64_t > : : max ( ) ;
2016-04-25 14:36:03 +01:00
thinBlockWaitingForTxns = - 1 ;
2014-08-21 05:17:21 +02:00
2016-03-09 10:39:39 -05:00
std : : string xmledName ;
2016-04-25 14:36:03 +01:00
if ( addrNameIn ! = " " )
xmledName = addrNameIn ;
2016-03-09 10:39:39 -05:00
else
2016-04-25 14:36:03 +01:00
xmledName = " ip " + addr . ToStringIP ( ) + " p " + addr . ToStringPort ( ) ;
2014-08-21 05:17:21 +02:00
{
LOCK ( cs_nLastNodeId ) ;
id = nLastNodeId + + ;
}
if ( fLogIPs )
2017-07-23 22:16:30 +02:00
logInfo ( Log : : Net ) < < " Added connection to " < < addrName < < " peer " < < id ;
2014-08-21 05:17:21 +02:00
else
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " Added connection peer " < < id ;
2014-08-21 05:17:21 +02:00
GetNodeSignals ( ) . InitializeNode ( GetId ( ) , this ) ;
}
CNode : : ~ CNode ( )
{
CloseSocket ( hSocket ) ;
if ( pfilter )
delete pfilter ;
2016-04-25 14:36:03 +01:00
delete pThinBlockFilter ;
2014-08-21 05:17:21 +02:00
2017-02-08 17:28:21 +01:00
addrFromPort = 0 ;
2014-08-21 05:17:21 +02:00
GetNodeSignals ( ) . FinalizeNode ( GetId ( ) ) ;
}
void CNode : : AskFor ( const CInv & inv )
{
2015-11-23 01:54:23 +00:00
if ( mapAskFor . size ( ) > MAPASKFOR_MAX_SZ | | setAskFor . size ( ) > SETASKFOR_MAX_SZ )
2014-09-09 09:18:05 +02:00
return ;
2015-11-23 01:54:23 +00:00
// a peer may not have multiple non-responded queue positions for a single inv item
2014-07-16 14:31:41 -07:00
if ( ! setAskFor . insert ( inv . hash ) . second )
return ;
2014-08-21 05:17:21 +02:00
// We're using mapAskFor as a priority queue,
// the key is the earliest time the request can be sent
int64_t nRequestTime ;
2016-04-11 12:52:29 -04:00
limitedmap < uint256 , int64_t > : : const_iterator it = mapAlreadyAskedFor . find ( inv . hash ) ;
2014-08-21 05:17:21 +02:00
if ( it ! = mapAlreadyAskedFor . end ( ) )
nRequestTime = it - > second ;
else
nRequestTime = 0 ;
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " askfor " < < inv < < nRequestTime < < DateTimeStrFormat ( " %H:%M:%S " , nRequestTime / 1000000 ) < < " peer: " < < id ;
2014-08-21 05:17:21 +02:00
// Make sure not to reuse time indexes to keep things in the same order
int64_t nNow = GetTimeMicros ( ) - 1000000 ;
static int64_t nLastTime ;
+ + nLastTime ;
nNow = std : : max ( nNow , nLastTime ) ;
nLastTime = nNow ;
// Each retry is 2 minutes after the last
nRequestTime = std : : max ( nRequestTime + 2 * 60 * 1000000 , nNow ) ;
if ( it ! = mapAlreadyAskedFor . end ( ) )
mapAlreadyAskedFor . update ( it , nRequestTime ) ;
else
2016-04-11 12:52:29 -04:00
mapAlreadyAskedFor . insert ( std : : make_pair ( inv . hash , nRequestTime ) ) ;
2014-08-21 05:17:21 +02:00
mapAskFor . insert ( std : : make_pair ( nRequestTime , inv ) ) ;
}
void CNode : : BeginMessage ( const char * pszCommand ) EXCLUSIVE_LOCK_FUNCTION ( cs_vSend )
{
2019-10-10 17:42:16 +02:00
ENTER_CRITICAL_SECTION ( cs_vSend )
2014-08-21 05:17:21 +02:00
assert ( ssSend . size ( ) = = 0 ) ;
2018-04-15 22:35:34 +02:00
ssSend < < CMessageHeader ( Params ( ) . magic ( ) , pszCommand , 0 ) ;
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) < < " sending: " < < SanitizeString ( pszCommand ) ;
2014-08-21 05:17:21 +02:00
}
void CNode : : AbortMessage ( ) UNLOCK_FUNCTION ( cs_vSend )
{
ssSend . clear ( ) ;
2019-10-10 17:42:16 +02:00
LEAVE_CRITICAL_SECTION ( cs_vSend )
2014-08-21 05:17:21 +02:00
2018-11-20 21:07:53 +01:00
logDebug ( Log : : Net ) ;
2014-08-21 05:17:21 +02:00
}
void CNode : : EndMessage ( ) UNLOCK_FUNCTION ( cs_vSend )
{
// The -*messagestest options are intentionally not documented in the help message,
// since they are only used during development to debug the networking code and are
// not intended for end-users.
if ( mapArgs . count ( " -dropmessagestest " ) & & GetRand ( GetArg ( " -dropmessagestest " , 2 ) ) = = 0 )
{
2018-11-20 21:07:53 +01:00
logDebug ( Log : : Net ) < < " dropmessages DROPPING SEND MESSAGE " ;
2014-08-21 05:17:21 +02:00
AbortMessage ( ) ;
return ;
}
if ( mapArgs . count ( " -fuzzmessagestest " ) )
Fuzz ( GetArg ( " -fuzzmessagestest " , 10 ) ) ;
if ( ssSend . size ( ) = = 0 )
2015-06-16 04:02:25 -04:00
{
2019-10-10 17:42:16 +02:00
LEAVE_CRITICAL_SECTION ( cs_vSend )
2014-08-21 05:17:21 +02:00
return ;
2015-06-16 04:02:25 -04:00
}
2014-08-21 05:17:21 +02:00
// Set the size
unsigned int nSize = ssSend . size ( ) - CMessageHeader : : HEADER_SIZE ;
2014-12-19 11:38:57 +01:00
WriteLE32 ( ( uint8_t * ) & ssSend [ CMessageHeader : : MESSAGE_SIZE_OFFSET ] , nSize ) ;
2014-08-21 05:17:21 +02:00
// Set the checksum
uint256 hash = Hash ( ssSend . begin ( ) + CMessageHeader : : HEADER_SIZE , ssSend . end ( ) ) ;
unsigned int nChecksum = 0 ;
memcpy ( & nChecksum , & hash , sizeof ( nChecksum ) ) ;
assert ( ssSend . size ( ) > = CMessageHeader : : CHECKSUM_OFFSET + sizeof ( nChecksum ) ) ;
memcpy ( ( char * ) & ssSend [ CMessageHeader : : CHECKSUM_OFFSET ] , & nChecksum , sizeof ( nChecksum ) ) ;
2017-07-23 22:16:30 +02:00
logDebug ( Log : : Net ) . nospace ( ) < < " ( " < < nSize < < " bytes) peer= " < < id ;
2014-08-21 05:17:21 +02:00
2019-08-24 15:01:22 +02:00
auto it = vSendMsg . insert ( vSendMsg . end ( ) , std : : vector < char > ( ) ) ;
2014-08-21 05:17:21 +02:00
ssSend . GetAndClear ( * it ) ;
nSendSize + = ( * it ) . size ( ) ;
// If write queue empty, attempt "optimistic write"
if ( it = = vSendMsg . begin ( ) )
SocketSendData ( this ) ;
2019-10-10 17:42:16 +02:00
LEAVE_CRITICAL_SECTION ( cs_vSend )
2014-08-21 05:17:21 +02:00
}
2015-06-19 15:27:37 +02:00
//
// CBanDB
//
CBanDB : : CBanDB ( )
{
pathBanlist = GetDataDir ( ) / " banlist.dat " ;
}
2017-08-01 13:07:18 +02:00
CBanDB : : CBanDB ( const boost : : filesystem : : path & banlistFilename )
{
pathBanlist = banlistFilename ;
}
2015-06-26 21:38:33 +02:00
bool CBanDB : : Write ( const banmap_t & banSet )
2015-06-19 15:27:37 +02:00
{
// Generate random temporary filename
unsigned short randv = 0 ;
GetRandBytes ( ( unsigned char * ) & randv , sizeof ( randv ) ) ;
std : : string tmpfn = strprintf ( " banlist.dat.%04x " , randv ) ;
// serialize banlist, checksum data up to that point, then append csum
CDataStream ssBanlist ( SER_DISK , CLIENT_VERSION ) ;
2017-08-01 13:07:18 +02:00
ssBanlist < < FLATDATA ( Params ( ) . magic ( ) ) ;
2015-06-19 15:27:37 +02:00
ssBanlist < < banSet ;
uint256 hash = Hash ( ssBanlist . begin ( ) , ssBanlist . end ( ) ) ;
ssBanlist < < hash ;
// open temp output file, and associate with CAutoFile
boost : : filesystem : : path pathTmp = GetDataDir ( ) / tmpfn ;
FILE * file = fopen ( pathTmp . string ( ) . c_str ( ) , " wb " ) ;
CAutoFile fileout ( file , SER_DISK , CLIENT_VERSION ) ;
if ( fileout . IsNull ( ) )
return error ( " %s: Failed to open file %s " , __func__ , pathTmp . string ( ) ) ;
// Write and commit header, data
try {
fileout < < ssBanlist ;
}
catch ( const std : : exception & e ) {
return error ( " %s: Serialize or I/O error - %s " , __func__ , e . what ( ) ) ;
}
FileCommit ( fileout . Get ( ) ) ;
fileout . fclose ( ) ;
// replace existing banlist.dat, if any, with new banlist.dat.XXXX
if ( ! RenameOver ( pathTmp , pathBanlist ) )
return error ( " %s: Rename-into-place failed " , __func__ ) ;
return true ;
}
2015-06-26 21:38:33 +02:00
bool CBanDB : : Read ( banmap_t & banSet )
2015-06-19 15:27:37 +02:00
{
// open input file, and associate with CAutoFile
FILE * file = fopen ( pathBanlist . string ( ) . c_str ( ) , " rb " ) ;
CAutoFile filein ( file , SER_DISK , CLIENT_VERSION ) ;
if ( filein . IsNull ( ) )
return error ( " %s: Failed to open file %s " , __func__ , pathBanlist . string ( ) ) ;
// use file size to size memory buffer
2015-06-26 15:21:59 +02:00
uint64_t fileSize = boost : : filesystem : : file_size ( pathBanlist ) ;
uint64_t dataSize = 0 ;
2015-06-19 15:27:37 +02:00
// Don't try to resize to a negative number if file is small
2015-06-26 15:21:59 +02:00
if ( fileSize > = sizeof ( uint256 ) )
dataSize = fileSize - sizeof ( uint256 ) ;
2017-08-15 10:32:47 -06:00
std : : vector < unsigned char > vchData ;
2015-06-19 15:27:37 +02:00
vchData . resize ( dataSize ) ;
uint256 hashIn ;
// read data and checksum from file
try {
filein . read ( ( char * ) & vchData [ 0 ] , dataSize ) ;
filein > > hashIn ;
}
catch ( const std : : exception & e ) {
return error ( " %s: Deserialize or I/O error - %s " , __func__ , e . what ( ) ) ;
}
filein . fclose ( ) ;
CDataStream ssBanlist ( vchData , SER_DISK , CLIENT_VERSION ) ;
// verify stored checksum matches input data
uint256 hashTmp = Hash ( ssBanlist . begin ( ) , ssBanlist . end ( ) ) ;
if ( hashIn ! = hashTmp )
return error ( " %s: Checksum mismatch, data corrupted " , __func__ ) ;
unsigned char pchMsgTmp [ 4 ] ;
try {
// de-serialize file header (network specific magic number) and ..
ssBanlist > > FLATDATA ( pchMsgTmp ) ;
// ... verify the network matches ours
2017-08-01 13:07:18 +02:00
if ( memcmp ( pchMsgTmp , Params ( ) . magic ( ) , sizeof ( pchMsgTmp ) ) )
2015-06-19 15:27:37 +02:00
return error ( " %s: Invalid network magic number " , __func__ ) ;
2017-04-19 13:00:23 +02:00
2015-06-19 15:27:37 +02:00
// de-serialize address data into one CAddrMan object
ssBanlist > > banSet ;
}
catch ( const std : : exception & e ) {
return error ( " %s: Deserialize or I/O error - %s " , __func__ , e . what ( ) ) ;
}
2017-04-19 13:00:23 +02:00
2015-06-19 15:27:37 +02:00
return true ;
}
void DumpBanlist ( )
{
int64_t nStart = GetTimeMillis ( ) ;
2015-08-09 00:17:27 +01:00
CNode : : SweepBanned ( ) ; //clean unused entries (if bantime has expired)
2015-06-19 15:27:37 +02:00
CBanDB bandb ;
2015-06-26 21:38:33 +02:00
banmap_t banmap ;
2015-06-19 15:27:37 +02:00
CNode : : GetBanned ( banmap ) ;
bandb . Write ( banmap ) ;
2018-11-20 21:07:53 +01:00
logInfo ( Log : : Net ) < < " Flushed " < < banmap . size ( ) < < " banned node ips/subnets to banlist.dat "
< < ( GetTimeMillis ( ) - nStart ) < < " ms " ;
2015-07-10 15:06:50 +02:00
}
2015-04-08 11:20:00 -07:00
int64_t PoissonNextSend ( int64_t nNow , int average_interval_seconds ) {
return nNow + ( int64_t ) ( log1p ( GetRand ( 1ULL < < 48 ) * - 0.0000000000000035527136788 /* -1/2^48 */ ) * average_interval_seconds * - 1000000.0 + 0.5 ) ;
}