2010-08-29 18:58:15 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2015-12-13 17:58:29 +01:00
// Copyright (c) 2009-2015 The Bitcoin Core developers
2014-12-13 05:09:33 +01:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 16:02:28 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2010-08-29 18:58:15 +02:00
2013-05-28 01:55:01 +02:00
# if defined(HAVE_CONFIG_H)
2014-06-23 20:04:24 +02:00
# include "config/bitcoin-config.h"
2013-05-28 01:55:01 +02:00
# endif
2011-05-14 23:20:30 +02:00
# include "net.h"
2013-04-13 07:13:08 +02:00
2012-01-04 23:39:45 +01:00
# include "addrman.h"
2013-04-13 07:13:08 +02:00
# include "chainparams.h"
2014-10-29 02:33:23 +01:00
# include "clientversion.h"
2015-09-02 17:03:27 +02:00
# include "consensus/consensus.h"
2015-07-05 14:30:07 +02:00
# include "crypto/common.h"
2016-05-23 09:21:05 +02:00
# include "crypto/sha256.h"
2015-07-05 14:30:07 +02:00
# include "hash.h"
2014-11-18 22:03:02 +01:00
# include "primitives/transaction.h"
2016-05-31 23:42:38 +02:00
# include "netbase.h"
2015-04-02 18:04:59 +02:00
# include "scheduler.h"
2012-04-15 22:10:54 +02:00
# include "ui_interface.h"
2015-07-05 14:30:07 +02:00
# include "utilstrencodings.h"
2013-04-13 07:13:08 +02:00
2011-10-07 17:02:21 +02:00
# ifdef WIN32
2011-07-02 03:59:37 +02:00
# include <string.h>
2013-04-13 07:13:08 +02:00
# else
2013-07-17 10:51:40 +02:00
# include <fcntl.h>
# endif
2011-03-26 13:01:27 +01:00
# ifdef USE_UPNP
# include <miniupnpc/miniupnpc.h>
2013-04-13 07:13:08 +02: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>
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
# include <boost/thread.hpp>
2014-01-30 10:55:55 +01:00
2015-04-08 20:20:00 +02:00
# include <math.h>
2015-07-03 09:46:17 +02:00
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
2013-06-24 00:23:28 +02:00
# define DUMP_ADDRESSES_INTERVAL 900
2013-04-13 07:13:08 +02:00
2016-06-17 06:10:07 +02:00
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
# define FEELER_SLEEP_WINDOW 1
2013-04-13 07:13:08 +02:00
# if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
2013-05-28 01:55:01 +02: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
2011-05-15 09:11:04 +02:00
2014-06-21 13:34:36 +02:00
namespace {
const int MAX_OUTBOUND_CONNECTIONS = 8 ;
2016-06-17 06:10:07 +02:00
const int MAX_FEELER_CONNECTIONS = 1 ;
2014-06-21 13:34:36 +02:00
struct ListenSocket {
SOCKET socket ;
bool whitelisted ;
ListenSocket ( SOCKET socket , bool whitelisted ) : socket ( socket ) , whitelisted ( whitelisted ) { }
} ;
}
2010-08-29 18:58:15 +02:00
2015-08-25 16:30:31 +02:00
const static std : : string NET_MESSAGE_COMMAND_OTHER = " *other* " ;
2016-03-26 19:09:22 +01:00
/** Services this node implementation cares about */
2015-11-17 00:20:49 +01:00
ServiceFlags nRelevantServices = NODE_NETWORK ;
2016-03-26 19:09:22 +01:00
2010-08-29 18:58:15 +02: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 ;
2016-06-08 19:12:22 +02:00
ServiceFlags nLocalServices = NODE_NETWORK ;
2016-05-12 14:00:22 +02:00
bool fRelayTxes = true ;
2014-05-05 13:22:28 +02:00
CCriticalSection cs_mapLocalHost ;
2016-04-16 01:53:45 +02:00
std : : map < CNetAddr , LocalServiceInfo > mapLocalHost ;
2012-05-04 16:46:22 +02:00
static bool vfLimited [ NET_MAX ] = { } ;
2011-08-11 13:41:01 +02:00
static CNode * pnodeLocalHost = NULL ;
2013-04-13 07:13:08 +02: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 ;
2015-08-01 19:41:21 +02:00
int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS ;
2014-09-18 14:08:43 +02:00
bool fAddressesInitialized = false ;
2015-07-31 18:05:42 +02:00
std : : string strSubVersion ;
2010-08-29 18:58:15 +02:00
2016-04-16 01:53:45 +02:00
std : : vector < CNode * > vNodes ;
2010-08-29 18:58:15 +02:00
CCriticalSection cs_vNodes ;
2016-04-11 18:52:29 +02:00
limitedmap < uint256 , int64_t > mapAlreadyAskedFor ( MAX_INV_SZ ) ;
2010-08-29 18:58:15 +02:00
2016-04-16 01:53:45 +02:00
static std : : deque < std : : string > vOneShots ;
2012-04-24 02:15:00 +02:00
CCriticalSection cs_vOneShots ;
2010-08-29 18:58:15 +02:00
2016-04-16 01:53:45 +02: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 11:35:37 +02:00
boost : : condition_variable messageHandlerCondition ;
2010-08-29 18:58:15 +02:00
2013-06-06 05:21:41 +02:00
// Signals for message handling
static CNodeSignals g_signals ;
CNodeSignals & GetNodeSignals ( ) { return g_signals ; }
2013-01-07 17:07:51 +01: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 16:45:08 +02:00
unsigned short GetListenPort ( )
{
2013-05-07 15:16:25 +02:00
return ( unsigned short ) ( GetArg ( " -port " , Params ( ) . GetDefaultPort ( ) ) ) ;
2011-04-21 16:45:08 +02:00
}
2010-08-29 18:58:15 +02: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 18:58:15 +02: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 ) ;
2016-04-16 01:53:45 +02: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
}
2010-08-29 18:58:15 +02:00
2015-01-24 05:40:50 +01: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 ) ) ;
2016-05-25 17:18:37 +02:00
CAddress addr ( CService ( ip , i - > port ) , NODE_NETWORK ) ;
2015-01-24 05:40:50 +01:00
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-21 08:32:25 +02: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 )
{
2016-05-31 19:51:11 +02:00
CAddress ret ( CService ( CNetAddr ( ) , GetListenPort ( ) ) , NODE_NONE ) ;
2012-05-10 20:35:13 +02:00
CService addr ;
2012-02-12 13:45:24 +01:00
if ( GetLocal ( addr , paddrPeer ) )
{
2016-05-25 17:18:37 +02:00
ret = CAddress ( addr , nLocalServices ) ;
2012-02-12 13:45:24 +01:00
}
2014-07-21 08:32:25 +02:00
ret . nTime = GetAdjustedTime ( ) ;
2012-02-12 13:45:24 +01:00
return ret ;
}
2010-08-29 18:58:15 +02:00
2014-07-21 08:32:25 +02:00
int GetnScore ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
2014-07-21 08:32:25 +02: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 19:35:32 +01:00
void AdvertiseLocal ( CNode * pnode )
2014-07-21 08:32:25 +02:00
{
if ( fListen & & pnode - > fSuccessfullyConnected )
2012-02-12 13:45:24 +01:00
{
2014-07-21 08:32:25 +02: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-21 08:32:25 +02:00
addrLocal . SetIP ( pnode - > addrLocal ) ;
}
if ( addrLocal . IsRoutable ( ) )
{
2016-08-05 18:34:32 +02:00
LogPrint ( " net " , " AdvertiseLocal: advertising address %s \n " , addrLocal . ToString ( ) ) ;
2014-07-21 08:32:25 +02: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 ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " AddLocal(%s,%i) \n " , addr . ToString ( ) , 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
}
2015-09-08 17:48:45 +02:00
bool RemoveLocal ( const CService & addr )
{
LOCK ( cs_mapLocalHost ) ;
LogPrintf ( " RemoveLocal(%s) \n " , addr . ToString ( ) ) ;
mapLocalHost . erase ( addr ) ;
return true ;
}
2012-05-04 16:46:22 +02:00
/** Make a particular network entirely off-limits (no automatic connects to it) */
void SetLimited ( enum Network net , bool fLimited )
{
2012-05-14 17:15:58 +02:00
if ( net = = NET_UNROUTABLE )
return ;
2012-05-04 16:46:22 +02:00
LOCK ( cs_mapLocalHost ) ;
vfLimited [ net ] = fLimited ;
}
2012-05-14 17:15:58 +02:00
bool IsLimited ( enum 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-21 08:32:25 +02: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 18:58:15 +02:00
2014-07-30 15:31:36 +02:00
/** check whether a given network is one we can probably connect to */
bool IsReachable ( enum Network net )
{
LOCK ( cs_mapLocalHost ) ;
2016-02-18 07:44:32 +01:00
return ! vfLimited [ net ] ;
2014-07-30 15:31:36 +02: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 )
{
2012-05-04 16:46:22 +02:00
enum 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 18:58:15 +02:00
2012-01-03 23:33:31 +01:00
void AddressCurrentlyConnected ( const CService & addr )
2010-08-29 18:58:15 +02:00
{
2012-01-04 23:39:45 +01:00
addrman . Connected ( addr ) ;
2010-08-29 18:58:15 +02:00
}
2013-04-13 07:13:08 +02:00
uint64_t CNode : : nTotalBytesRecv = 0 ;
uint64_t CNode : : nTotalBytesSent = 0 ;
2013-08-22 18:09:32 +02:00
CCriticalSection CNode : : cs_totalBytesRecv ;
CCriticalSection CNode : : cs_totalBytesSent ;
2010-08-29 18:58:15 +02: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 18:58:15 +02:00
{
2013-04-04 11:30:55 +02:00
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( ( CNetAddr ) pnode - > addr = = ip )
return ( pnode ) ;
2010-08-29 18:58:15 +02:00
return NULL ;
}
2015-05-25 20:03:51 +02:00
CNode * FindNode ( const CSubNet & subNet )
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
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 ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( pnode - > addrName = = addrName )
return ( pnode ) ;
return NULL ;
}
2012-01-03 23:33:31 +01:00
CNode * FindNode ( const CService & addr )
2010-08-29 18:58:15 +02:00
{
2013-04-04 11:30:55 +02:00
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( ( CService ) pnode - > addr = = addr )
return ( pnode ) ;
2010-08-29 18:58:15 +02:00
return NULL ;
}
2016-05-06 20:50:24 +02:00
//TODO: This is used in only one place in main, and should be removed
CNode * FindNode ( const NodeId nodeid )
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( pnode - > GetId ( ) = = nodeid )
return ( pnode ) ;
return NULL ;
}
2015-04-19 21:34:43 +02:00
CNode * ConnectNode ( CAddress addrConnect , const char * pszDest , bool fCountFailure )
2010-08-29 18:58:15 +02: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 18:58:15 +02: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 18:58:15 +02:00
}
/// debug print
2013-09-18 12:38:08 +02:00
LogPrint ( " net " , " trying connection %s lastseen=%.1fhrs \n " ,
2014-01-16 16:15:27 +01:00
pszDest ? pszDest : addrConnect . ToString ( ) ,
2014-05-24 11:14:52 +02:00
pszDest ? 0.0 : ( double ) ( GetAdjustedTime ( ) - addrConnect . nTime ) / 3600.0 ) ;
2010-08-29 18:58:15 +02: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 18:58:15 +02:00
{
2015-07-10 00:23:27 +02:00
if ( ! IsSelectableSocket ( hSocket ) ) {
LogPrintf ( " Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?) \n " ) ;
CloseSocket ( hSocket ) ;
return NULL ;
}
2016-05-28 16:22:02 +02:00
if ( pszDest & & addrConnect . IsValid ( ) ) {
// It is possible that we already have a connection to the IP/port pszDest resolved to.
// In that case, drop the connection that was just created, and return the existing CNode instead.
// Also store the name we used to connect in that CNode, so that future FindNode() calls to that
// name catch this early.
CNode * pnode = FindNode ( ( CService ) addrConnect ) ;
if ( pnode )
{
pnode - > AddRef ( ) ;
{
LOCK ( cs_vNodes ) ;
if ( pnode - > addrName . empty ( ) ) {
pnode - > addrName = std : : string ( pszDest ) ;
}
}
CloseSocket ( hSocket ) ;
return pnode ;
}
}
2015-04-19 21:34:43 +02:00
addrman . Attempt ( addrConnect , fCountFailure ) ;
2012-04-19 17:38:03 +02:00
2010-08-29 18:58:15 +02:00
// Add node
2012-04-19 17:38:03 +02:00
CNode * pnode = new CNode ( hSocket , addrConnect , pszDest ? pszDest : " " , false ) ;
2013-03-29 00:43:31 +01:00
pnode - > AddRef ( ) ;
2012-04-19 17:38:03 +02:00
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_vNodes ) ;
2010-08-29 18:58:15 +02:00
vNodes . push_back ( pnode ) ;
2012-04-06 18:39:12 +02:00
}
2010-08-29 18:58:15 +02:00
2016-06-08 19:12:22 +02:00
pnode - > nServicesExpected = ServiceFlags ( addrConnect . nServices & nRelevantServices ) ;
2010-08-29 18:58:15 +02:00
pnode - > nTimeConnected = GetTime ( ) ;
2014-02-27 02:55:04 +01:00
2010-08-29 18:58:15 +02: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.
2015-04-19 21:34:43 +02:00
addrman . Attempt ( addrConnect , fCountFailure ) ;
2010-08-29 18:58:15 +02:00
}
2014-05-24 11:14:52 +02:00
return NULL ;
2010-08-29 18:58:15 +02:00
}
2016-04-18 23:59:31 +02:00
static void DumpBanlist ( )
{
CNode : : SweepBanned ( ) ; // clean unused entries (if bantime has expired)
if ( ! CNode : : BannedSetIsDirty ( ) )
return ;
int64_t nStart = GetTimeMillis ( ) ;
CBanDB bandb ;
banmap_t banmap ;
CNode : : SetBannedSetDirty ( false ) ;
CNode : : GetBanned ( banmap ) ;
if ( ! bandb . Write ( banmap ) )
CNode : : SetBannedSetDirty ( true ) ;
LogPrint ( " net " , " Flushed %d banned node ips/subnets to banlist.dat %dms \n " ,
banmap . size ( ) , GetTimeMillis ( ) - nStart ) ;
}
2010-08-29 18:58:15 +02:00
void CNode : : CloseSocketDisconnect ( )
{
fDisconnect = true ;
if ( hSocket ! = INVALID_SOCKET )
{
2014-02-27 02:55:04 +01:00
LogPrint ( " net " , " disconnecting peer=%d \n " , id ) ;
2014-07-10 12:13:03 +02:00
CloseSocket ( hSocket ) ;
2010-08-29 18:58:15 +02: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 18:58:15 +02:00
}
2011-12-16 22:26:14 +01:00
void CNode : : PushVersion ( )
{
2016-04-16 02:03:18 +02:00
int nBestHeight = GetNodeSignals ( ) . GetHeight ( ) . get_value_or ( 0 ) ;
2013-10-10 23:07:44 +02:00
2013-04-13 07:13:08 +02:00
int64_t nTime = ( fInbound ? GetAdjustedTime ( ) : GetTime ( ) ) ;
2016-05-31 19:51:11 +02:00
CAddress addrYou = ( addr . IsRoutable ( ) & & ! IsProxy ( addr ) ? addr : CAddress ( CService ( ) , addr . nServices ) ) ;
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-27 02:55:04 +01:00
if ( fLogIPs )
LogPrint ( " net " , " send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d \n " , PROTOCOL_VERSION , nBestHeight , addrMe . ToString ( ) , addrYou . ToString ( ) , id ) ;
else
LogPrint ( " net " , " send version message: version %d, blocks=%d, us=%s, peer=%d \n " , PROTOCOL_VERSION , nBestHeight , addrMe . ToString ( ) , id ) ;
2016-06-08 19:12:22 +02:00
PushMessage ( NetMsgType : : VERSION , PROTOCOL_VERSION , ( uint64_t ) nLocalServices , nTime , addrYou , addrMe ,
2016-05-26 18:44:14 +02:00
nLocalHostNonce , strSubVersion , nBestHeight , : : fRelayTxes ) ;
2011-12-16 22:26:14 +01:00
}
2015-06-26 21:38:33 +02:00
banmap_t CNode : : setBanned ;
2011-09-06 22:09:04 +02:00
CCriticalSection CNode : : cs_setBanned ;
2015-06-19 15:27:37 +02:00
bool CNode : : setBannedIsDirty ;
2011-09-06 22:09:04 +02:00
void CNode : : ClearBanned ( )
{
2016-04-18 23:02:43 +02:00
{
LOCK ( cs_setBanned ) ;
setBanned . clear ( ) ;
setBannedIsDirty = true ;
}
DumpBanlist ( ) ; //store banlist to disk
uiInterface . BannedListChanged ( ) ;
2011-09-06 22:09:04 +02:00
}
2012-01-03 23:33:31 +01:00
bool CNode : : IsBanned ( CNetAddr ip )
2011-09-06 22:09:04 +02: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 22:09:04 +02:00
if ( i ! = setBanned . end ( ) )
{
2015-06-26 21:38:33 +02:00
CBanEntry banEntry = ( * i ) . second ;
if ( GetTime ( ) < banEntry . nBanUntil )
2011-09-06 22:09:04 +02: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 )
{
2015-06-27 21:21:41 +02:00
bantimeoffset = GetArg ( " -bantime " , DEFAULT_MISBEHAVING_BANTIME ) ;
2015-06-26 21:38:33 +02:00
sinceUnixEpoch = false ;
}
banEntry . nBanUntil = ( sinceUnixEpoch ? 0 : GetTime ( ) ) + bantimeoffset ;
2016-04-18 23:02:43 +02:00
{
LOCK ( cs_setBanned ) ;
if ( setBanned [ subNet ] . nBanUntil < banEntry . nBanUntil ) {
setBanned [ subNet ] = banEntry ;
setBannedIsDirty = true ;
}
else
return ;
}
uiInterface . BannedListChanged ( ) ;
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes ) {
if ( subNet . Match ( ( CNetAddr ) pnode - > addr ) )
pnode - > fDisconnect = true ;
}
}
if ( banReason = = BanReasonManuallyAdded )
DumpBanlist ( ) ; //store banlist to disk immediately if user requested ban
2011-09-06 22:09:04 +02: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-06-19 15:27:37 +02:00
{
2016-04-18 23:02:43 +02:00
LOCK ( cs_setBanned ) ;
if ( ! setBanned . erase ( subNet ) )
return false ;
2015-06-19 15:27:37 +02:00
setBannedIsDirty = true ;
}
2016-04-18 23:02:43 +02:00
uiInterface . BannedListChanged ( ) ;
DumpBanlist ( ) ; //store banlist to disk immediately
return true ;
2015-05-19 10:07:23 +02:00
}
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-07-03 09:46:17 +02:00
CSubNet subNet = ( * it ) . first ;
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 ;
2015-07-03 09:46:17 +02:00
LogPrint ( " net " , " %s: Removed banned node ip/subnet from banlist.dat: %s \n " , __func__ , subNet . ToString ( ) ) ;
2015-06-19 15:27:37 +02:00
}
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 ) ;
BOOST_FOREACH ( const CSubNet & subnet , vWhitelistedRange ) {
if ( subnet . Match ( addr ) )
return true ;
}
return false ;
}
void CNode : : AddWhitelistedRange ( const CSubNet & subnet ) {
LOCK ( cs_vWhitelistedRange ) ;
vWhitelistedRange . push_back ( subnet ) ;
}
2012-06-29 23:24:53 +02: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 23:24:53 +02:00
X ( nServices ) ;
2015-11-21 00:51:44 +01:00
X ( fRelayTxes ) ;
2012-06-29 23:24:53 +02:00
X ( nLastSend ) ;
X ( nLastRecv ) ;
X ( nTimeConnected ) ;
2014-12-15 11:06:15 +01:00
X ( nTimeOffset ) ;
2012-06-29 23:24:53 +02:00
X ( addrName ) ;
X ( nVersion ) ;
2013-11-26 12:52:21 +01:00
X ( cleanSubVer ) ;
2012-06-29 23:24:53 +02:00
X ( fInbound ) ;
X ( nStartingHeight ) ;
2013-04-07 19:31:13 +02:00
X ( nSendBytes ) ;
2015-08-25 16:30:31 +02:00
X ( mapSendBytesPerMsgCmd ) ;
2013-04-07 19:31:13 +02:00
X ( nRecvBytes ) ;
2015-08-25 16:30:31 +02:00
X ( mapRecvBytesPerMsgCmd ) ;
2014-06-21 13:34:36 +02:00
X ( fWhitelisted ) ;
2013-11-15 12:24:34 +01:00
2013-08-22 13:34:33 +02: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 07:13:08 +02:00
int64_t nPingUsecWait = 0 ;
2013-08-22 13:34:33 +02:00
if ( ( 0 ! = nPingNonceSent ) & & ( 0 ! = nPingUsecStart ) ) {
nPingUsecWait = GetTimeMicros ( ) - nPingUsecStart ;
}
2013-11-15 12:24:34 +01:00
2013-08-22 13:34:33 +02: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 22:06:13 +02:00
stats . dPingMin = ( ( ( double ) nMinPingUsecTime ) / 1e6 ) ;
2013-08-22 13:34:33 +02:00
stats . dPingWait = ( ( ( double ) nPingUsecWait ) / 1e6 ) ;
2013-11-15 12:24:34 +01:00
2013-08-22 07:50:19 +02:00
// Leave string empty if addrLocal invalid (not filled in yet)
stats . addrLocal = addrLocal . IsValid ( ) ? addrLocal . ToString ( ) : " " ;
2012-06-29 23:24:53 +02:00
}
# undef X
2010-08-29 18:58:15 +02:00
2012-11-16 01:41:12 +01: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-16 01:41:12 +01:00
vRecvMsg . back ( ) . complete ( ) )
2014-10-28 01:24:31 +01:00
vRecvMsg . push_back ( CNetMessage ( Params ( ) . MessageStart ( ) , SER_NETWORK , nRecvVersion ) ) ;
2012-11-16 01:41:12 +01: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 )
return false ;
2015-03-05 13:01:22 +01:00
if ( msg . in_data & & msg . hdr . nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH ) {
2015-08-29 18:40:13 +02:00
LogPrint ( " net " , " Oversized message from peer=%i, disconnecting \n " , GetId ( ) ) ;
2015-03-05 13:01:22 +01:00
return false ;
}
2012-11-16 01:41:12 +01:00
pch + = handled ;
nBytes - = handled ;
2014-07-06 16:06:46 +02:00
2015-04-05 11:35:37 +02:00
if ( msg . complete ( ) ) {
2015-08-25 16:30:31 +02:00
//store received bytes per message command
//to prevent a memory DOS, only allow valid commands
mapMsgCmdSize : : iterator i = mapRecvBytesPerMsgCmd . find ( msg . hdr . pchCommand ) ;
if ( i = = mapRecvBytesPerMsgCmd . end ( ) )
i = mapRecvBytesPerMsgCmd . find ( NET_MESSAGE_COMMAND_OTHER ) ;
assert ( i ! = mapRecvBytesPerMsgCmd . end ( ) ) ;
i - > second + = msg . hdr . nMessageSize + CMessageHeader : : HEADER_SIZE ;
2014-07-06 16:06:46 +02:00
msg . nTime = GetTimeMicros ( ) ;
2015-04-05 11:35:37 +02:00
messageHandlerCondition . notify_one ( ) ;
}
2012-11-16 01:41:12 +01: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-16 01:41:12 +01: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-16 01:41:12 +01:00
memcpy ( & vRecv [ nDataPos ] , pch , nCopy ) ;
nDataPos + = nCopy ;
return nCopy ;
}
2010-08-29 18:58:15 +02:00
2012-11-16 00:04:52 +01:00
// requires LOCK(cs_vSend)
void SocketSendData ( CNode * pnode )
{
2013-03-24 16:52:24 +01:00
std : : deque < CSerializeData > : : iterator it = pnode - > vSendMsg . begin ( ) ;
while ( it ! = pnode - > vSendMsg . end ( ) ) {
const CSerializeData & data = * it ;
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-22 18:09:32 +02: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 )
{
2014-05-08 14:15:19 +02:00
LogPrintf ( " socket send error %s \n " , NetworkErrorString ( nErr ) ) ;
2013-03-24 16:52:24 +01:00
pnode - > CloseSocketDisconnect ( ) ;
}
}
// couldn't send anything at all
break ;
2012-11-16 00:04:52 +01: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-16 00:04:52 +01:00
}
2010-08-29 18:58:15 +02:00
2016-04-16 01:53:45 +02:00
static std : : list < CNode * > vNodesDisconnected ;
2013-03-29 02:17:10 +01:00
2016-04-18 21:58:19 +02:00
struct NodeEvictionCandidate
{
NodeId id ;
int64_t nTimeConnected ;
int64_t nMinPingUsecTime ;
2016-05-22 07:55:15 +02:00
int64_t nLastBlockTime ;
int64_t nLastTXTime ;
bool fNetworkNode ;
bool fRelayTxes ;
bool fBloomFilter ;
2016-04-18 21:58:19 +02:00
CAddress addr ;
2016-05-25 15:38:32 +02:00
uint64_t nKeyedNetGroup ;
2015-08-21 02:29:04 +02:00
} ;
2016-04-18 21:58:19 +02:00
static bool ReverseCompareNodeMinPingTime ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
2015-08-13 11:58:58 +02:00
{
2016-04-18 21:58:19 +02:00
return a . nMinPingUsecTime > b . nMinPingUsecTime ;
2015-08-13 11:58:58 +02:00
}
2016-04-18 21:58:19 +02:00
static bool ReverseCompareNodeTimeConnected ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
2015-08-13 11:58:58 +02:00
{
2016-04-18 21:58:19 +02:00
return a . nTimeConnected > b . nTimeConnected ;
2015-08-13 11:58:58 +02:00
}
2016-05-23 09:21:05 +02:00
static bool CompareNetGroupKeyed ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b ) {
2016-05-25 15:38:32 +02:00
return a . nKeyedNetGroup < b . nKeyedNetGroup ;
2016-05-22 07:55:15 +02:00
}
static bool CompareNodeBlockTime ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
{
// There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block.
if ( a . nLastBlockTime ! = b . nLastBlockTime ) return a . nLastBlockTime < b . nLastBlockTime ;
if ( a . fNetworkNode ! = b . fNetworkNode ) return b . fNetworkNode ;
return a . nTimeConnected > b . nTimeConnected ;
}
static bool CompareNodeTXTime ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
{
// There is a fall-through here because it is common for a node to have more than a few peers that have not yet relayed txn.
if ( a . nLastTXTime ! = b . nLastTXTime ) return a . nLastTXTime < b . nLastTXTime ;
if ( a . fRelayTxes ! = b . fRelayTxes ) return b . fRelayTxes ;
if ( a . fBloomFilter ! = b . fBloomFilter ) return a . fBloomFilter ;
return a . nTimeConnected > b . nTimeConnected ;
}
2015-08-13 11:58:58 +02:00
2016-04-29 16:23:51 +02:00
/** Try to find a connection to evict when the node is full.
* Extreme care must be taken to avoid opening the node to attacker
* triggered network partitioning .
* The strategy used here is to protect a small number of peers
* for each of several distinct characteristics which are difficult
* to forge . In order to partition a node the attacker must be
* simultaneously better at all of them than honest peers .
*/
2016-05-22 07:55:15 +02:00
static bool AttemptToEvictConnection ( ) {
2016-04-18 21:58:19 +02:00
std : : vector < NodeEvictionCandidate > vEvictionCandidates ;
2015-08-13 11:58:58 +02:00
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * node , vNodes ) {
if ( node - > fWhitelisted )
continue ;
if ( ! node - > fInbound )
continue ;
if ( node - > fDisconnect )
continue ;
2016-05-22 07:55:15 +02:00
NodeEvictionCandidate candidate = { node - > id , node - > nTimeConnected , node - > nMinPingUsecTime ,
node - > nLastBlockTime , node - > nLastTXTime , node - > fNetworkNode ,
node - > fRelayTxes , node - > pfilter ! = NULL , node - > addr , node - > nKeyedNetGroup } ;
2016-04-18 21:58:19 +02:00
vEvictionCandidates . push_back ( candidate ) ;
2015-08-13 11:58:58 +02:00
}
}
2015-08-23 00:15:39 +02:00
if ( vEvictionCandidates . empty ( ) ) return false ;
2015-08-13 11:58:58 +02:00
// Protect connections with certain characteristics
2015-08-21 01:47:49 +02:00
// Deterministically select 4 peers to protect by netgroup.
2016-05-23 09:21:05 +02:00
// An attacker cannot predict which netgroups will be protected
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , CompareNetGroupKeyed ) ;
2015-08-13 11:58:58 +02:00
vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std : : min ( 4 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ;
2015-08-23 00:15:39 +02:00
if ( vEvictionCandidates . empty ( ) ) return false ;
2016-04-29 16:23:51 +02:00
// Protect the 8 nodes with the lowest minimum ping time.
2015-08-21 01:47:49 +02:00
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
2015-08-13 11:58:58 +02:00
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , ReverseCompareNodeMinPingTime ) ;
vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std : : min ( 8 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ;
2015-08-23 00:15:39 +02:00
if ( vEvictionCandidates . empty ( ) ) return false ;
2016-05-22 07:55:15 +02:00
// Protect 4 nodes that most recently sent us transactions.
// An attacker cannot manipulate this metric without performing useful work.
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , CompareNodeTXTime ) ;
vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std : : min ( 4 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ;
if ( vEvictionCandidates . empty ( ) ) return false ;
// Protect 4 nodes that most recently sent us blocks.
// An attacker cannot manipulate this metric without performing useful work.
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , CompareNodeBlockTime ) ;
vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std : : min ( 4 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ;
if ( vEvictionCandidates . empty ( ) ) return false ;
2015-08-26 01:31:13 +02:00
// Protect the half of the remaining nodes which have been connected the longest.
2016-04-29 16:23:51 +02:00
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
2015-08-13 11:58:58 +02:00
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , ReverseCompareNodeTimeConnected ) ;
2015-08-23 00:15:39 +02:00
vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - static_cast < int > ( vEvictionCandidates . size ( ) / 2 ) , vEvictionCandidates . end ( ) ) ;
2015-08-13 11:58:58 +02:00
2015-08-23 00:15:39 +02:00
if ( vEvictionCandidates . empty ( ) ) return false ;
2015-08-13 11:58:58 +02:00
2015-11-23 04:48:54 +01:00
// Identify the network group with the most connections and youngest member.
// (vEvictionCandidates is already sorted by reverse connect time)
2016-05-25 15:38:32 +02:00
uint64_t naMostConnections ;
2015-08-13 11:58:58 +02:00
unsigned int nMostConnections = 0 ;
2015-11-23 04:48:54 +01:00
int64_t nMostConnectionsTime = 0 ;
2016-06-10 16:09:06 +02:00
std : : map < uint64_t , std : : vector < NodeEvictionCandidate > > mapNetGroupNodes ;
2016-04-18 21:58:19 +02:00
BOOST_FOREACH ( const NodeEvictionCandidate & node , vEvictionCandidates ) {
2016-06-10 16:09:06 +02:00
mapNetGroupNodes [ node . nKeyedNetGroup ] . push_back ( node ) ;
int64_t grouptime = mapNetGroupNodes [ node . nKeyedNetGroup ] [ 0 ] . nTimeConnected ;
size_t groupsize = mapNetGroupNodes [ node . nKeyedNetGroup ] . size ( ) ;
2015-08-13 11:58:58 +02:00
2015-11-23 04:48:54 +01:00
if ( groupsize > nMostConnections | | ( groupsize = = nMostConnections & & grouptime > nMostConnectionsTime ) ) {
nMostConnections = groupsize ;
nMostConnectionsTime = grouptime ;
2016-05-25 15:38:32 +02:00
naMostConnections = node . nKeyedNetGroup ;
2015-08-13 11:58:58 +02:00
}
}
2015-08-26 02:06:15 +02:00
// Reduce to the network group with the most connections
2016-06-10 16:09:06 +02:00
vEvictionCandidates = std : : move ( mapNetGroupNodes [ naMostConnections ] ) ;
2015-08-13 11:58:58 +02:00
2015-11-23 04:48:54 +01:00
// Disconnect from the network group with the most connections
2016-04-18 21:58:19 +02:00
NodeId evicted = vEvictionCandidates . front ( ) . id ;
LOCK ( cs_vNodes ) ;
for ( std : : vector < CNode * > : : const_iterator it ( vNodes . begin ( ) ) ; it ! = vNodes . end ( ) ; + + it ) {
if ( ( * it ) - > GetId ( ) = = evicted ) {
( * it ) - > fDisconnect = true ;
return true ;
}
}
return false ;
2015-08-13 11:58:58 +02:00
}
2015-08-13 11:00:10 +02: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 ;
2016-06-17 06:10:07 +02:00
int nMaxInbound = nMaxConnections - ( MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS ) ;
assert ( nMaxInbound > 0 ) ;
2015-08-13 11:00:10 +02:00
if ( hSocket ! = INVALID_SOCKET )
if ( ! addr . SetSockAddr ( ( const struct sockaddr * ) & sockaddr ) )
LogPrintf ( " Warning: Unknown socket family \n " ) ;
bool whitelisted = hListenSocket . whitelisted | | CNode : : IsWhitelistedRange ( addr ) ;
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( pnode - > fInbound )
nInbound + + ;
}
if ( hSocket = = INVALID_SOCKET )
{
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK )
LogPrintf ( " socket error accept failed: %s \n " , NetworkErrorString ( nErr ) ) ;
2015-08-13 11:16:46 +02:00
return ;
2015-08-13 11:00:10 +02:00
}
2015-08-13 11:16:46 +02:00
if ( ! IsSelectableSocket ( hSocket ) )
2015-08-13 11:00:10 +02:00
{
LogPrintf ( " connection from %s dropped: non-selectable socket \n " , addr . ToString ( ) ) ;
CloseSocket ( hSocket ) ;
2015-08-13 11:16:46 +02:00
return ;
2015-08-13 11:00:10 +02:00
}
2015-08-13 11:16:46 +02:00
2015-10-22 01:52:29 +02: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
2015-08-13 11:19:17 +02:00
if ( CNode : : IsBanned ( addr ) & & ! whitelisted )
2015-08-13 11:00:10 +02:00
{
2015-08-13 11:19:17 +02:00
LogPrintf ( " connection from %s dropped (banned) \n " , addr . ToString ( ) ) ;
2015-08-13 11:00:10 +02:00
CloseSocket ( hSocket ) ;
2015-08-13 11:16:46 +02:00
return ;
2015-08-13 11:00:10 +02:00
}
2015-08-13 11:16:46 +02:00
2015-08-13 11:19:17 +02:00
if ( nInbound > = nMaxInbound )
2015-08-13 11:00:10 +02:00
{
2016-05-22 07:55:15 +02:00
if ( ! AttemptToEvictConnection ( ) ) {
2015-08-13 11:58:58 +02:00
// No connection to evict, disconnect the new connection
LogPrint ( " net " , " failed to find an eviction candidate - connection dropped (full) \n " ) ;
CloseSocket ( hSocket ) ;
return ;
}
2015-08-13 11:00:10 +02:00
}
2015-08-13 11:16:46 +02:00
CNode * pnode = new CNode ( hSocket , addr , " " , true ) ;
pnode - > AddRef ( ) ;
pnode - > fWhitelisted = whitelisted ;
2015-08-13 11:00:10 +02:00
2015-08-13 11:16:46 +02:00
LogPrint ( " net " , " connection from %s accepted \n " , addr . ToString ( ) ) ;
{
LOCK ( cs_vNodes ) ;
vNodes . push_back ( pnode ) ;
2015-08-13 11:00:10 +02:00
}
}
2013-03-07 04:31:26 +01:00
void ThreadSocketHandler ( )
2010-08-29 18:58:15 +02:00
{
2012-04-22 20:01:25 +02:00
unsigned int nPrevNodeCount = 0 ;
2013-07-31 06:06:44 +02:00
while ( true )
2010-08-29 18:58:15 +02:00
{
//
// Disconnect nodes
//
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2010-08-29 18:58:15 +02:00
// Disconnect unused nodes
2016-04-16 01:53:45 +02:00
std : : vector < CNode * > vNodesCopy = vNodes ;
2011-05-15 09:11:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
2010-08-29 18:58:15 +02: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 18:58:15 +02: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 18:58:15 +02: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 ) ;
}
}
2013-07-25 02:25:25 +02:00
}
{
2010-08-29 18:58:15 +02:00
// Delete disconnected nodes
2016-04-16 01:53:45 +02:00
std : : list < CNode * > vNodesDisconnectedCopy = vNodesDisconnected ;
2011-05-15 09:11:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodesDisconnectedCopy )
2010-08-29 18:58:15 +02: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-16 01:41:12 +01: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 18:58:15 +02:00
if ( fDelete )
{
vNodesDisconnected . remove ( pnode ) ;
delete pnode ;
}
}
}
}
2013-08-22 18:09:32 +02:00
if ( vNodes . size ( ) ! = nPrevNodeCount ) {
2010-08-29 18:58:15 +02:00
nPrevNodeCount = vNodes . size ( ) ;
2013-08-22 18:09:32 +02:00
uiInterface . NotifyNumConnectionsChanged ( nPrevNodeCount ) ;
2010-08-29 18:58:15 +02: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 22:01:28 +02:00
bool have_fds = false ;
2010-12-22 14:08:00 +01:00
2014-06-21 13:34:36 +02:00
BOOST_FOREACH ( const ListenSocket & hListenSocket , vhListenSocket ) {
FD_SET ( hListenSocket . socket , & fdsetRecv ) ;
2016-04-16 01:53:45 +02:00
hSocketMax = std : : max ( hSocketMax , hListenSocket . socket ) ;
2012-09-05 22:01:28 +02:00
have_fds = true ;
2012-05-11 15:28:59 +02:00
}
2014-06-24 09:09:45 +02:00
2010-08-29 18:58:15 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2011-05-15 09:11:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodes )
2010-08-29 18:58:15 +02:00
{
2011-06-24 20:09:24 +02:00
if ( pnode - > hSocket = = INVALID_SOCKET )
2010-08-29 18:58:15 +02:00
continue ;
2013-04-30 18:42:01 +02:00
FD_SET ( pnode - > hSocket , & fdsetError ) ;
2016-04-16 01:53:45 +02: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-16 00:20:26 +01: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 18:58:15 +02:00
}
}
2012-09-05 22:01:28 +02:00
int nSelect = select ( have_fds ? hSocketMax + 1 : 0 ,
& fdsetRecv , & fdsetSend , & fdsetError , & timeout ) ;
2013-03-07 04:31:26 +01:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 18:58:15 +02:00
if ( nSelect = = SOCKET_ERROR )
{
2012-09-05 22:01:28 +02:00
if ( have_fds )
2011-06-07 00:48:37 +02:00
{
2012-09-05 22:01:28 +02:00
int nErr = WSAGetLastError ( ) ;
2014-05-08 14:15:19 +02:00
LogPrintf ( " socket select error %s \n " , NetworkErrorString ( nErr ) ) ;
2012-04-15 22:52:09 +02:00
for ( unsigned int i = 0 ; i < = hSocketMax ; i + + )
2011-06-07 00:48:37 +02:00
FD_SET ( i , & fdsetRecv ) ;
}
2010-08-29 18:58:15 +02:00
FD_ZERO ( & fdsetSend ) ;
FD_ZERO ( & fdsetError ) ;
2013-03-07 20:25:21 +01:00
MilliSleep ( timeout . tv_usec / 1000 ) ;
2010-08-29 18:58:15 +02:00
}
//
// Accept new connections
//
2014-06-21 13:34:36 +02:00
BOOST_FOREACH ( const ListenSocket & hListenSocket , vhListenSocket )
2010-08-29 18:58:15 +02:00
{
2014-06-21 13:34:36 +02:00
if ( hListenSocket . socket ! = INVALID_SOCKET & & FD_ISSET ( hListenSocket . socket , & fdsetRecv ) )
2012-04-06 18:39:12 +02:00
{
2015-08-13 11:00:10 +02:00
AcceptConnection ( hListenSocket ) ;
2010-08-29 18:58:15 +02:00
}
}
//
// Service each socket
//
2016-04-16 01:53:45 +02:00
std : : vector < CNode * > vNodesCopy ;
2010-08-29 18:58:15 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2010-08-29 18:58:15 +02:00
vNodesCopy = vNodes ;
2011-05-15 09:11:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
2010-08-29 18:58:15 +02:00
pnode - > AddRef ( ) ;
}
2011-05-15 09:11:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
2010-08-29 18:58:15 +02:00
{
2013-03-07 04:31:26 +01:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 18:58:15 +02:00
//
// Receive
//
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
if ( FD_ISSET ( pnode - > hSocket , & fdsetRecv ) | | FD_ISSET ( pnode - > hSocket , & fdsetError ) )
{
2012-11-16 01:41:12 +01:00
TRY_LOCK ( pnode - > cs_vRecvMsg , lockRecv ) ;
2012-04-06 18:39:12 +02:00
if ( lockRecv )
2010-08-29 18:58:15 +02:00
{
2013-04-30 18:42:01 +02:00
{
2011-02-16 19:18:11 +01: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 18:58:15 +02:00
{
2012-11-16 01:41:12 +01:00
if ( ! pnode - > ReceiveMsgBytes ( pchBuf , nBytes ) )
pnode - > CloseSocketDisconnect ( ) ;
2011-02-16 19:18:11 +01:00
pnode - > nLastRecv = GetTime ( ) ;
2013-04-07 19:31:13 +02:00
pnode - > nRecvBytes + = nBytes ;
2013-08-22 18:09:32 +02:00
pnode - > RecordBytesRecv ( nBytes ) ;
2011-02-16 19:18:11 +01:00
}
else if ( nBytes = = 0 )
{
// socket closed gracefully
2010-08-29 18:58:15 +02:00
if ( ! pnode - > fDisconnect )
2013-09-18 12:38:08 +02:00
LogPrint ( " net " , " socket closed \n " ) ;
2010-08-29 18:58:15 +02:00
pnode - > CloseSocketDisconnect ( ) ;
}
2011-02-16 19:18:11 +01:00
else if ( nBytes < 0 )
{
// error
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS )
{
if ( ! pnode - > fDisconnect )
2014-05-08 14:15:19 +02:00
LogPrintf ( " socket recv error %s \n " , NetworkErrorString ( nErr ) ) ;
2011-02-16 19:18:11 +01:00
pnode - > CloseSocketDisconnect ( ) ;
}
}
2010-08-29 18:58:15 +02: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-16 00:04:52 +01:00
SocketSendData ( pnode ) ;
2010-08-29 18:58:15 +02:00
}
//
// Inactivity checking
//
2013-10-15 00:34:20 +02:00
int64_t nTime = GetTime ( ) ;
if ( nTime - pnode - > nTimeConnected > 60 )
2010-08-29 18:58:15 +02:00
{
if ( pnode - > nLastRecv = = 0 | | pnode - > nLastSend = = 0 )
{
2014-02-27 02:55:04 +01: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 18:58:15 +02:00
pnode - > fDisconnect = true ;
}
2013-10-15 00:34:20 +02:00
else if ( nTime - pnode - > nLastSend > TIMEOUT_INTERVAL )
2010-08-29 18:58:15 +02:00
{
2013-10-15 00:34:20 +02:00
LogPrintf ( " socket sending timeout: %is \n " , nTime - pnode - > nLastSend ) ;
2010-08-29 18:58:15 +02: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 18:58:15 +02:00
{
2013-10-15 00:34:20 +02:00
LogPrintf ( " socket receive timeout: %is \n " , nTime - pnode - > nLastRecv ) ;
pnode - > fDisconnect = true ;
}
else if ( pnode - > nPingNonceSent & & pnode - > nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros ( ) )
{
LogPrintf ( " ping timeout: %fs \n " , 0.000001 * ( GetTimeMicros ( ) - pnode - > nPingUsecStart ) ) ;
2010-08-29 18:58:15 +02:00
pnode - > fDisconnect = true ;
}
}
}
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2011-05-15 09:11:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
2010-08-29 18:58:15 +02:00
pnode - > Release ( ) ;
}
}
}
2011-03-26 13:01:27 +01:00
# ifdef USE_UPNP
2013-03-07 04:31:26 +01: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 17:52:50 +01:00
# ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 ) ;
2015-08-23 22:53:49 +02:00
# elif MINIUPNPC_API_VERSION < 14
2011-12-10 17:52:50 +01: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 22:53:49 +02:00
# else
/* miniupnpc 1.9.20150730 */
int error = 0 ;
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 , 0 , 2 , & error ) ;
2011-12-10 17:52:50 +01:00
# endif
2011-03-26 13:01:27 +01:00
struct UPNPUrls urls ;
struct IGDdatas data ;
int r ;
2011-04-16 20:35:45 +02: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-10 04:41:42 +01:00
char externalIPAddress [ 40 ] ;
r = UPNP_GetExternalIPAddress ( urls . controlURL , data . first . servicetype , externalIPAddress ) ;
if ( r ! = UPNPCOMMAND_SUCCESS )
2013-09-18 12:38:08 +02:00
LogPrintf ( " UPnP: GetExternalIPAddress() returned %d \n " , r ) ;
2012-02-10 04:41:42 +01:00
else
{
if ( externalIPAddress [ 0 ] )
{
2016-05-31 19:05:52 +02:00
CNetAddr resolved ;
if ( LookupHost ( externalIPAddress , resolved , false ) ) {
LogPrintf ( " UPnP: ExternalIPAddress = %s \n " , resolved . ToString ( ) . c_str ( ) ) ;
AddLocal ( resolved , LOCAL_UPNP ) ;
}
2012-02-10 04:41:42 +01:00
}
else
2013-09-18 12:38:08 +02:00
LogPrintf ( " UPnP: GetExternalIPAddress failed. \n " ) ;
2012-02-10 04:41:42 +01:00
}
}
2016-04-16 01:53:45 +02:00
std : : string strDesc = " Bitcoin " + FormatFullVersion ( ) ;
2011-08-12 00:20:07 +02:00
2013-03-07 04:31:26 +01:00
try {
2013-07-31 06:06:44 +02:00
while ( true ) {
2012-01-31 23:36:25 +01: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 23:36:25 +01: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 23:36:25 +01:00
# endif
if ( r ! = UPNPCOMMAND_SUCCESS )
2013-09-18 12:38:08 +02:00
LogPrintf ( " AddPortMapping(%s, %s, %s) failed with code %d (%s) \n " ,
2014-01-16 16:15:27 +01:00
port , port , lanaddr , r , strupnperror ( r ) ) ;
2012-01-31 23:36:25 +01:00
else
2015-12-30 04:42:27 +01:00
LogPrintf ( " UPnP Port Mapping successful. \n " ) ;
2013-03-07 04:31:26 +01:00
MilliSleep ( 20 * 60 * 1000 ) ; // Refresh every 20 minutes
2012-01-31 23:36:25 +01:00
}
2013-03-07 04:31:26 +01:00
}
2014-12-07 13:29:06 +01:00
catch ( const boost : : thread_interrupted & )
2013-03-07 04:31:26 +01:00
{
r = UPNP_DeletePortMapping ( urls . controlURL , data . first . servicetype , port . c_str ( ) , " TCP " , 0 ) ;
2015-01-08 11:44:25 +01:00
LogPrintf ( " UPNP_DeletePortMapping() returned: %d \n " , r ) ;
2013-03-07 04:31:26 +01:00
freeUPNPDevlist ( devlist ) ; devlist = 0 ;
FreeUPNPUrls ( & urls ) ;
throw ;
2011-03-26 13:01:27 +01:00
}
} else {
2013-09-18 12:38:08 +02:00
LogPrintf ( " No valid UPnP IGDs found \n " ) ;
2011-03-26 13:01:27 +01:00
freeUPNPDevlist ( devlist ) ; devlist = 0 ;
2011-04-16 20:35:45 +02:00
if ( r ! = 0 )
FreeUPNPUrls ( & urls ) ;
2011-03-26 13:01:27 +01:00
}
}
2013-03-07 04:31:26 +01:00
void MapPort ( bool fUseUPnP )
2011-03-26 13:01:27 +01:00
{
2013-03-07 04:31:26 +01:00
static boost : : thread * upnp_thread = NULL ;
if ( fUseUPnP )
2011-03-26 13:01:27 +01:00
{
2013-03-07 04:31:26 +01:00
if ( upnp_thread ) {
upnp_thread - > interrupt ( ) ;
upnp_thread - > join ( ) ;
delete upnp_thread ;
}
2013-04-23 11:36:54 +02:00
upnp_thread = new boost : : thread ( boost : : bind ( & TraceThread < void ( * ) ( ) > , " upnp " , & ThreadMapPort ) ) ;
2013-03-07 04:31:26 +01: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-07 04:31:26 +01:00
2011-08-09 18:38:17 +02:00
# else
2013-03-07 04:31:26 +01:00
void MapPort ( bool )
2011-08-09 18:38:17 +02:00
{
// Intentionally left blank.
}
2011-03-26 13:01:27 +01:00
# endif
2016-06-15 19:31:28 +02:00
static std : : string GetDNSHost ( const CDNSSeedData & data , ServiceFlags * requiredServiceBits )
{
//use default host for non-filter-capable seeds or if we use the default service bits (NODE_NETWORK)
if ( ! data . supportsServiceBitsFiltering | | * requiredServiceBits = = NODE_NETWORK ) {
* requiredServiceBits = NODE_NETWORK ;
return data . host ;
}
return strprintf ( " x%x.%s " , * requiredServiceBits , data . host ) ;
}
2013-03-07 04:31:26 +01:00
void ThreadDNSAddressSeed ( )
2011-11-21 18:25:00 +01:00
{
2014-07-29 17:04:46 +02:00
// goal: only query DNS seeds if address need is acute
if ( ( addrman . size ( ) > 0 ) & &
2015-06-27 21:21:41 +02:00
( ! GetBoolArg ( " -forcednsseed " , DEFAULT_FORCEDNSSEED ) ) ) {
2014-07-29 17:04:46 +02:00
MilliSleep ( 11 * 1000 ) ;
LOCK ( cs_vNodes ) ;
if ( vNodes . size ( ) > = 2 ) {
LogPrintf ( " P2P peers available. Skipped DNS seeding. \n " ) ;
return ;
}
}
2016-04-16 01:53:45 +02:00
const std : : vector < CDNSSeedData > & vSeeds = Params ( ) . DNSSeeds ( ) ;
2011-03-09 04:40:50 +01:00
int found = 0 ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " Loading addresses from DNS seeds (could take a while) \n " ) ;
2013-01-30 05:13:17 +01:00
2013-05-07 15:16:25 +02:00
BOOST_FOREACH ( const CDNSSeedData & seed , vSeeds ) {
2013-01-30 05:13:17 +01:00
if ( HaveNameProxy ( ) ) {
2013-05-07 15:16:25 +02:00
AddOneShot ( seed . host ) ;
2013-01-30 05:13:17 +01:00
} else {
2016-04-16 01:53:45 +02:00
std : : vector < CNetAddr > vIPs ;
std : : vector < CAddress > vAdd ;
2016-06-08 19:12:22 +02:00
ServiceFlags requiredServiceBits = nRelevantServices ;
2016-06-15 19:31:28 +02:00
if ( LookupHost ( GetDNSHost ( seed , & requiredServiceBits ) . c_str ( ) , vIPs , 0 , true ) )
2013-01-30 05:13:17 +01:00
{
2015-05-31 15:36:44 +02:00
BOOST_FOREACH ( const CNetAddr & ip , vIPs )
2011-05-02 15:34:42 +02:00
{
2013-01-30 05:13:17 +01:00
int nOneDay = 24 * 3600 ;
2016-05-21 23:55:22 +02:00
CAddress addr = CAddress ( CService ( ip , Params ( ) . GetDefaultPort ( ) ) , requiredServiceBits ) ;
2013-01-30 05:13:17 +01: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-09 04:40:50 +01:00
}
2016-04-13 02:38:06 +02:00
// TODO: The seed name resolve may fail, yielding an IP of [::], which results in
// addrman assigning the same source to results from different seeds.
// This should switch to a hard-coded stable dummy IP for each seed name, so that the
// resolve is not required at all.
if ( ! vIPs . empty ( ) ) {
CService seedSource ;
Lookup ( seed . name . c_str ( ) , seedSource , 0 , true ) ;
addrman . Add ( vAdd , seedSource ) ;
}
2011-03-09 04:40:50 +01:00
}
}
2013-09-18 12:38:08 +02:00
LogPrintf ( " %d addresses found from DNS seeds \n " , found ) ;
2011-03-09 04:40:50 +01:00
}
2010-08-29 18:58:15 +02:00
2011-11-21 18:25:00 +01:00
2012-01-04 23:39:45 +01:00
void DumpAddresses ( )
{
2013-04-13 07:13:08 +02:00
int64_t nStart = GetTimeMillis ( ) ;
2012-05-17 04:11:19 +02:00
2012-01-04 23:39:45 +01:00
CAddrDB adb ;
2012-05-17 04:11:19 +02:00
adb . Write ( addrman ) ;
2014-02-24 09:08:56 +01:00
LogPrint ( " net " , " Flushed %d addresses to peers.dat %dms \n " ,
2012-05-17 04:11:19 +02:00
addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
2012-01-04 23:39:45 +01:00
}
2010-08-29 18:58:15 +02:00
2015-06-19 15:27:37 +02:00
void DumpData ( )
{
DumpAddresses ( ) ;
2015-07-03 10:46:08 +02:00
DumpBanlist ( ) ;
2015-06-19 15:27:37 +02:00
}
2012-04-24 02:15:00 +02:00
void static ProcessOneShot ( )
{
2016-04-16 01:53:45 +02: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 ) {
2015-04-19 21:34:43 +02:00
if ( ! OpenNetworkConnection ( addr , false , & grant , strDest . c_str ( ) , true ) )
2012-05-10 18:44:07 +02:00
AddOneShot ( strDest ) ;
}
2012-04-24 02:15:00 +02:00
}
2013-03-07 04:31:26 +01:00
void ThreadOpenConnections ( )
2010-08-29 18:58:15 +02:00
{
// Connect to specific addresses
2012-08-21 17:32:04 +02:00
if ( mapArgs . count ( " -connect " ) & & mapMultiArgs [ " -connect " ] . size ( ) > 0 )
2010-08-29 18:58:15 +02:00
{
2013-04-13 07:13:08 +02:00
for ( int64_t nLoop = 0 ; ; nLoop + + )
2010-08-29 18:58:15 +02:00
{
2012-04-24 02:15:00 +02:00
ProcessOneShot ( ) ;
2015-05-31 15:36:44 +02:00
BOOST_FOREACH ( const std : : string & strAddr , mapMultiArgs [ " -connect " ] )
2010-08-29 18:58:15 +02:00
{
2016-06-08 19:12:22 +02:00
CAddress addr ( CService ( ) , NODE_NONE ) ;
2015-04-19 21:34:43 +02:00
OpenNetworkConnection ( addr , false , NULL , strAddr . c_str ( ) ) ;
2010-08-29 18:58:15 +02:00
for ( int i = 0 ; i < 10 & & i < nLoop ; i + + )
{
2013-03-07 20:25:21 +01:00
MilliSleep ( 500 ) ;
2010-08-29 18:58:15 +02:00
}
}
2013-03-07 20:25:21 +01:00
MilliSleep ( 500 ) ;
2010-08-29 18:58:15 +02:00
}
}
// Initiate network connections
2013-04-13 07:13:08 +02:00
int64_t nStart = GetTime ( ) ;
2016-06-17 06:10:07 +02:00
// Minimum time before next feeler connection (in microseconds).
int64_t nNextFeeler = PoissonNextSend ( nStart * 1000 * 1000 , FEELER_INTERVAL ) ;
2013-07-31 06:06:44 +02:00
while ( true )
2010-08-29 18:58:15 +02:00
{
2012-04-24 02:15:00 +02:00
ProcessOneShot ( ) ;
2013-03-07 20:25:21 +01:00
MilliSleep ( 500 ) ;
2012-02-15 21:17:15 +01:00
2012-05-10 18:44:07 +02:00
CSemaphoreGrant grant ( * semOutbound ) ;
2013-03-07 04:31:26 +01:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 18:58:15 +02:00
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 ) {
2013-09-18 12:38:08 +02:00
LogPrintf ( " Adding fixed seed nodes as DNS doesn't seem to be available. \n " ) ;
2016-05-31 19:05:52 +02:00
CNetAddr local ;
LookupHost ( " 127.0.0.1 " , local , false ) ;
addrman . Add ( convertSeed6 ( Params ( ) . FixedSeeds ( ) ) , local ) ;
2013-05-07 15:16:25 +02:00
done = true ;
2010-08-29 18:58:15 +02:00
}
}
//
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect ;
2012-07-02 02:23:26 +02:00
// Only connect out to one peer per network group (/16 for IPv4).
2010-08-29 18:58:15 +02:00
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
2012-05-10 18:44:07 +02:00
int nOutbound = 0 ;
2016-04-16 01:53:45 +02:00
std : : set < std : : vector < unsigned char > > setConnected ;
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_vNodes ) ;
2012-05-10 18:44:07 +02:00
BOOST_FOREACH ( CNode * pnode , vNodes ) {
2012-07-02 02:23:26 +02:00
if ( ! pnode - > fInbound ) {
setConnected . insert ( pnode - > addr . GetGroup ( ) ) ;
2012-05-10 18:44:07 +02:00
nOutbound + + ;
2012-07-02 02:23:26 +02:00
}
2012-05-10 18:44:07 +02:00
}
2012-04-06 18:39:12 +02:00
}
2016-06-17 06:10:07 +02:00
assert ( nOutbound < = ( MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS ) ) ;
2010-08-29 18:58:15 +02:00
2016-06-17 06:10:07 +02:00
// Feeler Connections
//
// Design goals:
// * Increase the number of connectable addresses in the tried table.
//
// Method:
// * Choose a random address from new and attempt to connect to it if we can connect
// successfully it is added to tried.
// * Start attempting feeler connections only after node finishes making outbound
// connections.
// * Only make a feeler connection once every few minutes.
//
bool fFeeler = false ;
if ( nOutbound > = MAX_OUTBOUND_CONNECTIONS ) {
int64_t nTime = GetTimeMicros ( ) ; // The current time right now (in microseconds).
if ( nTime > nNextFeeler ) {
nNextFeeler = PoissonNextSend ( nTime , FEELER_INTERVAL ) ;
fFeeler = true ;
} else {
continue ;
}
}
2011-10-04 05:41:47 +02:00
2016-06-17 06:10:07 +02:00
int64_t nANow = GetAdjustedTime ( ) ;
2012-01-04 23:39:45 +01:00
int nTries = 0 ;
2013-07-31 06:06:44 +02:00
while ( true )
2010-08-29 18:58:15 +02:00
{
2016-06-17 06:10:07 +02:00
CAddrInfo addr = addrman . Select ( fFeeler ) ;
2010-08-29 18:58:15 +02: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 18:58:15 +02: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 18:58:15 +02:00
2012-05-04 16:46:22 +02:00
if ( IsLimited ( addr ) )
continue ;
2016-03-26 13:31:25 +01:00
// only connect to full nodes
2016-06-13 16:01:21 +02:00
if ( ( addr . nServices & REQUIRED_SERVICES ) ! = REQUIRED_SERVICES )
2016-03-26 13:31:25 +01:00
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 ;
2016-08-13 19:21:13 +02:00
// only consider nodes missing relevant services after 40 failed attempts
2015-11-17 00:20:49 +01:00
if ( ( addr . nServices & nRelevantServices ) ! = nRelevantServices & & nTries < 40 )
continue ;
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 ;
addrConnect = addr ;
break ;
2010-08-29 18:58:15 +02:00
}
2016-06-17 06:10:07 +02:00
if ( addrConnect . IsValid ( ) ) {
if ( fFeeler ) {
// Add small amount of random noise before connection to avoid synchronization.
int randsleep = GetRandInt ( FEELER_SLEEP_WINDOW * 1000 ) ;
MilliSleep ( randsleep ) ;
LogPrint ( " net " , " Making feeler connection to %s \n " , addrConnect . ToString ( ) ) ;
}
OpenNetworkConnection ( addrConnect , ( int ) setConnected . size ( ) > = std : : min ( nMaxConnections - 1 , 2 ) , & grant , NULL , false , fFeeler ) ;
}
2010-08-29 18:58:15 +02:00
}
}
2016-05-28 15:32:30 +02:00
std : : vector < AddedNodeInfo > GetAddedNodeInfo ( )
2011-12-17 01:48:03 +01:00
{
2016-05-28 15:32:30 +02:00
std : : vector < AddedNodeInfo > ret ;
std : : list < std : : string > lAddresses ( 0 ) ;
2012-07-02 19:55:16 +02:00
{
LOCK ( cs_vAddedNodes ) ;
2016-05-28 15:32:30 +02:00
ret . reserve ( vAddedNodes . size ( ) ) ;
BOOST_FOREACH ( const std : : string & strAddNode , vAddedNodes )
lAddresses . push_back ( strAddNode ) ;
2012-07-02 19:55:16 +02:00
}
2011-12-17 01:48:03 +01:00
2016-05-28 15:32:30 +02:00
// Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService
std : : map < CService , bool > mapConnected ;
std : : map < std : : string , std : : pair < bool , CService > > mapConnectedByName ;
{
LOCK ( cs_vNodes ) ;
for ( const CNode * pnode : vNodes ) {
if ( pnode - > addr . IsValid ( ) ) {
mapConnected [ pnode - > addr ] = pnode - > fInbound ;
2012-07-02 19:55:16 +02:00
}
2016-05-28 15:32:30 +02:00
if ( ! pnode - > addrName . empty ( ) ) {
mapConnectedByName [ pnode - > addrName ] = std : : make_pair ( pnode - > fInbound , static_cast < const CService & > ( pnode - > addr ) ) ;
2012-04-19 17:38:03 +02:00
}
}
}
2016-05-28 15:32:30 +02:00
BOOST_FOREACH ( const std : : string & strAddNode , lAddresses ) {
2016-08-04 22:37:49 +02:00
CService service ( LookupNumeric ( strAddNode . c_str ( ) , Params ( ) . GetDefaultPort ( ) ) ) ;
2016-05-28 15:32:30 +02:00
if ( service . IsValid ( ) ) {
// strAddNode is an IP:port
auto it = mapConnected . find ( service ) ;
if ( it ! = mapConnected . end ( ) ) {
ret . push_back ( AddedNodeInfo { strAddNode , service , true , it - > second } ) ;
} else {
ret . push_back ( AddedNodeInfo { strAddNode , CService ( ) , false , false } ) ;
}
} else {
// strAddNode is a name
auto it = mapConnectedByName . find ( strAddNode ) ;
if ( it ! = mapConnectedByName . end ( ) ) {
ret . push_back ( AddedNodeInfo { strAddNode , it - > second . second , true , it - > second . first } ) ;
} else {
ret . push_back ( AddedNodeInfo { strAddNode , CService ( ) , false , false } ) ;
2012-04-19 17:38:03 +02:00
}
}
}
2016-05-28 15:32:30 +02:00
return ret ;
}
void ThreadOpenAddedConnections ( )
{
{
LOCK ( cs_vAddedNodes ) ;
vAddedNodes = mapMultiArgs [ " -addnode " ] ;
}
2012-07-02 21:11:57 +02:00
for ( unsigned int i = 0 ; true ; i + + )
2011-12-17 01:48:03 +01:00
{
2016-05-28 15:32:30 +02:00
std : : vector < AddedNodeInfo > vInfo = GetAddedNodeInfo ( ) ;
for ( const AddedNodeInfo & info : vInfo ) {
if ( ! info . fConnected ) {
CSemaphoreGrant grant ( * semOutbound ) ;
// If strAddedNode is an IP/port, decode it immediately, so
// OpenNetworkConnection can detect existing connections to that IP/port.
2016-08-04 22:37:49 +02:00
CService service ( LookupNumeric ( info . strAddedNode . c_str ( ) , Params ( ) . GetDefaultPort ( ) ) ) ;
2016-05-28 15:32:30 +02:00
OpenNetworkConnection ( CAddress ( service , NODE_NONE ) , false , & grant , info . strAddedNode . c_str ( ) , false ) ;
MilliSleep ( 500 ) ;
}
2012-07-02 19:55:16 +02:00
}
2013-03-07 20:25:21 +01:00
MilliSleep ( 120000 ) ; // Retry every 2 minutes
2011-12-17 01:48:03 +01:00
}
}
2012-07-26 02:48:39 +02:00
// if successful, this moves the passed grant to the constructed node
2016-06-17 06:10:07 +02:00
bool OpenNetworkConnection ( const CAddress & addrConnect , bool fCountFailure , CSemaphoreGrant * grantOutbound , const char * pszDest , bool fOneShot , bool fFeeler )
2010-08-29 18:58:15 +02:00
{
//
// Initiate outbound network connection
//
2013-03-07 04:31:26 +01: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 18:58:15 +02:00
return false ;
2015-04-19 21:34:43 +02:00
CNode * pnode = ConnectNode ( addrConnect , pszDest , fCountFailure ) ;
2013-03-07 04:31:26 +01:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 18:58:15 +02:00
if ( ! pnode )
return false ;
2012-05-10 18:44:07 +02:00
if ( grantOutbound )
grantOutbound - > MoveTo ( pnode - > grantOutbound ) ;
2010-08-29 18:58:15 +02:00
pnode - > fNetworkNode = true ;
2012-04-24 02:15:00 +02:00
if ( fOneShot )
pnode - > fOneShot = true ;
2016-06-17 06:10:07 +02:00
if ( fFeeler )
pnode - > fFeeler = true ;
2010-08-29 18:58:15 +02:00
return true ;
}
2013-03-07 04:31:26 +01:00
void ThreadMessageHandler ( )
2010-08-29 18:58:15 +02:00
{
2015-04-05 11:35:37 +02:00
boost : : mutex condition_mutex ;
boost : : unique_lock < boost : : mutex > lock ( condition_mutex ) ;
2015-05-31 15:44:22 +02:00
2013-03-07 04:31:26 +01:00
while ( true )
2010-08-29 18:58:15 +02:00
{
2016-04-16 01:53:45 +02:00
std : : vector < CNode * > vNodesCopy ;
2010-08-29 18:58:15 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2010-08-29 18:58:15 +02:00
vNodesCopy = vNodes ;
2013-04-05 00:43:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodesCopy ) {
2010-08-29 18:58:15 +02:00
pnode - > AddRef ( ) ;
2013-04-05 00:43:04 +02:00
}
2010-08-29 18:58:15 +02:00
}
2013-10-28 21:20:21 +01:00
bool fSleep = true ;
2013-11-15 12:24:34 +01:00
2011-05-15 09:11:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
2010-08-29 18:58:15 +02:00
{
2013-03-01 01:41:28 +01:00
if ( pnode - > fDisconnect )
continue ;
2010-08-29 18:58:15 +02:00
// Receive messages
2012-04-06 18:39:12 +02:00
{
2012-11-16 01:41:12 +01:00
TRY_LOCK ( pnode - > cs_vRecvMsg , lockRecv ) ;
2012-04-06 18:39:12 +02:00
if ( lockRecv )
2013-10-28 21:20:21 +01:00
{
2016-04-16 02:03:18 +02:00
if ( ! GetNodeSignals ( ) . ProcessMessages ( pnode ) )
2012-11-16 01:41:12 +01:00
pnode - > CloseSocketDisconnect ( ) ;
2013-11-15 12:24:34 +01:00
2013-10-28 21:20:21 +01: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-07 04:31:26 +01:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 18:58:15 +02:00
// Send messages
2012-04-06 18:39:12 +02:00
{
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
2013-06-06 05:21:41 +02:00
if ( lockSend )
2016-04-16 02:03:18 +02:00
GetNodeSignals ( ) . SendMessages ( pnode ) ;
2012-04-06 18:39:12 +02:00
}
2013-03-07 04:31:26 +01:00
boost : : this_thread : : interruption_point ( ) ;
2010-08-29 18:58:15 +02:00
}
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2011-05-15 09:11:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
2010-08-29 18:58:15 +02:00
pnode - > Release ( ) ;
}
2013-11-15 12:24:34 +01:00
2013-10-28 21:20:21 +01:00
if ( fSleep )
2015-04-05 11:35:37 +02:00
messageHandlerCondition . timed_wait ( lock , boost : : posix_time : : microsec_clock : : universal_time ( ) + boost : : posix_time : : milliseconds ( 100 ) ) ;
2010-08-29 18:58:15 +02:00
}
}
2016-04-16 01:53:45 +02:00
bool BindListenPort ( const CService & addrBind , std : : string & strError , bool fWhitelisted )
2010-08-29 18:58:15 +02: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 ) )
{
2014-05-24 11:14:52 +02:00
strError = strprintf ( " Error: Bind address family for %s not supported " , addrBind . ToString ( ) ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " %s \n " , strError ) ;
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 18:58:15 +02:00
if ( hListenSocket = = INVALID_SOCKET )
{
2014-05-08 14:15:19 +02:00
strError = strprintf ( " Error: Couldn't open socket for incoming connections (socket returned error %s) " , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " %s \n " , strError ) ;
2010-08-29 18:58:15 +02:00
return false ;
}
2015-07-10 00:23:27 +02:00
if ( ! IsSelectableSocket ( hListenSocket ) )
{
strError = " Error: Couldn't create a listenable socket for incoming connections " ;
LogPrintf ( " %s \n " , strError ) ;
return false ;
}
2010-08-29 18:58:15 +02:00
2014-06-24 09:03:18 +02:00
# ifndef WIN32
2011-08-07 18:18:05 +02:00
# ifdef SO_NOSIGPIPE
2010-08-29 18:58:15 +02: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 21:50:13 +02:00
// the program was closed and restarted.
2010-08-29 18:58:15 +02:00
setsockopt ( hListenSocket , SOL_SOCKET , SO_REUSEADDR , ( void * ) & nOne , sizeof ( int ) ) ;
2015-10-22 01:52:29 +02:00
// Disable Nagle's algorithm
setsockopt ( hListenSocket , IPPROTO_TCP , TCP_NODELAY , ( void * ) & nOne , sizeof ( int ) ) ;
2015-08-20 21:50:13 +02:00
# else
setsockopt ( hListenSocket , SOL_SOCKET , SO_REUSEADDR , ( const char * ) & nOne , sizeof ( int ) ) ;
2015-10-22 01:52:29 +02:00
setsockopt ( hListenSocket , IPPROTO_TCP , TCP_NODELAY , ( const char * ) & nOne , sizeof ( int ) ) ;
2010-08-29 18:58:15 +02:00
# endif
2012-07-26 02:48:39 +02:00
// Set to non-blocking, incoming connections will also inherit this
2014-07-09 11:00:00 +02:00
if ( ! SetSocketNonBlocking ( hListenSocket , true ) ) {
strError = strprintf ( " BindListenPort: Setting listening socket to non-blocking failed, error %s \n " , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " %s \n " , strError ) ;
2010-08-29 18:58:15 +02: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 18:58:15 +02:00
{
int nErr = WSAGetLastError ( ) ;
if ( nErr = = WSAEADDRINUSE )
2015-12-09 11:53:12 +01:00
strError = strprintf ( _ ( " Unable to bind to %s on this computer. %s is probably already running. " ) , addrBind . ToString ( ) , _ ( PACKAGE_NAME ) ) ;
2010-08-29 18:58:15 +02:00
else
2014-05-08 14:15:19 +02:00
strError = strprintf ( _ ( " Unable to bind to %s on this computer (bind returned error %s) " ) , addrBind . ToString ( ) , NetworkErrorString ( nErr ) ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " %s \n " , strError ) ;
2014-07-17 22:33:58 +02:00
CloseSocket ( hListenSocket ) ;
2010-08-29 18:58:15 +02:00
return false ;
}
2014-01-16 16:15:27 +01:00
LogPrintf ( " Bound to %s \n " , addrBind . ToString ( ) ) ;
2010-08-29 18:58:15 +02:00
// Listen for incoming connections
if ( listen ( hListenSocket , SOMAXCONN ) = = SOCKET_ERROR )
{
2014-05-08 14:15:19 +02:00
strError = strprintf ( _ ( " Error: Listening for incoming connections failed (listen returned error %s) " ) , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " %s \n " , strError ) ;
2014-07-17 22:33:58 +02:00
CloseSocket ( hListenSocket ) ;
2010-08-29 18:58:15 +02: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 18:58:15 +02:00
return true ;
}
2013-12-09 05:08:51 +01:00
void static Discover ( boost : : thread_group & threadGroup )
2010-08-29 18:58:15 +02:00
{
2012-05-24 19:02:21 +02:00
if ( ! fDiscover )
2012-02-19 20:44:35 +01:00
return ;
2010-08-29 18:58:15 +02:00
2011-10-07 17:02:21 +02:00
# ifdef WIN32
2012-07-26 02:48:39 +02:00
// Get local host IP
2014-11-13 15:23:15 +01:00
char pszHostName [ 256 ] = " " ;
2010-08-29 18:58:15 +02:00
if ( gethostname ( pszHostName , sizeof ( pszHostName ) ) ! = SOCKET_ERROR )
{
2016-04-16 01:53:45 +02:00
std : : vector < CNetAddr > vaddr ;
2016-04-13 02:23:16 +02:00
if ( LookupHost ( pszHostName , vaddr , 0 , true ) )
2012-05-01 01:44:59 +02:00
{
2012-01-03 23:33:31 +01:00
BOOST_FOREACH ( const CNetAddr & addr , vaddr )
2012-05-01 01:44:59 +02:00
{
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 18:58:15 +02: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 ( ) ) ;
2010-08-29 18:58:15 +02: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 ) )
2014-11-13 15:20:57 +01:00
LogPrintf ( " %s: IPv6 %s: %s \n " , __func__ , ifa - > ifa_name , addr . ToString ( ) ) ;
2010-08-29 18:58:15 +02:00
}
}
freeifaddrs ( myaddrs ) ;
}
# endif
2012-02-19 20:44:35 +01:00
}
2015-04-02 18:04:59 +02: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... " ) ) ;
2015-07-03 09:46:17 +02:00
// Load addresses from peers.dat
2014-09-18 14:08:43 +02:00
int64_t nStart = GetTimeMillis ( ) ;
{
CAddrDB adb ;
2015-07-03 09:46:17 +02:00
if ( adb . Read ( addrman ) )
LogPrintf ( " Loaded %i addresses from peers.dat %dms \n " , addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
2016-02-02 10:45:11 +01:00
else {
2016-03-16 17:54:30 +01:00
addrman . Clear ( ) ; // Addrman can be in an inconsistent state after failure, reset it
2014-09-18 14:08:43 +02:00
LogPrintf ( " Invalid or missing peers.dat; recreating \n " ) ;
2016-02-02 10:45:11 +01:00
DumpAddresses ( ) ;
}
2014-09-18 14:08:43 +02:00
}
2015-06-19 15:27:37 +02:00
2015-07-03 09:46:17 +02:00
uiInterface . InitMessage ( _ ( " Loading banlist... " ) ) ;
// Load addresses from banlist.dat
nStart = GetTimeMillis ( ) ;
2015-06-19 15:27:37 +02:00
CBanDB bandb ;
2015-06-26 21:38:33 +02:00
banmap_t banmap ;
2015-07-03 09:44:49 +02:00
if ( bandb . Read ( banmap ) ) {
CNode : : SetBanned ( banmap ) ; // thread save setter
CNode : : SetBannedSetDirty ( false ) ; // no need to write down, just read data
CNode : : SweepBanned ( ) ; // sweep out unused entries
LogPrint ( " net " , " Loaded %d banned node ips/subnets from banlist.dat %dms \n " ,
banmap . size ( ) , GetTimeMillis ( ) - nStart ) ;
2016-02-02 10:45:11 +01:00
} else {
2015-06-19 15:27:37 +02:00
LogPrintf ( " Invalid or missing banlist.dat; recreating \n " ) ;
2016-02-02 10:45:11 +01:00
CNode : : SetBannedSetDirty ( true ) ; // force write
DumpBanlist ( ) ;
}
2015-06-19 15:27:37 +02:00
2016-07-22 16:01:12 +02:00
uiInterface . InitMessage ( _ ( " Starting network threads... " ) ) ;
2014-09-18 14:08:43 +02:00
fAddressesInitialized = true ;
2012-05-10 18:44:07 +02:00
if ( semOutbound = = NULL ) {
// initialize semaphore
2016-06-17 06:10:07 +02:00
int nMaxOutbound = std : : min ( ( MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS ) , nMaxConnections ) ;
2012-05-10 18:44:07 +02:00
semOutbound = new CSemaphore ( nMaxOutbound ) ;
}
2016-05-31 19:51:11 +02:00
if ( pnodeLocalHost = = NULL ) {
CNetAddr local ;
LookupHost ( " 127.0.0.1 " , local , false ) ;
pnodeLocalHost = new CNode ( INVALID_SOCKET , CAddress ( CService ( local , 0 ) , nLocalServices ) ) ;
}
2012-02-19 20:44:35 +01:00
2013-12-09 05:08:51 +01:00
Discover ( threadGroup ) ;
2010-08-29 18:58:15 +02:00
//
// Start threads
//
2012-02-06 20:35:57 +01:00
if ( ! GetBoolArg ( " -dnsseed " , true ) )
2013-09-18 12:38:08 +02:00
LogPrintf ( " DNS seeding disabled \n " ) ;
2011-11-21 18:25:00 +01:00
else
2013-04-23 11:36:54 +02:00
threadGroup . create_thread ( boost : : bind ( & TraceThread < void ( * ) ( ) > , " dnsseed " , & ThreadDNSAddressSeed ) ) ;
2011-11-21 18:25:00 +01: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 18:58:15 +02:00
// Send and receive from sockets, accept connections
2013-03-09 18:02:57 +01:00
threadGroup . create_thread ( boost : : bind ( & TraceThread < void ( * ) ( ) > , " net " , & ThreadSocketHandler ) ) ;
2010-08-29 18:58:15 +02:00
2011-12-17 01:48:03 +01:00
// Initiate outbound connections from -addnode
2013-03-09 18:02:57 +01:00
threadGroup . create_thread ( boost : : bind ( & TraceThread < void ( * ) ( ) > , " addcon " , & ThreadOpenAddedConnections ) ) ;
2011-12-17 01:48:03 +01:00
2010-08-29 18:58:15 +02:00
// Initiate outbound connections
2013-03-09 18:02:57 +01:00
threadGroup . create_thread ( boost : : bind ( & TraceThread < void ( * ) ( ) > , " opencon " , & ThreadOpenConnections ) ) ;
2010-08-29 18:58:15 +02:00
// Process messages
2013-03-09 18:02:57 +01:00
threadGroup . create_thread ( boost : : bind ( & TraceThread < void ( * ) ( ) > , " msghand " , & ThreadMessageHandler ) ) ;
2010-08-29 18:58:15 +02: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 18:58:15 +02:00
}
bool StopNode ( )
{
2013-09-18 12:38:08 +02:00
LogPrintf ( " StopNode() \n " ) ;
2013-03-07 04:31:26 +01:00
MapPort ( false ) ;
2012-05-12 17:44:14 +02:00
if ( semOutbound )
2016-06-17 06:10:07 +02:00
for ( int i = 0 ; i < ( MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS ) ; i + + )
2012-05-12 17:44:14 +02:00
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 18:58:15 +02:00
return true ;
}
class CNetCleanup
{
public :
2014-05-24 11:14:52 +02:00
CNetCleanup ( ) { }
2010-08-29 18:58:15 +02:00
~ CNetCleanup ( )
{
// Close sockets
2011-05-15 09:11:04 +02:00
BOOST_FOREACH ( CNode * pnode , vNodes )
2010-08-29 18:58:15 +02:00
if ( pnode - > hSocket ! = INVALID_SOCKET )
2014-07-10 12:13:03 +02:00
CloseSocket ( pnode - > hSocket ) ;
2014-06-21 13:34:36 +02:00
BOOST_FOREACH ( ListenSocket & hListenSocket , vhListenSocket )
if ( hListenSocket . socket ! = INVALID_SOCKET )
2014-07-10 12:13:03 +02:00
if ( ! CloseSocket ( hListenSocket . socket ) )
LogPrintf ( " CloseSocket(hListenSocket) failed with error %s \n " , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
2010-08-29 18:58:15 +02:00
2013-03-29 02:17:10 +01:00
// clean up some globals (to help leak detection)
BOOST_FOREACH ( CNode * pnode , vNodes )
delete pnode ;
BOOST_FOREACH ( CNode * pnode , vNodesDisconnected )
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 17:02:21 +02:00
# ifdef WIN32
2010-08-29 18:58:15 +02:00
// Shutdown Windows Sockets
WSACleanup ( ) ;
# endif
}
}
instance_of_cnetcleanup ;
2012-08-13 05:26:30 +02:00
2016-04-20 21:38:19 +02:00
void RelayTransaction ( const CTransaction & tx )
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_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
{
2016-04-20 09:05:23 +02:00
pnode - > PushInventory ( inv ) ;
2012-08-13 05:26:30 +02:00
}
}
2013-08-22 18:09:32 +02:00
2013-04-13 07:13:08 +02:00
void CNode : : RecordBytesRecv ( uint64_t bytes )
2013-08-22 18:09:32 +02:00
{
LOCK ( cs_totalBytesRecv ) ;
nTotalBytesRecv + = bytes ;
}
2013-04-13 07:13:08 +02:00
void CNode : : RecordBytesSent ( uint64_t bytes )
2013-08-22 18:09:32 +02: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 ) ;
2016-01-03 18:54:50 +01:00
uint64_t recommendedMinimum = ( nMaxOutboundTimeframe / 600 ) * MAX_BLOCK_SERIALIZED_SIZE ;
2015-09-02 17:03:27 +02:00
nMaxOutboundLimit = limit ;
2015-11-06 00:05:06 +01:00
if ( limit > 0 & & limit < recommendedMinimum )
LogPrintf ( " Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes. \n " , nMaxOutboundLimit , recommendedMinimum ) ;
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 )
{
2016-01-17 12:03:56 +01:00
// keep a large enough buffer to at least relay each block once
2015-09-02 17:03:27 +02:00
uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle ( ) ;
2016-01-03 18:54:50 +01:00
uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SERIALIZED_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-22 18:09:32 +02:00
}
2013-04-13 07:13:08 +02:00
uint64_t CNode : : GetTotalBytesRecv ( )
2013-08-22 18:09:32 +02:00
{
LOCK ( cs_totalBytesRecv ) ;
return nTotalBytesRecv ;
}
2013-04-13 07:13:08 +02:00
uint64_t CNode : : GetTotalBytesSent ( )
2013-08-22 18:09:32 +02:00
{
LOCK ( cs_totalBytesSent ) ;
return nTotalBytesSent ;
}
2013-10-28 07:28:00 +01: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 " ;
}
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 ) ;
ssPeers < < FLATDATA ( Params ( ) . MessageStart ( ) ) ;
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-26 01:25:19 +02:00
CAutoFile fileout ( file , SER_DISK , CLIENT_VERSION ) ;
2014-10-14 01:48:34 +02: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-26 01:25:19 +02:00
CAutoFile filein ( file , SER_DISK , CLIENT_VERSION ) ;
2014-10-14 01:48:34 +02: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 ) ;
2016-04-16 01:53:45 +02: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 17:54:30 +01: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
if ( memcmp ( pchMsgTmp , Params ( ) . MessageStart ( ) , 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 17:54:30 +01: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
2015-06-27 21:21:41 +02:00
unsigned int ReceiveFloodSize ( ) { return 1000 * GetArg ( " -maxreceivebuffer " , DEFAULT_MAXRECEIVEBUFFER ) ; }
unsigned int SendBufferSize ( ) { return 1000 * GetArg ( " -maxsendbuffer " , DEFAULT_MAXSENDBUFFER ) ; }
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 17:19:57 +02:00
ssSend ( SER_NETWORK , INIT_PROTO_VERSION ) ,
2016-05-25 15:38:32 +02:00
addr ( addrIn ) ,
nKeyedNetGroup ( CalculateKeyedNetGroup ( addrIn ) ) ,
2015-07-19 21:43:34 +02:00
addrKnown ( 5000 , 0.001 ) ,
2015-11-29 10:52:51 +01:00
filterInventoryKnown ( 50000 , 0.000001 )
2014-08-21 05:17:21 +02:00
{
2016-06-08 19:12:22 +02:00
nServices = NODE_NONE ;
nServicesExpected = NODE_NONE ;
2014-08-21 05:17:21 +02:00
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
addrName = addrNameIn = = " " ? addr . ToStringIPPort ( ) : addrNameIn ;
nVersion = 0 ;
strSubVer = " " ;
fWhitelisted = false ;
fOneShot = false ;
fClient = false ; // set by version message
2016-06-17 06:10:07 +02:00
fFeeler = false ;
2014-08-21 05:17:21 +02:00
fInbound = fInboundIn ;
fNetworkNode = false ;
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-29 10:52:51 +01:00
filterInventoryKnown . reset ( ) ;
2016-04-08 16:26:41 +02:00
fSendMempool = false ;
2014-08-21 05:17:21 +02:00
fGetAddr = false ;
2015-04-08 20:20:00 +02:00
nNextLocalAddrSend = 0 ;
nNextAddrSend = 0 ;
nNextInvSend = 0 ;
2014-08-21 05:17:21 +02:00
fRelayTxes = false ;
2016-04-11 03:09:34 +02:00
fSentAddr = false ;
2014-08-21 05:17:21 +02:00
pfilter = new CBloomFilter ( ) ;
2016-05-20 18:19:26 +02:00
timeLastMempoolReq = 0 ;
2016-05-22 07:55:15 +02:00
nLastBlockTime = 0 ;
nLastTXTime = 0 ;
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-02-12 21:57:15 +01:00
minFeeFilter = 0 ;
lastSentFeeFilter = 0 ;
nextSendTimeFeeFilter = 0 ;
2015-12-07 15:31:32 +01:00
BOOST_FOREACH ( const std : : string & msg , getAllNetMessageTypes ( ) )
mapRecvBytesPerMsgCmd [ msg ] = 0 ;
2015-08-25 16:30:31 +02:00
mapRecvBytesPerMsgCmd [ NET_MESSAGE_COMMAND_OTHER ] = 0 ;
2014-08-21 05:17:21 +02:00
{
LOCK ( cs_nLastNodeId ) ;
id = nLastNodeId + + ;
}
if ( fLogIPs )
LogPrint ( " net " , " Added connection to %s peer=%d \n " , addrName , id ) ;
else
LogPrint ( " net " , " Added connection peer=%d \n " , id ) ;
// Be shy and don't send version until we hear
if ( hSocket ! = INVALID_SOCKET & & ! fInbound )
PushVersion ( ) ;
GetNodeSignals ( ) . InitializeNode ( GetId ( ) , this ) ;
}
CNode : : ~ CNode ( )
{
CloseSocket ( hSocket ) ;
if ( pfilter )
delete pfilter ;
GetNodeSignals ( ) . FinalizeNode ( GetId ( ) ) ;
}
void CNode : : AskFor ( const CInv & inv )
{
2015-11-23 02:54:23 +01:00
if ( mapAskFor . size ( ) > MAPASKFOR_MAX_SZ | | setAskFor . size ( ) > SETASKFOR_MAX_SZ )
2014-09-09 09:18:05 +02:00
return ;
2015-11-23 02:54:23 +01:00
// a peer may not have multiple non-responded queue positions for a single inv item
2014-07-16 23:31:41 +02: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 18:52:29 +02: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 ;
2014-09-08 12:25:52 +02:00
LogPrint ( " net " , " askfor %s %d (%s) peer=%d \n " , inv . ToString ( ) , nRequestTime , DateTimeStrFormat ( " %H:%M:%S " , nRequestTime / 1000000 ) , 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 18:52:29 +02: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 )
{
ENTER_CRITICAL_SECTION ( cs_vSend ) ;
assert ( ssSend . size ( ) = = 0 ) ;
2014-10-28 01:24:31 +01:00
ssSend < < CMessageHeader ( Params ( ) . MessageStart ( ) , pszCommand , 0 ) ;
2015-02-08 01:59:58 +01:00
LogPrint ( " net " , " sending: %s " , SanitizeString ( pszCommand ) ) ;
2014-08-21 05:17:21 +02:00
}
void CNode : : AbortMessage ( ) UNLOCK_FUNCTION ( cs_vSend )
{
ssSend . clear ( ) ;
LEAVE_CRITICAL_SECTION ( cs_vSend ) ;
LogPrint ( " net " , " (aborted) \n " ) ;
}
2015-08-25 16:30:31 +02:00
void CNode : : EndMessage ( const char * pszCommand ) UNLOCK_FUNCTION ( cs_vSend )
2014-08-21 05:17:21 +02:00
{
// 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 )
{
LogPrint ( " net " , " dropmessages DROPPING SEND MESSAGE \n " ) ;
AbortMessage ( ) ;
return ;
}
if ( mapArgs . count ( " -fuzzmessagestest " ) )
Fuzz ( GetArg ( " -fuzzmessagestest " , 10 ) ) ;
if ( ssSend . size ( ) = = 0 )
2015-06-16 10:02:25 +02:00
{
LEAVE_CRITICAL_SECTION ( cs_vSend ) ;
2014-08-21 05:17:21 +02:00
return ;
2015-06-16 10:02:25 +02: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
2015-08-25 16:30:31 +02:00
//log total amount of bytes per command
mapSendBytesPerMsgCmd [ std : : string ( pszCommand ) ] + = nSize + CMessageHeader : : HEADER_SIZE ;
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 ) ) ;
LogPrint ( " net " , " (%d bytes) peer=%d \n " , nSize , id ) ;
std : : deque < CSerializeData > : : iterator it = vSendMsg . insert ( vSendMsg . end ( ) , CSerializeData ( ) ) ;
ssSend . GetAndClear ( * it ) ;
nSendSize + = ( * it ) . size ( ) ;
// If write queue empty, attempt "optimistic write"
if ( it = = vSendMsg . begin ( ) )
SocketSendData ( this ) ;
LEAVE_CRITICAL_SECTION ( cs_vSend ) ;
}
2015-06-19 15:27:37 +02:00
//
// CBanDB
//
CBanDB : : CBanDB ( )
{
pathBanlist = GetDataDir ( ) / " banlist.dat " ;
}
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 ) ;
ssBanlist < < FLATDATA ( Params ( ) . MessageStart ( ) ) ;
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 ) ;
2016-04-16 01:53:45 +02: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
if ( memcmp ( pchMsgTmp , Params ( ) . MessageStart ( ) , sizeof ( pchMsgTmp ) ) )
return error ( " %s: Invalid network magic number " , __func__ ) ;
2015-07-03 10:46:08 +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 ( ) ) ;
}
2015-07-03 10:46:08 +02:00
2015-06-19 15:27:37 +02:00
return true ;
}
2015-04-08 20:20:00 +02: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 ) ;
}
2016-05-25 15:38:32 +02:00
/* static */ uint64_t CNode : : CalculateKeyedNetGroup ( const CAddress & ad )
{
2016-06-07 16:29:03 +02:00
static const uint64_t k0 = GetRand ( std : : numeric_limits < uint64_t > : : max ( ) ) ;
static const uint64_t k1 = GetRand ( std : : numeric_limits < uint64_t > : : max ( ) ) ;
2016-05-25 15:38:32 +02:00
std : : vector < unsigned char > vchNetGroup ( ad . GetGroup ( ) ) ;
return CSipHasher ( k0 , k1 ) . Write ( & vchNetGroup [ 0 ] , vchNetGroup . size ( ) ) . Finalize ( ) ;
}