// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include "irc.h"
# include "db.h"
# include "net.h"
# include "init.h"
# include "addrman.h"
# include "ui_interface.h"
# include "script.h"
# ifdef WIN32
# include <string.h>
# endif
# ifdef USE_UPNP
# include <miniupnpc/miniwget.h>
# include <miniupnpc/miniupnpc.h>
# include <miniupnpc/upnpcommands.h>
# include <miniupnpc/upnperrors.h>
# endif
using namespace std ;
using namespace boost ;
static const int MAX_OUTBOUND_CONNECTIONS = 8 ;
void ThreadMessageHandler2 ( void * parg ) ;
void ThreadSocketHandler2 ( void * parg ) ;
void ThreadOpenConnections2 ( void * parg ) ;
void ThreadOpenAddedConnections2 ( void * parg ) ;
# ifdef USE_UPNP
void ThreadMapPort2 ( void * parg ) ;
# endif
void ThreadDNSAddressSeed2 ( void * parg ) ;
bool OpenNetworkConnection ( const CAddress & addrConnect , CSemaphoreGrant * grantOutbound = NULL , const char * strDest = NULL , bool fOneShot = false ) ;
struct LocalServiceInfo {
int nScore ;
int nPort ;
} ;
//
// Global state variables
//
bool fDiscover = true ;
bool fUseUPnP = false ;
uint64 nLocalServices = NODE_NETWORK ;
static CCriticalSection cs_mapLocalHost ;
static map < CNetAddr , LocalServiceInfo > mapLocalHost ;
static bool vfReachable [ NET_MAX ] = { } ;
static bool vfLimited [ NET_MAX ] = { } ;
static CNode * pnodeLocalHost = NULL ;
uint64 nLocalHostNonce = 0 ;
array < int , THREAD_MAX > vnThreadsRunning ;
static std : : vector < SOCKET > vhListenSocket ;
CAddrMan addrman ;
vector < CNode * > vNodes ;
CCriticalSection cs_vNodes ;
map < CInv , CDataStream > mapRelay ;
deque < pair < int64 , CInv > > vRelayExpiration ;
CCriticalSection cs_mapRelay ;
map < CInv , int64 > mapAlreadyAskedFor ;
static deque < string > vOneShots ;
CCriticalSection cs_vOneShots ;
set < CNetAddr > setservAddNodeAddresses ;
CCriticalSection cs_setservAddNodeAddresses ;
vector < std : : string > vAddedNodes ;
CCriticalSection cs_vAddedNodes ;
static CSemaphore * semOutbound = NULL ;
void AddOneShot ( string strDest )
{
LOCK ( cs_vOneShots ) ;
vOneShots . push_back ( strDest ) ;
}
unsigned short GetListenPort ( )
{
return ( unsigned short ) ( GetArg ( " -port " , GetDefaultPort ( ) ) ) ;
}
void CNode : : PushGetBlocks ( CBlockIndex * pindexBegin , uint256 hashEnd )
{
// Filter out duplicate requests
if ( pindexBegin = = pindexLastGetBlocksBegin & & hashEnd = = hashLastGetBlocksEnd )
return ;
pindexLastGetBlocksBegin = pindexBegin ;
hashLastGetBlocksEnd = hashEnd ;
PushMessage ( " getblocks " , CBlockLocator ( pindexBegin ) , hashEnd ) ;
}
// find 'best' local address for a particular peer
bool GetLocal ( CService & addr , const CNetAddr * paddrPeer )
{
if ( fNoListen )
return false ;
int nBestScore = - 1 ;
int nBestReachability = - 1 ;
{
LOCK ( cs_mapLocalHost ) ;
for ( map < CNetAddr , LocalServiceInfo > : : iterator it = mapLocalHost . begin ( ) ; it ! = mapLocalHost . end ( ) ; it + + )
{
int nScore = ( * it ) . second . nScore ;
int nReachability = ( * it ) . first . GetReachabilityFrom ( paddrPeer ) ;
if ( nReachability > nBestReachability | | ( nReachability = = nBestReachability & & nScore > nBestScore ) )
{
addr = CService ( ( * it ) . first , ( * it ) . second . nPort ) ;
nBestReachability = nReachability ;
nBestScore = nScore ;
}
}
}
return nBestScore > = 0 ;
}
// get best local address for a particular peer as a CAddress
CAddress GetLocalAddress ( const CNetAddr * paddrPeer )
{
CAddress ret ( CService ( " 0.0.0.0 " , 0 ) , 0 ) ;
CService addr ;
if ( GetLocal ( addr , paddrPeer ) )
{
ret = CAddress ( addr ) ;
ret . nServices = nLocalServices ;
ret . nTime = GetAdjustedTime ( ) ;
}
return ret ;
}
bool RecvLine ( SOCKET hSocket , string & strLine )
{
strLine = " " ;
loop
{
char c ;
int nBytes = recv ( hSocket , & c , 1 , 0 ) ;
if ( nBytes > 0 )
{
if ( c = = ' \n ' )
continue ;
if ( c = = ' \r ' )
return true ;
strLine + = c ;
if ( strLine . size ( ) > = 9000 )
return true ;
}
else if ( nBytes < = 0 )
{
if ( fShutdown )
return false ;
if ( nBytes < 0 )
{
int nErr = WSAGetLastError ( ) ;
if ( nErr = = WSAEMSGSIZE )
continue ;
if ( nErr = = WSAEWOULDBLOCK | | nErr = = WSAEINTR | | nErr = = WSAEINPROGRESS )
{
Sleep ( 10 ) ;
continue ;
}
}
if ( ! strLine . empty ( ) )
return true ;
if ( nBytes = = 0 )
{
// socket closed
printf ( " socket closed \n " ) ;
return false ;
}
else
{
// socket error
int nErr = WSAGetLastError ( ) ;
printf ( " recv failed: %d \n " , nErr ) ;
return false ;
}
}
}
}
// used when scores of local addresses may have changed
// pushes better local address to peers
void static AdvertizeLocal ( )
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
{
if ( pnode - > fSuccessfullyConnected )
{
CAddress addrLocal = GetLocalAddress ( & pnode - > addr ) ;
if ( addrLocal . IsRoutable ( ) & & ( CService ) addrLocal ! = ( CService ) pnode - > addrLocal )
{
pnode - > PushAddress ( addrLocal ) ;
pnode - > addrLocal = addrLocal ;
}
}
}
}
void SetReachable ( enum Network net , bool fFlag )
{
LOCK ( cs_mapLocalHost ) ;
vfReachable [ net ] = fFlag ;
if ( net = = NET_IPV6 & & fFlag )
vfReachable [ NET_IPV4 ] = true ;
}
// learn a new local address
bool AddLocal ( const CService & addr , int nScore )
{
if ( ! addr . IsRoutable ( ) )
return false ;
if ( ! fDiscover & & nScore < LOCAL_MANUAL )
return false ;
if ( IsLimited ( addr ) )
return false ;
printf ( " AddLocal(%s,%i) \n " , addr . ToString ( ) . c_str ( ) , nScore ) ;
{
LOCK ( cs_mapLocalHost ) ;
bool fAlready = mapLocalHost . count ( addr ) > 0 ;
LocalServiceInfo & info = mapLocalHost [ addr ] ;
if ( ! fAlready | | nScore > = info . nScore ) {
info . nScore = nScore + ( fAlready ? 1 : 0 ) ;
info . nPort = addr . GetPort ( ) ;
}
SetReachable ( addr . GetNetwork ( ) ) ;
}
AdvertizeLocal ( ) ;
return true ;
}
bool AddLocal ( const CNetAddr & addr , int nScore )
{
return AddLocal ( CService ( addr , GetListenPort ( ) ) , nScore ) ;
}
/** Make a particular network entirely off-limits (no automatic connects to it) */
void SetLimited ( enum Network net , bool fLimited )
{
if ( net = = NET_UNROUTABLE )
return ;
LOCK ( cs_mapLocalHost ) ;
vfLimited [ net ] = fLimited ;
}
bool IsLimited ( enum Network net )
{
LOCK ( cs_mapLocalHost ) ;
return vfLimited [ net ] ;
}
bool IsLimited ( const CNetAddr & addr )
{
return IsLimited ( addr . GetNetwork ( ) ) ;
}
/** vote for a local address */
bool SeenLocal ( const CService & addr )
{
{
LOCK ( cs_mapLocalHost ) ;
if ( mapLocalHost . count ( addr ) = = 0 )
return false ;
mapLocalHost [ addr ] . nScore + + ;
}
AdvertizeLocal ( ) ;
return true ;
}
/** check whether a given address is potentially local */
bool IsLocal ( const CService & addr )
{
LOCK ( cs_mapLocalHost ) ;
return mapLocalHost . count ( addr ) > 0 ;
}
/** check whether a given address is in a network we can probably connect to */
bool IsReachable ( const CNetAddr & addr )
{
LOCK ( cs_mapLocalHost ) ;
enum Network net = addr . GetNetwork ( ) ;
return vfReachable [ net ] & & ! vfLimited [ net ] ;
}
bool GetMyExternalIP2 ( const CService & addrConnect , const char * pszGet , const char * pszKeyword , CNetAddr & ipRet )
{
SOCKET hSocket ;
if ( ! ConnectSocket ( addrConnect , hSocket ) )
return error ( " GetMyExternalIP() : connection to % s failed " , addrConnect.ToString().c_str()) ;
send ( hSocket , pszGet , strlen ( pszGet ) , MSG_NOSIGNAL ) ;
string strLine ;
while ( RecvLine ( hSocket , strLine ) )
{
if ( strLine . empty ( ) ) // HTTP response is separated from headers by blank line
{
loop
{
if ( ! RecvLine ( hSocket , strLine ) )
{
closesocket ( hSocket ) ;
return false ;
}
if ( pszKeyword = = NULL )
break ;
if ( strLine . find ( pszKeyword ) ! = string : : npos )
{
strLine = strLine . substr ( strLine . find ( pszKeyword ) + strlen ( pszKeyword ) ) ;
break ;
}
}
closesocket ( hSocket ) ;
if ( strLine . find ( " < " ) ! = string : : npos )
strLine = strLine . substr ( 0 , strLine . find ( " < " ) ) ;
strLine = strLine . substr ( strspn ( strLine . c_str ( ) , " \t \n \r " ) ) ;
while ( strLine . size ( ) > 0 & & isspace ( strLine [ strLine . size ( ) - 1 ] ) )
strLine . resize ( strLine . size ( ) - 1 ) ;
CService addr ( strLine , 0 , true ) ;
printf ( " GetMyExternalIP() received [%s] %s \n " , strLine . c_str ( ) , addr . ToString ( ) . c_str ( ) ) ;
if ( ! addr . IsValid ( ) | | ! addr . IsRoutable ( ) )
return false ;
ipRet . SetIP ( addr ) ;
return true ;
}
}
closesocket ( hSocket ) ;
return error ( " GetMyExternalIP() : connection closed " ) ;
}
// We now get our external IP from the IRC server first and only use this as a backup
bool GetMyExternalIP ( CNetAddr & ipRet )
{
CService addrConnect ;
const char * pszGet ;
const char * pszKeyword ;
for ( int nLookup = 0 ; nLookup < = 1 ; nLookup + + )
for ( int nHost = 1 ; nHost < = 2 ; nHost + + )
{
// We should be phasing out our use of sites like these. If we need
// replacements, we should ask for volunteers to put this simple
// php file on their web server that prints the client IP:
// <?php echo $_SERVER["REMOTE_ADDR"]; ?>
if ( nHost = = 1 )
{
addrConnect = CService ( " 91.198.22.70 " , 80 ) ; // checkip.dyndns.org
if ( nLookup = = 1 )
{
CService addrIP ( " checkip.dyndns.org " , 80 , true ) ;
if ( addrIP . IsValid ( ) )
addrConnect = addrIP ;
}
pszGet = " GET / HTTP/1.1 \r \n "
" Host: checkip.dyndns.org \r \n "
" User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1) \r \n "
" Connection: close \r \n "
" \r \n " ;
pszKeyword = " Address: " ;
}
else if ( nHost = = 2 )
{
addrConnect = CService ( " 74.208.43.192 " , 80 ) ; // www.showmyip.com
if ( nLookup = = 1 )
{
CService addrIP ( " www.showmyip.com " , 80 , true ) ;
if ( addrIP . IsValid ( ) )
addrConnect = addrIP ;
}
pszGet = " GET /simple/ HTTP/1.1 \r \n "
" Host: www.showmyip.com \r \n "
" User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1) \r \n "
" Connection: close \r \n "
" \r \n " ;
pszKeyword = NULL ; // Returns just IP address
}
if ( GetMyExternalIP2 ( addrConnect , pszGet , pszKeyword , ipRet ) )
return true ;
}
return false ;
}
void ThreadGetMyExternalIP ( void * parg )
{
// Make this thread recognisable as the external IP detection thread
RenameThread ( " bitcoin-ext-ip " ) ;
CNetAddr addrLocalHost ;
if ( GetMyExternalIP ( addrLocalHost ) )
{
printf ( " GetMyExternalIP() returned %s \n " , addrLocalHost . ToStringIP ( ) . c_str ( ) ) ;
AddLocal ( addrLocalHost , LOCAL_HTTP ) ;
}
}
void AddressCurrentlyConnected ( const CService & addr )
{
addrman . Connected ( addr ) ;
}
CNode * FindNode ( const CNetAddr & ip )
{
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( ( CNetAddr ) pnode - > addr = = ip )
return ( pnode ) ;
}
return NULL ;
}
CNode * FindNode ( std : : string addrName )
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( pnode - > addrName = = addrName )
return ( pnode ) ;
return NULL ;
}
CNode * FindNode ( const CService & addr )
{
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( ( CService ) pnode - > addr = = addr )
return ( pnode ) ;
}
return NULL ;
}
CNode * ConnectNode ( CAddress addrConnect , const char * pszDest , int64 nTimeout )
{
if ( pszDest = = NULL ) {
if ( IsLocal ( addrConnect ) )
return NULL ;
// Look for an existing connection
CNode * pnode = FindNode ( ( CService ) addrConnect ) ;
if ( pnode )
{
if ( nTimeout ! = 0 )
pnode - > AddRef ( nTimeout ) ;
else
pnode - > AddRef ( ) ;
return pnode ;
}
}
/// debug print
printf ( " trying connection %s lastseen=%.1fhrs \n " ,
pszDest ? pszDest : addrConnect . ToString ( ) . c_str ( ) ,
pszDest ? 0 : ( double ) ( GetAdjustedTime ( ) - addrConnect . nTime ) / 3600.0 ) ;
// Connect
SOCKET hSocket ;
if ( pszDest ? ConnectSocketByName ( addrConnect , hSocket , pszDest , GetDefaultPort ( ) ) : ConnectSocket ( addrConnect , hSocket ) )
{
addrman . Attempt ( addrConnect ) ;
/// debug print
printf ( " connected %s \n " , pszDest ? pszDest : addrConnect . ToString ( ) . c_str ( ) ) ;
// Set to non-blocking
# ifdef WIN32
u_long nOne = 1 ;
if ( ioctlsocket ( hSocket , FIONBIO , & nOne ) = = SOCKET_ERROR )
printf ( " ConnectSocket() : ioctlsocket non-blocking setting failed, error %d \n " , WSAGetLastError ( ) ) ;
# else
if ( fcntl ( hSocket , F_SETFL , O_NONBLOCK ) = = SOCKET_ERROR )
printf ( " ConnectSocket() : fcntl non-blocking setting failed, error %d \n " , errno ) ;
# endif
// Add node
CNode * pnode = new CNode ( hSocket , addrConnect , pszDest ? pszDest : " " , false ) ;
if ( nTimeout ! = 0 )
pnode - > AddRef ( nTimeout ) ;
else
pnode - > AddRef ( ) ;
{
LOCK ( cs_vNodes ) ;
vNodes . push_back ( pnode ) ;
}
pnode - > nTimeConnected = GetTime ( ) ;
return pnode ;
}
else
{
return NULL ;
}
}
void CNode : : CloseSocketDisconnect ( )
{
fDisconnect = true ;
if ( hSocket ! = INVALID_SOCKET )
{
printf ( " disconnecting node %s \n " , addrName . c_str ( ) ) ;
closesocket ( hSocket ) ;
hSocket = INVALID_SOCKET ;
vRecv . clear ( ) ;
}
}
void CNode : : Cleanup ( )
{
}
void CNode : : PushVersion ( )
{
/// when NTP implemented, change to just nTime = GetAdjustedTime()
int64 nTime = ( fInbound ? GetAdjustedTime ( ) : GetTime ( ) ) ;
CAddress addrYou = ( addr . IsRoutable ( ) & & ! IsProxy ( addr ) ? addr : CAddress ( CService ( " 0.0.0.0 " , 0 ) ) ) ;
CAddress addrMe = GetLocalAddress ( & addr ) ;
RAND_bytes ( ( unsigned char * ) & nLocalHostNonce , sizeof ( nLocalHostNonce ) ) ;
printf ( " send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s \n " , PROTOCOL_VERSION , nBestHeight , addrMe . ToString ( ) . c_str ( ) , addrYou . ToString ( ) . c_str ( ) , addr . ToString ( ) . c_str ( ) ) ;
PushMessage ( " version " , PROTOCOL_VERSION , nLocalServices , nTime , addrYou , addrMe ,
nLocalHostNonce , FormatSubVersion ( CLIENT_NAME , CLIENT_VERSION , std : : vector < string > ( ) ) , nBestHeight ) ;
}
std : : map < CNetAddr , int64 > CNode : : setBanned ;
CCriticalSection CNode : : cs_setBanned ;
void CNode : : ClearBanned ( )
{
setBanned . clear ( ) ;
}
bool CNode : : IsBanned ( CNetAddr ip )
{
bool fResult = false ;
{
LOCK ( cs_setBanned ) ;
std : : map < CNetAddr , int64 > : : iterator i = setBanned . find ( ip ) ;
if ( i ! = setBanned . end ( ) )
{
int64 t = ( * i ) . second ;
if ( GetTime ( ) < t )
fResult = true ;
}
}
return fResult ;
}
bool CNode : : Misbehaving ( int howmuch )
{
if ( addr . IsLocal ( ) )
{
printf ( " Warning: Local node %s misbehaving (delta: %d)! \n " , addrName . c_str ( ) , howmuch ) ;
return false ;
}
nMisbehavior + = howmuch ;
if ( nMisbehavior > = GetArg ( " -banscore " , 100 ) )
{
int64 banTime = GetTime ( ) + GetArg ( " -bantime " , 60 * 60 * 24 ) ; // Default 24-hour ban
printf ( " Misbehaving: %s (%d -> %d) DISCONNECTING \n " , addr . ToString ( ) . c_str ( ) , nMisbehavior - howmuch , nMisbehavior ) ;
{
LOCK ( cs_setBanned ) ;
if ( setBanned [ addr ] < banTime )
setBanned [ addr ] = banTime ;
}
CloseSocketDisconnect ( ) ;
return true ;
} else
printf ( " Misbehaving: %s (%d -> %d) \n " , addr . ToString ( ) . c_str ( ) , nMisbehavior - howmuch , nMisbehavior ) ;
return false ;
}
# undef X
# define X(name) stats.name = name
void CNode : : copyStats ( CNodeStats & stats )
{
X ( nServices ) ;
X ( nLastSend ) ;
X ( nLastRecv ) ;
X ( nTimeConnected ) ;
X ( addrName ) ;
X ( nVersion ) ;
X ( strSubVer ) ;
X ( fInbound ) ;
X ( nReleaseTime ) ;
X ( nStartingHeight ) ;
X ( nMisbehavior ) ;
}
# undef X
void ThreadSocketHandler ( void * parg )
{
// Make this thread recognisable as the networking thread
RenameThread ( " bitcoin-net " ) ;
try
{
vnThreadsRunning [ THREAD_SOCKETHANDLER ] + + ;
ThreadSocketHandler2 ( parg ) ;
vnThreadsRunning [ THREAD_SOCKETHANDLER ] - - ;
}
catch ( std : : exception & e ) {
vnThreadsRunning [ THREAD_SOCKETHANDLER ] - - ;
PrintException ( & e , " ThreadSocketHandler() " ) ;
} catch ( . . . ) {
vnThreadsRunning [ THREAD_SOCKETHANDLER ] - - ;
throw ; // support pthread_cancel()
}
printf ( " ThreadSocketHandler exited \n " ) ;
}
void ThreadSocketHandler2 ( void * parg )
{
printf ( " ThreadSocketHandler started \n " ) ;
list < CNode * > vNodesDisconnected ;
unsigned int nPrevNodeCount = 0 ;
loop
{
//
// Disconnect nodes
//
{
LOCK ( cs_vNodes ) ;
// Disconnect unused nodes
vector < CNode * > vNodesCopy = vNodes ;
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
{
if ( pnode - > fDisconnect | |
( pnode - > GetRefCount ( ) < = 0 & & pnode - > vRecv . empty ( ) & & pnode - > vSend . empty ( ) ) )
{
// remove from vNodes
vNodes . erase ( remove ( vNodes . begin ( ) , vNodes . end ( ) , pnode ) , vNodes . end ( ) ) ;
// release outbound grant (if any)
pnode - > grantOutbound . Release ( ) ;
// close socket and cleanup
pnode - > CloseSocketDisconnect ( ) ;
pnode - > Cleanup ( ) ;
// hold in disconnected pool until all refs are released
pnode - > nReleaseTime = max ( pnode - > nReleaseTime , GetTime ( ) + 15 * 60 ) ;
if ( pnode - > fNetworkNode | | pnode - > fInbound )
pnode - > Release ( ) ;
vNodesDisconnected . push_back ( pnode ) ;
}
}
// Delete disconnected nodes
list < CNode * > vNodesDisconnectedCopy = vNodesDisconnected ;
BOOST_FOREACH ( CNode * pnode , vNodesDisconnectedCopy )
{
// wait until threads are done using it
if ( pnode - > GetRefCount ( ) < = 0 )
{
bool fDelete = false ;
{
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
if ( lockSend )
{
TRY_LOCK ( pnode - > cs_vRecv , lockRecv ) ;
if ( lockRecv )
{
TRY_LOCK ( pnode - > cs_inventory , lockInv ) ;
if ( lockInv )
fDelete = true ;
}
}
}
if ( fDelete )
{
vNodesDisconnected . remove ( pnode ) ;
delete pnode ;
}
}
}
}
if ( vNodes . size ( ) ! = nPrevNodeCount )
{
nPrevNodeCount = vNodes . size ( ) ;
uiInterface . NotifyNumConnectionsChanged ( vNodes . size ( ) ) ;
}
//
// 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 ;
bool have_fds = false ;
BOOST_FOREACH ( SOCKET hListenSocket , vhListenSocket ) {
FD_SET ( hListenSocket , & fdsetRecv ) ;
hSocketMax = max ( hSocketMax , hListenSocket ) ;
have_fds = true ;
}
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
{
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
FD_SET ( pnode - > hSocket , & fdsetRecv ) ;
FD_SET ( pnode - > hSocket , & fdsetError ) ;
hSocketMax = max ( hSocketMax , pnode - > hSocket ) ;
have_fds = true ;
{
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
if ( lockSend & & ! pnode - > vSend . empty ( ) )
FD_SET ( pnode - > hSocket , & fdsetSend ) ;
}
}
}
vnThreadsRunning [ THREAD_SOCKETHANDLER ] - - ;
int nSelect = select ( have_fds ? hSocketMax + 1 : 0 ,
& fdsetRecv , & fdsetSend , & fdsetError , & timeout ) ;
vnThreadsRunning [ THREAD_SOCKETHANDLER ] + + ;
if ( fShutdown )
return ;
if ( nSelect = = SOCKET_ERROR )
{
if ( have_fds )
{
int nErr = WSAGetLastError ( ) ;
printf ( " socket select error %d \n " , nErr ) ;
for ( unsigned int i = 0 ; i < = hSocketMax ; i + + )
FD_SET ( i , & fdsetRecv ) ;
}
FD_ZERO ( & fdsetSend ) ;
FD_ZERO ( & fdsetError ) ;
Sleep ( timeout . tv_usec / 1000 ) ;
}
//
// Accept new connections
//
BOOST_FOREACH ( SOCKET hListenSocket , vhListenSocket )
if ( hListenSocket ! = INVALID_SOCKET & & FD_ISSET ( hListenSocket , & fdsetRecv ) )
{
# ifdef USE_IPV6
struct sockaddr_storage sockaddr ;
# else
struct sockaddr sockaddr ;
# endif
socklen_t len = sizeof ( sockaddr ) ;
SOCKET hSocket = accept ( hListenSocket , ( struct sockaddr * ) & sockaddr , & len ) ;
CAddress addr ;
int nInbound = 0 ;
if ( hSocket ! = INVALID_SOCKET )
if ( ! addr . SetSockAddr ( ( const struct sockaddr * ) & sockaddr ) )
printf ( " Warning: Unknown socket family \n " ) ;
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( pnode - > fInbound )
nInbound + + ;
}
if ( hSocket = = INVALID_SOCKET )
{
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK )
printf ( " socket error accept failed: %d \n " , nErr ) ;
}
else if ( nInbound > = GetArg ( " -maxconnections " , 125 ) - MAX_OUTBOUND_CONNECTIONS )
{
{
LOCK ( cs_setservAddNodeAddresses ) ;
if ( ! setservAddNodeAddresses . count ( addr ) )
closesocket ( hSocket ) ;
}
}
else if ( CNode : : IsBanned ( addr ) )
{
printf ( " connection from %s dropped (banned) \n " , addr . ToString ( ) . c_str ( ) ) ;
closesocket ( hSocket ) ;
}
else
{
printf ( " accepted connection %s \n " , addr . ToString ( ) . c_str ( ) ) ;
CNode * pnode = new CNode ( hSocket , addr , " " , true ) ;
pnode - > AddRef ( ) ;
{
LOCK ( cs_vNodes ) ;
vNodes . push_back ( pnode ) ;
}
}
}
//
// Service each socket
//
vector < CNode * > vNodesCopy ;
{
LOCK ( cs_vNodes ) ;
vNodesCopy = vNodes ;
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
pnode - > AddRef ( ) ;
}
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
{
if ( fShutdown )
return ;
//
// Receive
//
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
if ( FD_ISSET ( pnode - > hSocket , & fdsetRecv ) | | FD_ISSET ( pnode - > hSocket , & fdsetError ) )
{
TRY_LOCK ( pnode - > cs_vRecv , lockRecv ) ;
if ( lockRecv )
{
CDataStream & vRecv = pnode - > vRecv ;
unsigned int nPos = vRecv . size ( ) ;
if ( nPos > ReceiveBufferSize ( ) ) {
if ( ! pnode - > fDisconnect )
printf ( " socket recv flood control disconnect (% " PRIszu " bytes) \n " , vRecv . size ( ) ) ;
pnode - > CloseSocketDisconnect ( ) ;
}
else {
// typical socket buffer is 8K-64K
char pchBuf [ 0x10000 ] ;
int nBytes = recv ( pnode - > hSocket , pchBuf , sizeof ( pchBuf ) , MSG_DONTWAIT ) ;
if ( nBytes > 0 )
{
vRecv . resize ( nPos + nBytes ) ;
memcpy ( & vRecv [ nPos ] , pchBuf , nBytes ) ;
pnode - > nLastRecv = GetTime ( ) ;
}
else if ( nBytes = = 0 )
{
// socket closed gracefully
if ( ! pnode - > fDisconnect )
printf ( " socket closed \n " ) ;
pnode - > CloseSocketDisconnect ( ) ;
}
else if ( nBytes < 0 )
{
// error
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS )
{
if ( ! pnode - > fDisconnect )
printf ( " socket recv error %d \n " , nErr ) ;
pnode - > CloseSocketDisconnect ( ) ;
}
}
}
}
}
//
// Send
//
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
if ( FD_ISSET ( pnode - > hSocket , & fdsetSend ) )
{
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
if ( lockSend )
{
CDataStream & vSend = pnode - > vSend ;
if ( ! vSend . empty ( ) )
{
int nBytes = send ( pnode - > hSocket , & vSend [ 0 ] , vSend . size ( ) , MSG_NOSIGNAL | MSG_DONTWAIT ) ;
if ( nBytes > 0 )
{
vSend . erase ( vSend . begin ( ) , vSend . begin ( ) + nBytes ) ;
pnode - > nLastSend = GetTime ( ) ;
}
else if ( nBytes < 0 )
{
// error
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS )
{
printf ( " socket send error %d \n " , nErr ) ;
pnode - > CloseSocketDisconnect ( ) ;
}
}
}
}
}
//
// Inactivity checking
//
if ( pnode - > vSend . empty ( ) )
pnode - > nLastSendEmpty = GetTime ( ) ;
if ( GetTime ( ) - pnode - > nTimeConnected > 60 )
{
if ( pnode - > nLastRecv = = 0 | | pnode - > nLastSend = = 0 )
{
printf ( " socket no message in first 60 seconds, %d %d \n " , pnode - > nLastRecv ! = 0 , pnode - > nLastSend ! = 0 ) ;
pnode - > fDisconnect = true ;
}
else if ( GetTime ( ) - pnode - > nLastSend > 90 * 60 & & GetTime ( ) - pnode - > nLastSendEmpty > 90 * 60 )
{
printf ( " socket not sending \n " ) ;
pnode - > fDisconnect = true ;
}
else if ( GetTime ( ) - pnode - > nLastRecv > 90 * 60 )
{
printf ( " socket inactivity timeout \n " ) ;
pnode - > fDisconnect = true ;
}
}
}
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
pnode - > Release ( ) ;
}
Sleep ( 10 ) ;
}
}
# ifdef USE_UPNP
void ThreadMapPort ( void * parg )
{
// Make this thread recognisable as the UPnP thread
RenameThread ( " bitcoin-UPnP " ) ;
try
{
vnThreadsRunning [ THREAD_UPNP ] + + ;
ThreadMapPort2 ( parg ) ;
vnThreadsRunning [ THREAD_UPNP ] - - ;
}
catch ( std : : exception & e ) {
vnThreadsRunning [ THREAD_UPNP ] - - ;
PrintException ( & e , " ThreadMapPort() " ) ;
} catch ( . . . ) {
vnThreadsRunning [ THREAD_UPNP ] - - ;
PrintException ( NULL , " ThreadMapPort() " ) ;
}
printf ( " ThreadMapPort exited \n " ) ;
}
void ThreadMapPort2 ( void * parg )
{
printf ( " ThreadMapPort started \n " ) ;
std : : string port = strprintf ( " %u " , GetListenPort ( ) ) ;
const char * multicastif = 0 ;
const char * minissdpdpath = 0 ;
struct UPNPDev * devlist = 0 ;
char lanaddr [ 64 ] ;
# ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 ) ;
# else
/* miniupnpc 1.6 */
int error = 0 ;
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 , 0 , & error ) ;
# endif
struct UPNPUrls urls ;
struct IGDdatas data ;
int r ;
r = UPNP_GetValidIGD ( devlist , & urls , & data , lanaddr , sizeof ( lanaddr ) ) ;
if ( r = = 1 )
{
if ( fDiscover ) {
char externalIPAddress [ 40 ] ;
r = UPNP_GetExternalIPAddress ( urls . controlURL , data . first . servicetype , externalIPAddress ) ;
if ( r ! = UPNPCOMMAND_SUCCESS )
printf ( " UPnP: GetExternalIPAddress() returned %d \n " , r ) ;
else
{
if ( externalIPAddress [ 0 ] )
{
printf ( " UPnP: ExternalIPAddress = %s \n " , externalIPAddress ) ;
AddLocal ( CNetAddr ( externalIPAddress ) , LOCAL_UPNP ) ;
}
else
printf ( " UPnP: GetExternalIPAddress failed. \n " ) ;
}
}
string strDesc = " Bitcoin " + FormatFullVersion ( ) ;
# ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
r = UPNP_AddPortMapping ( urls . controlURL , data . first . servicetype ,
port . c_str ( ) , port . c_str ( ) , lanaddr , strDesc . c_str ( ) , " TCP " , 0 ) ;
# else
/* miniupnpc 1.6 */
r = UPNP_AddPortMapping ( urls . controlURL , data . first . servicetype ,
port . c_str ( ) , port . c_str ( ) , lanaddr , strDesc . c_str ( ) , " TCP " , 0 , " 0 " ) ;
# endif
if ( r ! = UPNPCOMMAND_SUCCESS )
printf ( " AddPortMapping(%s, %s, %s) failed with code %d (%s) \n " ,
port . c_str ( ) , port . c_str ( ) , lanaddr , r , strupnperror ( r ) ) ;
else
printf ( " UPnP Port Mapping successful. \n " ) ;
int i = 1 ;
loop {
if ( fShutdown | | ! fUseUPnP )
{
r = UPNP_DeletePortMapping ( urls . controlURL , data . first . servicetype , port . c_str ( ) , " TCP " , 0 ) ;
printf ( " UPNP_DeletePortMapping() returned : %d \n " , r ) ;
freeUPNPDevlist ( devlist ) ; devlist = 0 ;
FreeUPNPUrls ( & urls ) ;
return ;
}
if ( i % 600 = = 0 ) // Refresh every 20 minutes
{
# ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
r = UPNP_AddPortMapping ( urls . controlURL , data . first . servicetype ,
port . c_str ( ) , port . c_str ( ) , lanaddr , strDesc . c_str ( ) , " TCP " , 0 ) ;
# else
/* miniupnpc 1.6 */
r = UPNP_AddPortMapping ( urls . controlURL , data . first . servicetype ,
port . c_str ( ) , port . c_str ( ) , lanaddr , strDesc . c_str ( ) , " TCP " , 0 , " 0 " ) ;
# endif
if ( r ! = UPNPCOMMAND_SUCCESS )
printf ( " AddPortMapping(%s, %s, %s) failed with code %d (%s) \n " ,
port . c_str ( ) , port . c_str ( ) , lanaddr , r , strupnperror ( r ) ) ;
else
printf ( " UPnP Port Mapping successful. \n " ) ; ;
}
Sleep ( 2000 ) ;
i + + ;
}
} else {
printf ( " No valid UPnP IGDs found \n " ) ;
freeUPNPDevlist ( devlist ) ; devlist = 0 ;
if ( r ! = 0 )
FreeUPNPUrls ( & urls ) ;
loop {
if ( fShutdown | | ! fUseUPnP )
return ;
Sleep ( 2000 ) ;
}
}
}
void MapPort ( )
{
if ( fUseUPnP & & vnThreadsRunning [ THREAD_UPNP ] < 1 )
{
if ( ! NewThread ( ThreadMapPort , NULL ) )
printf ( " Error: ThreadMapPort(ThreadMapPort) failed \n " ) ;
}
}
# else
void MapPort ( )
{
// Intentionally left blank.
}
# endif
// DNS seeds
// Each pair gives a source name and a seed name.
// The first name is used as information source for addrman.
// The second name should resolve to a list of seed addresses.
static const char * strDNSSeed [ ] [ 2 ] = {
{ " bitcoin.sipa.be " , " seed.bitcoin.sipa.be " } ,
{ " bluematt.me " , " dnsseed.bluematt.me " } ,
{ " dashjr.org " , " dnsseed.bitcoin.dashjr.org " } ,
{ " xf2.org " , " bitseed.xf2.org " } ,
} ;
void ThreadDNSAddressSeed ( void * parg )
{
// Make this thread recognisable as the DNS seeding thread
RenameThread ( " bitcoin-dnsseed " ) ;
try
{
vnThreadsRunning [ THREAD_DNSSEED ] + + ;
ThreadDNSAddressSeed2 ( parg ) ;
vnThreadsRunning [ THREAD_DNSSEED ] - - ;
}
catch ( std : : exception & e ) {
vnThreadsRunning [ THREAD_DNSSEED ] - - ;
PrintException ( & e , " ThreadDNSAddressSeed() " ) ;
} catch ( . . . ) {
vnThreadsRunning [ THREAD_DNSSEED ] - - ;
throw ; // support pthread_cancel()
}
printf ( " ThreadDNSAddressSeed exited \n " ) ;
}
void ThreadDNSAddressSeed2 ( void * parg )
{
printf ( " ThreadDNSAddressSeed started \n " ) ;
int found = 0 ;
if ( ! fTestNet )
{
printf ( " Loading addresses from DNS seeds (could take a while) \n " ) ;
for ( unsigned int seed_idx = 0 ; seed_idx < ARRAYLEN ( strDNSSeed ) ; seed_idx + + ) {
if ( HaveNameProxy ( ) ) {
AddOneShot ( strDNSSeed [ seed_idx ] [ 1 ] ) ;
} else {
vector < CNetAddr > vaddr ;
vector < CAddress > vAdd ;
if ( LookupHost ( strDNSSeed [ seed_idx ] [ 1 ] , vaddr ) )
{
BOOST_FOREACH ( CNetAddr & ip , vaddr )
{
int nOneDay = 24 * 3600 ;
CAddress addr = CAddress ( CService ( ip , GetDefaultPort ( ) ) ) ;
addr . nTime = GetTime ( ) - 3 * nOneDay - GetRand ( 4 * nOneDay ) ; // use a random age between 3 and 7 days old
vAdd . push_back ( addr ) ;
found + + ;
}
}
addrman . Add ( vAdd , CNetAddr ( strDNSSeed [ seed_idx ] [ 0 ] , true ) ) ;
}
}
}
printf ( " %d addresses found from DNS seeds \n " , found ) ;
}
unsigned int pnSeed [ ] =
{
0x959bd347 , 0xf8de42b2 , 0x73bc0518 , 0xea6edc50 , 0x21b00a4d , 0xc725b43d , 0xd665464d , 0x1a2a770e ,
0x27c93946 , 0x65b2fa46 , 0xb80ae255 , 0x66b3b446 , 0xb1877a3e , 0x6ee89e3e , 0xc3175b40 , 0x2a01a83c ,
0x95b1363a , 0xa079ad3d , 0xe6ca801f , 0x027f4f4a , 0x34f7f03a , 0xf790f04a , 0x16ca801f , 0x2f4d5e40 ,
0x3a4d5e40 , 0xc43a322e , 0xc8159753 , 0x14d4724c , 0x7919a118 , 0xe0bdb34e , 0x68a16b2e , 0xff64b44d ,
0x6099115b , 0x9b57b05b , 0x7bd1b4ad , 0xdf95944f , 0x29d2b73d , 0xafa8db79 , 0xe247ba41 , 0x24078348 ,
0xf722f03c , 0x33567ebc , 0xace64ed4 , 0x984d3932 , 0xb5f34e55 , 0x27b7024d , 0x94579247 , 0x8894042e ,
0x9357d34c , 0x1063c24b , 0xcaa228b1 , 0xa3c5a8b2 , 0x5dc64857 , 0xa2c23643 , 0xa8369a54 , 0x31203077 ,
0x00707c5c , 0x09fc0b3a , 0x272e9e2e , 0xf80f043e , 0x9449ca3e , 0x5512c33e , 0xd106b555 , 0xe8024157 ,
0xe288ec29 , 0xc79c5461 , 0xafb63932 , 0xdb02ab4b , 0x0e512777 , 0x8a145a4c , 0xb201ff4f , 0x5e09314b ,
0xcd9bfbcd , 0x1c023765 , 0x4394e75c , 0xa728bd4d , 0x65331552 , 0xa98420b1 , 0x89ecf559 , 0x6e80801f ,
0xf404f118 , 0xefd62b51 , 0x05918346 , 0x9b186d5f , 0xacabab46 , 0xf912e255 , 0xc188ea62 , 0xcc55734e ,
0xc668064d , 0xd77a4558 , 0x46201c55 , 0xf17dfc80 , 0xf7142f2e , 0x87bfb718 , 0x8aa54fb2 , 0xc451d518 ,
0xc4ae8831 , 0x8dd44d55 , 0x5bbd206c , 0x64536b5d , 0x5c667e60 , 0x3b064242 , 0xfe963a42 , 0xa28e6dc8 ,
0xe8a9604a , 0xc989464e , 0xd124a659 , 0x50065140 , 0xa44dfe5e , 0x1079e655 , 0x3fb986d5 , 0x47895b18 ,
0x7d3ce4ad , 0x4561ba50 , 0x296eec62 , 0x255b41ad , 0xaed35ec9 , 0x55556f12 , 0xc7d3154d , 0x3297b65d ,
0x8930121f , 0xabf42e4e , 0x4a29e044 , 0x1212685d , 0x676c1e40 , 0xce009744 , 0x383a8948 , 0xa2dbd0ad ,
0xecc2564d , 0x07dbc252 , 0x887ee24b , 0x5171644c , 0x6bb798c1 , 0x847f495d , 0x4cbb7145 , 0x3bb81c32 ,
0x45eb262e , 0xc8015a4e , 0x250a361b , 0xf694f946 , 0xd64a183e , 0xd4f1dd59 , 0x8f20ffd4 , 0x51d9e55c ,
0x09521763 , 0x5e02002e , 0x32c8074d , 0xe685762e , 0x8290b0bc , 0x762a922e , 0xfc5ee754 , 0x83a24829 ,
0x775b224d , 0x6295bb4d , 0x38ec0555 , 0xbffbba50 , 0xe5560260 , 0x86b16a7c , 0xd372234e , 0x49a3c24b ,
0x2f6a171f , 0x4d75ed60 , 0xae94115b , 0xcb543744 , 0x63080c59 , 0x3f9c724c , 0xc977ce18 , 0x532efb18 ,
0x69dc3b2e , 0x5f94d929 , 0x1732bb4d , 0x9c814b4d , 0xe6b3762e , 0xc024f662 , 0x8face35b , 0x6b5b044d ,
0x798c7b57 , 0x79a6b44c , 0x067d3057 , 0xf9e94e5f , 0x91cbe15b , 0x71405eb2 , 0x2662234e , 0xcbcc4a6d ,
0xbf69d54b , 0xa79b4e55 , 0xec6d3e51 , 0x7c0b3c02 , 0x60f83653 , 0x24c1e15c , 0x1110b62e , 0x10350f59 ,
0xa56f1d55 , 0x3509e7a9 , 0xeb128354 , 0x14268e2e , 0x934e28bc , 0x8e32692e , 0x8331a21f , 0x3e633932 ,
0xc812b12e , 0xc684bf2e , 0x80112d2e , 0xe0ddc96c , 0xc630ca4a , 0x5c09b3b2 , 0x0b580518 , 0xc8e9d54b ,
0xd169aa43 , 0x17d0d655 , 0x1d029963 , 0x7ff87559 , 0xcb701f1f , 0x6fa3e85d , 0xe45e9a54 , 0xf05d1802 ,
0x44d03b2e , 0x837b692e , 0xccd4354e , 0x3d6da13c , 0x3423084d , 0xf707c34a , 0x55f6db3a , 0xad26e442 ,
0x6233a21f , 0x09e80e59 , 0x8caeb54d , 0xbe870941 , 0xb407d20e , 0x20b51018 , 0x56fb152e , 0x460d2a4e ,
0xbb9a2946 , 0x560eb12e , 0xed83dd29 , 0xd6724f53 , 0xa50aafb8 , 0x451346d9 , 0x88348e2e , 0x7312fead ,
0x8ecaf96f , 0x1bda4e5f , 0xf1671e40 , 0x3c8c3e3b , 0x4716324d , 0xdde24ede , 0xf98cd17d , 0xa91d4644 ,
0x28124eb2 , 0x147d5129 , 0xd022042e , 0x61733d3b , 0xad0d5e02 , 0x8ce2932e , 0xe5c18502 , 0x549c1e32 ,
0x9685801f , 0x86e217ad , 0xd948214b , 0x4110f462 , 0x3a2e894e , 0xbd35492e , 0x87e0d558 , 0x64b8ef7d ,
0x7c3eb962 , 0x72a84b3e , 0x7cd667c9 , 0x28370a2e , 0x4bc60e7b , 0x6fc1ec60 , 0x14a6983f , 0x86739a4b ,
0x46954e5f , 0x32e2e15c , 0x2e9326cf , 0xe5801c5e , 0x379607b2 , 0x32151145 , 0xf0e39744 , 0xacb54c55 ,
0xa37dfb60 , 0x83b55cc9 , 0x388f7ca5 , 0x15034f5f , 0x3e94965b , 0x68e0ffad , 0x35280f59 , 0x8fe190cf ,
0x7c6ba5b2 , 0xa5e9db43 , 0x4ee1fc60 , 0xd9d94e5f , 0x04040677 , 0x0ea9b35e , 0x5961f14f , 0x67fda063 ,
0xa48a5a31 , 0xc6524e55 , 0x283d325e , 0x3f37515f , 0x96b94b3e , 0xacce620e , 0x6481cc5b , 0xa4a06d4b ,
0x9e95d2d9 , 0xe40c03d5 , 0xc2f4514b , 0xb79aad44 , 0xf64be843 , 0xb2064070 , 0xfca00455 , 0x429dfa4e ,
0x2323f173 , 0xeda4185e , 0xabd5227d , 0x9efd4d58 , 0xb1104758 , 0x4811e955 , 0xbd9ab355 , 0xe921f44b ,
0x9f166dce , 0x09e279b2 , 0xe0c9ac7b , 0x7901a5ad , 0xa145d4b0 , 0x79104671 , 0xec31e35a , 0x4fe0b555 ,
0xc7d9cbad , 0xad057f55 , 0xe94cc759 , 0x7fe0b043 , 0xe4529f2e , 0x0d4dd4b2 , 0x9f11a54d , 0x031e2e4e ,
0xe6014f5f , 0x11d1ca6c , 0x26bd7f61 , 0xeb86854f , 0x4d347b57 , 0x116bbe2e , 0xdba7234e , 0x7bcbfd2e ,
0x174dd4b2 , 0x6686762e , 0xb089ba50 , 0xc6258246 , 0x087e767b , 0xc4a8cb4a , 0x595dba50 , 0x7f0ae502 ,
0x7b1dbd5a , 0xa0603492 , 0x57d1af4b , 0x9e21ffd4 , 0x6393064d , 0x7407376e , 0xe484762e , 0x122a4e53 ,
0x4a37aa43 , 0x3888a6be , 0xee77864e , 0x039c8dd5 , 0x688d89af , 0x0e988f62 , 0x08218246 , 0xfc2f8246 ,
0xd1d97040 , 0xd64cd4b2 , 0x5ae4a6b8 , 0x7d0de9bc , 0x8d304d61 , 0x06c5c672 , 0xa4c8bd4d , 0xe0fd373b ,
0x575ebe4d , 0x72d26277 , 0x55570f55 , 0x77b154d9 , 0xe214293a , 0xfc740f4b , 0xfe3f6a57 , 0xa9c55f02 ,
0xae4054db , 0x2394d918 , 0xb511b24a , 0xb8741ab2 , 0x0758e65e , 0xc7b5795b , 0xb0a30a4c , 0xaf7f170c ,
0xf3b4762e , 0x8179576d , 0x738a1581 , 0x4b95b64c , 0x9829b618 , 0x1bea932e , 0x7bdeaa4b , 0xcb5e0281 ,
0x65618f54 , 0x0658474b , 0x27066acf , 0x40556d65 , 0x7d204d53 , 0xf28bc244 , 0xdce23455 , 0xadc0ff54 ,
0x3863c948 , 0xcee34e5f , 0xdeb85e02 , 0x2ed17a61 , 0x6a7b094d , 0x7f0cfc40 , 0x59603f54 , 0x3220afbc ,
0xb5dfd962 , 0x125d21c0 , 0x13f8d243 , 0xacfefb4e , 0x86c2c147 , 0x3d8bbd59 , 0xbd02a21f , 0x2593042e ,
0xc6a17a7c , 0x28925861 , 0xb487ed44 , 0xb5f4fd6d , 0x90c28a45 , 0x5a14f74d , 0x43d71b4c , 0x728ebb5d ,
0x885bf950 , 0x08134dd0 , 0x38ec046e , 0xc575684b , 0x50082d2e , 0xa2f47757 , 0x270f86ae , 0xf3ff6462 ,
0x10ed3f4e , 0x4b58d462 , 0xe01ce23e , 0x8c5b092e , 0x63e52f4e , 0x22c1e85d , 0xa908f54e , 0x8591624f ,
0x2c0fb94e , 0xa280ba3c , 0xb6f41b4c , 0x24f9aa47 , 0x27201647 , 0x3a3ea6dc , 0xa14fc3be , 0x3c34bdd5 ,
0x5b8d4f5b , 0xaadeaf4b , 0xc71cab50 , 0x15697a4c , 0x9a1a734c , 0x2a037d81 , 0x2590bd59 , 0x48ec2741 ,
0x53489c5b , 0x7f00314b , 0x2170d362 , 0xf2e92542 , 0x42c10b44 , 0x98f0f118 , 0x883a3456 , 0x099a932e ,
0xea38f7bc , 0x644e9247 , 0xbb61b62e , 0x30e0863d , 0x5f51be54 , 0x207215c7 , 0x5f306c45 , 0xaa7f3932 ,
0x98da7d45 , 0x4e339b59 , 0x2e411581 , 0xa808f618 , 0xad2c0c59 , 0x54476741 , 0x09e99fd1 , 0x5db8f752 ,
0xc16df8bd , 0x1dd4b44f , 0x106edf2e , 0x9e15c180 , 0x2ad6b56f , 0x633a5332 , 0xff33787c , 0x077cb545 ,
0x6610be6d , 0x75aad2c4 , 0x72fb4d5b , 0xe81e0f59 , 0x576f6332 , 0x47333373 , 0x351ed783 , 0x2d90fb50 ,
0x8d5e0f6c , 0x5b27a552 , 0xdb293ebb , 0xe55ef950 , 0x4b133ad8 , 0x75df975a , 0x7b6a8740 , 0xa899464b ,
0xfab15161 , 0x10f8b64d , 0xd055ea4d , 0xee8e146b , 0x4b14afb8 , 0x4bc1c44a , 0x9b961dcc , 0xd111ff43 ,
0xfca0b745 , 0xc800e412 , 0x0afad9d1 , 0xf751c350 , 0xf9f0cccf , 0xa290a545 , 0x8ef13763 , 0x7ec70d59 ,
0x2b066acf , 0x65496c45 , 0xade02c1b , 0xae6eb077 , 0x92c1e65b , 0xc064e6a9 , 0xc649e56d , 0x5287a243 ,
0x36de4f5b , 0x5b1df6ad , 0x65c39a59 , 0xdba805b2 , 0x20067aa8 , 0x6457e56d , 0x3cee26cf , 0xfd3ff26d ,
0x04f86d4a , 0x06b8e048 , 0xa93bcd5c , 0x91135852 , 0xbe90a643 , 0x8fa0094d , 0x06d8215f , 0x2677094d ,
0xd735685c , 0x164a00c9 , 0x5209ac5f , 0xa9564c5c , 0x3b504f5f , 0xcc826bd0 , 0x4615042e , 0x5fe13b4a ,
0x8c81b86d , 0x879ab68c , 0x1de564b8 , 0x434487d8 , 0x2dcb1b63 , 0x82ab524a , 0xb0676abb , 0xa13d9c62 ,
0xdbb5b86d , 0x5b7f4b59 , 0xaddfb44d , 0xad773532 , 0x3997054c , 0x72cebd89 , 0xb194544c , 0xc5b8046e ,
0x6e1adeb2 , 0xaa5abb51 , 0xefb54b44 , 0x15efc54f , 0xe9f1bc4d , 0x5f401b6c , 0x97f018ad , 0xc82f9252 ,
0x2cdc762e , 0x8e52e56d , 0x1827175e , 0x9b7d7d80 , 0xb2ad6845 , 0x51065140 , 0x71180a18 , 0x5b27006c ,
0x0621e255 , 0x721cbe58 , 0x670c0cb8 , 0xf8bd715d , 0xe0bdc5d9 , 0xed843501 , 0x4b84554d , 0x7f1a18bc ,
0x53bcaf47 , 0x5729d35f , 0xf0dda246 , 0x22382bd0 , 0x4d641fb0 , 0x316afcde , 0x50a22f1f , 0x73608046 ,
0xc461d84a , 0xb2dbe247 ,
} ;
void DumpAddresses ( )
{
int64 nStart = GetTimeMillis ( ) ;
CAddrDB adb ;
adb . Write ( addrman ) ;
printf ( " Flushed %d addresses to peers.dat % " PRI64d " ms \n " ,
addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
}
void ThreadDumpAddress2 ( void * parg )
{
printf ( " ThreadDumpAddress started \n " ) ;
vnThreadsRunning [ THREAD_DUMPADDRESS ] + + ;
while ( ! fShutdown )
{
DumpAddresses ( ) ;
vnThreadsRunning [ THREAD_DUMPADDRESS ] - - ;
Sleep ( 100000 ) ;
vnThreadsRunning [ THREAD_DUMPADDRESS ] + + ;
}
vnThreadsRunning [ THREAD_DUMPADDRESS ] - - ;
}
void ThreadDumpAddress ( void * parg )
{
// Make this thread recognisable as the address dumping thread
RenameThread ( " bitcoin-adrdump " ) ;
try
{
ThreadDumpAddress2 ( parg ) ;
}
catch ( std : : exception & e ) {
PrintException ( & e , " ThreadDumpAddress() " ) ;
}
printf ( " ThreadDumpAddress exited \n " ) ;
}
void ThreadOpenConnections ( void * parg )
{
// Make this thread recognisable as the connection opening thread
RenameThread ( " bitcoin-opencon " ) ;
try
{
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] + + ;
ThreadOpenConnections2 ( parg ) ;
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] - - ;
}
catch ( std : : exception & e ) {
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] - - ;
PrintException ( & e , " ThreadOpenConnections() " ) ;
} catch ( . . . ) {
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] - - ;
PrintException ( NULL , " ThreadOpenConnections() " ) ;
}
printf ( " ThreadOpenConnections exited \n " ) ;
}
void static ProcessOneShot ( )
{
string strDest ;
{
LOCK ( cs_vOneShots ) ;
if ( vOneShots . empty ( ) )
return ;
strDest = vOneShots . front ( ) ;
vOneShots . pop_front ( ) ;
}
CAddress addr ;
CSemaphoreGrant grant ( * semOutbound , true ) ;
if ( grant ) {
if ( ! OpenNetworkConnection ( addr , & grant , strDest . c_str ( ) , true ) )
AddOneShot ( strDest ) ;
}
}
void ThreadOpenConnections2 ( void * parg )
{
printf ( " ThreadOpenConnections started \n " ) ;
// Connect to specific addresses
if ( mapArgs . count ( " -connect " ) & & mapMultiArgs [ " -connect " ] . size ( ) > 0 )
{
for ( int64 nLoop = 0 ; ; nLoop + + )
{
ProcessOneShot ( ) ;
BOOST_FOREACH ( string strAddr , mapMultiArgs [ " -connect " ] )
{
CAddress addr ;
OpenNetworkConnection ( addr , NULL , strAddr . c_str ( ) ) ;
for ( int i = 0 ; i < 10 & & i < nLoop ; i + + )
{
Sleep ( 500 ) ;
if ( fShutdown )
return ;
}
}
Sleep ( 500 ) ;
}
}
// Initiate network connections
int64 nStart = GetTime ( ) ;
loop
{
ProcessOneShot ( ) ;
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] - - ;
Sleep ( 500 ) ;
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] + + ;
if ( fShutdown )
return ;
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] - - ;
CSemaphoreGrant grant ( * semOutbound ) ;
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] + + ;
if ( fShutdown )
return ;
// Add seed nodes if IRC isn't working
if ( addrman . size ( ) = = 0 & & ( GetTime ( ) - nStart > 60 ) & & ! fTestNet )
{
std : : vector < CAddress > vAdd ;
for ( unsigned int i = 0 ; i < ARRAYLEN ( pnSeed ) ; i + + )
{
// 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 nOneWeek = 7 * 24 * 60 * 60 ;
struct in_addr ip ;
memcpy ( & ip , & pnSeed [ i ] , sizeof ( ip ) ) ;
CAddress addr ( CService ( ip , GetDefaultPort ( ) ) ) ;
addr . nTime = GetTime ( ) - GetRand ( nOneWeek ) - nOneWeek ;
vAdd . push_back ( addr ) ;
}
addrman . Add ( vAdd , CNetAddr ( " 127.0.0.1 " ) ) ;
}
//
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect ;
// Only connect out to one peer per network group (/16 for IPv4).
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
int nOutbound = 0 ;
set < vector < unsigned char > > setConnected ;
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes ) {
if ( ! pnode - > fInbound ) {
setConnected . insert ( pnode - > addr . GetGroup ( ) ) ;
nOutbound + + ;
}
}
}
int64 nANow = GetAdjustedTime ( ) ;
int nTries = 0 ;
loop
{
// use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
CAddress addr = addrman . Select ( 10 + min ( nOutbound , 8 ) * 10 ) ;
// if we selected an invalid address, restart
if ( ! addr . IsValid ( ) | | setConnected . count ( addr . GetGroup ( ) ) | | IsLocal ( addr ) )
break ;
// 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.
nTries + + ;
if ( nTries > 100 )
break ;
if ( IsLimited ( addr ) )
continue ;
// only consider very recently tried nodes after 30 failed attempts
if ( nANow - addr . nLastTry < 600 & & nTries < 30 )
continue ;
// do not allow non-default ports, unless after 50 invalid addresses selected already
if ( addr . GetPort ( ) ! = GetDefaultPort ( ) & & nTries < 50 )
continue ;
addrConnect = addr ;
break ;
}
if ( addrConnect . IsValid ( ) )
OpenNetworkConnection ( addrConnect , & grant ) ;
}
}
void ThreadOpenAddedConnections ( void * parg )
{
// Make this thread recognisable as the connection opening thread
RenameThread ( " bitcoin-opencon " ) ;
try
{
vnThreadsRunning [ THREAD_ADDEDCONNECTIONS ] + + ;
ThreadOpenAddedConnections2 ( parg ) ;
vnThreadsRunning [ THREAD_ADDEDCONNECTIONS ] - - ;
}
catch ( std : : exception & e ) {
vnThreadsRunning [ THREAD_ADDEDCONNECTIONS ] - - ;
PrintException ( & e , " ThreadOpenAddedConnections() " ) ;
} catch ( . . . ) {
vnThreadsRunning [ THREAD_ADDEDCONNECTIONS ] - - ;
PrintException ( NULL , " ThreadOpenAddedConnections() " ) ;
}
printf ( " ThreadOpenAddedConnections exited \n " ) ;
}
void ThreadOpenAddedConnections2 ( void * parg )
{
printf ( " ThreadOpenAddedConnections started \n " ) ;
{
LOCK ( cs_vAddedNodes ) ;
vAddedNodes = mapMultiArgs [ " -addnode " ] ;
}
if ( HaveNameProxy ( ) ) {
while ( ! fShutdown ) {
list < string > lAddresses ( 0 ) ;
{
LOCK ( cs_vAddedNodes ) ;
BOOST_FOREACH ( string & strAddNode , vAddedNodes )
lAddresses . push_back ( strAddNode ) ;
}
BOOST_FOREACH ( string & strAddNode , lAddresses ) {
CAddress addr ;
CSemaphoreGrant grant ( * semOutbound ) ;
OpenNetworkConnection ( addr , & grant , strAddNode . c_str ( ) ) ;
Sleep ( 500 ) ;
if ( fShutdown )
return ;
}
vnThreadsRunning [ THREAD_ADDEDCONNECTIONS ] - - ;
Sleep ( 120000 ) ; // Retry every 2 minutes
vnThreadsRunning [ THREAD_ADDEDCONNECTIONS ] + + ;
}
return ;
}
loop
{
list < string > lAddresses ( 0 ) ;
{
LOCK ( cs_vAddedNodes ) ;
BOOST_FOREACH ( string & strAddNode , vAddedNodes )
lAddresses . push_back ( strAddNode ) ;
}
list < vector < CService > > lservAddressesToAdd ( 0 ) ;
BOOST_FOREACH ( string & strAddNode , lAddresses )
{
vector < CService > vservNode ( 0 ) ;
if ( Lookup ( strAddNode . c_str ( ) , vservNode , GetDefaultPort ( ) , fNameLookup , 0 ) )
{
lservAddressesToAdd . push_back ( vservNode ) ;
{
LOCK ( cs_setservAddNodeAddresses ) ;
BOOST_FOREACH ( CService & serv , vservNode )
setservAddNodeAddresses . insert ( serv ) ;
}
}
}
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
// (keeping in mind that addnode entries can have many IPs if fNameLookup)
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
for ( list < vector < CService > > : : iterator it = lservAddressesToAdd . begin ( ) ; it ! = lservAddressesToAdd . end ( ) ; it + + )
BOOST_FOREACH ( CService & addrNode , * ( it ) )
if ( pnode - > addr = = addrNode )
{
it = lservAddressesToAdd . erase ( it ) ;
it - - ;
break ;
}
}
BOOST_FOREACH ( vector < CService > & vserv , lservAddressesToAdd )
{
CSemaphoreGrant grant ( * semOutbound ) ;
OpenNetworkConnection ( CAddress ( * ( vserv . begin ( ) ) ) , & grant ) ;
Sleep ( 500 ) ;
if ( fShutdown )
return ;
}
if ( fShutdown )
return ;
vnThreadsRunning [ THREAD_ADDEDCONNECTIONS ] - - ;
Sleep ( 120000 ) ; // Retry every 2 minutes
vnThreadsRunning [ THREAD_ADDEDCONNECTIONS ] + + ;
if ( fShutdown )
return ;
}
}
// if successful, this moves the passed grant to the constructed node
bool OpenNetworkConnection ( const CAddress & addrConnect , CSemaphoreGrant * grantOutbound , const char * strDest , bool fOneShot )
{
//
// Initiate outbound network connection
//
if ( fShutdown )
return false ;
if ( ! strDest )
if ( IsLocal ( addrConnect ) | |
FindNode ( ( CNetAddr ) addrConnect ) | | CNode : : IsBanned ( addrConnect ) | |
FindNode ( addrConnect . ToStringIPPort ( ) . c_str ( ) ) )
return false ;
if ( strDest & & FindNode ( strDest ) )
return false ;
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] - - ;
CNode * pnode = ConnectNode ( addrConnect , strDest ) ;
vnThreadsRunning [ THREAD_OPENCONNECTIONS ] + + ;
if ( fShutdown )
return false ;
if ( ! pnode )
return false ;
if ( grantOutbound )
grantOutbound - > MoveTo ( pnode - > grantOutbound ) ;
pnode - > fNetworkNode = true ;
if ( fOneShot )
pnode - > fOneShot = true ;
return true ;
}
void ThreadMessageHandler ( void * parg )
{
// Make this thread recognisable as the message handling thread
RenameThread ( " bitcoin-msghand " ) ;
try
{
vnThreadsRunning [ THREAD_MESSAGEHANDLER ] + + ;
ThreadMessageHandler2 ( parg ) ;
vnThreadsRunning [ THREAD_MESSAGEHANDLER ] - - ;
}
catch ( std : : exception & e ) {
vnThreadsRunning [ THREAD_MESSAGEHANDLER ] - - ;
PrintException ( & e , " ThreadMessageHandler() " ) ;
} catch ( . . . ) {
vnThreadsRunning [ THREAD_MESSAGEHANDLER ] - - ;
PrintException ( NULL , " ThreadMessageHandler() " ) ;
}
printf ( " ThreadMessageHandler exited \n " ) ;
}
void ThreadMessageHandler2 ( void * parg )
{
printf ( " ThreadMessageHandler started \n " ) ;
SetThreadPriority ( THREAD_PRIORITY_BELOW_NORMAL ) ;
while ( ! fShutdown )
{
vector < CNode * > vNodesCopy ;
{
LOCK ( cs_vNodes ) ;
vNodesCopy = vNodes ;
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
pnode - > AddRef ( ) ;
}
// Poll the connected nodes for messages
CNode * pnodeTrickle = NULL ;
if ( ! vNodesCopy . empty ( ) )
pnodeTrickle = vNodesCopy [ GetRand ( vNodesCopy . size ( ) ) ] ;
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
{
// Receive messages
{
TRY_LOCK ( pnode - > cs_vRecv , lockRecv ) ;
if ( lockRecv )
ProcessMessages ( pnode ) ;
}
if ( fShutdown )
return ;
// Send messages
{
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
if ( lockSend )
SendMessages ( pnode , pnode = = pnodeTrickle ) ;
}
if ( fShutdown )
return ;
}
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodesCopy )
pnode - > Release ( ) ;
}
// Wait and allow messages to bunch up.
// Reduce vnThreadsRunning so StopNode has permission to exit while
// we're sleeping, but we must always check fShutdown after doing this.
vnThreadsRunning [ THREAD_MESSAGEHANDLER ] - - ;
Sleep ( 100 ) ;
if ( fRequestShutdown )
StartShutdown ( ) ;
vnThreadsRunning [ THREAD_MESSAGEHANDLER ] + + ;
if ( fShutdown )
return ;
}
}
bool BindListenPort ( const CService & addrBind , string & strError )
{
strError = " " ;
int nOne = 1 ;
# ifdef WIN32
// Initialize Windows Sockets
WSADATA wsadata ;
int ret = WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsadata ) ;
if ( ret ! = NO_ERROR )
{
strError = strprintf ( " Error: TCP/IP socket library failed to start (WSAStartup returned error %d) " , ret ) ;
printf ( " %s \n " , strError . c_str ( ) ) ;
return false ;
}
# endif
// Create socket for listening for incoming connections
# ifdef USE_IPV6
struct sockaddr_storage sockaddr ;
# else
struct sockaddr sockaddr ;
# endif
socklen_t len = sizeof ( sockaddr ) ;
if ( ! addrBind . GetSockAddr ( ( struct sockaddr * ) & sockaddr , & len ) )
{
strError = strprintf ( " Error: bind address family for %s not supported " , addrBind . ToString ( ) . c_str ( ) ) ;
printf ( " %s \n " , strError . c_str ( ) ) ;
return false ;
}
SOCKET hListenSocket = socket ( ( ( struct sockaddr * ) & sockaddr ) - > sa_family , SOCK_STREAM , IPPROTO_TCP ) ;
if ( hListenSocket = = INVALID_SOCKET )
{
strError = strprintf ( " Error: Couldn't open socket for incoming connections (socket returned error %d) " , WSAGetLastError ( ) ) ;
printf ( " %s \n " , strError . c_str ( ) ) ;
return false ;
}
# ifdef SO_NOSIGPIPE
// Different way of disabling SIGPIPE on BSD
setsockopt ( hListenSocket , SOL_SOCKET , SO_NOSIGPIPE , ( void * ) & nOne , sizeof ( int ) ) ;
# endif
# ifndef WIN32
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted. Not an issue on windows.
setsockopt ( hListenSocket , SOL_SOCKET , SO_REUSEADDR , ( void * ) & nOne , sizeof ( int ) ) ;
# endif
# ifdef WIN32
// Set to non-blocking, incoming connections will also inherit this
if ( ioctlsocket ( hListenSocket , FIONBIO , ( u_long * ) & nOne ) = = SOCKET_ERROR )
# else
if ( fcntl ( hListenSocket , F_SETFL , O_NONBLOCK ) = = SOCKET_ERROR )
# endif
{
strError = strprintf ( " Error: Couldn't set properties on socket for incoming connections (error %d) " , WSAGetLastError ( ) ) ;
printf ( " %s \n " , strError . c_str ( ) ) ;
return false ;
}
# ifdef USE_IPV6
// 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
setsockopt ( hListenSocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( void * ) & nOne , sizeof ( int ) ) ;
# endif
# ifdef WIN32
int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */ ;
int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */ ;
// this call is allowed to fail
setsockopt ( hListenSocket , IPPROTO_IPV6 , nParameterId , ( const char * ) & nProtLevel , sizeof ( int ) ) ;
# endif
}
# endif
if ( : : bind ( hListenSocket , ( struct sockaddr * ) & sockaddr , len ) = = SOCKET_ERROR )
{
int nErr = WSAGetLastError ( ) ;
if ( nErr = = WSAEADDRINUSE )
strError = strprintf ( _ ( " Unable to bind to %s on this computer. Bitcoin is probably already running. " ) , addrBind . ToString ( ) . c_str ( ) ) ;
else
strError = strprintf ( _ ( " Unable to bind to %s on this computer (bind returned error %d, %s) " ) , addrBind . ToString ( ) . c_str ( ) , nErr , strerror ( nErr ) ) ;
printf ( " %s \n " , strError . c_str ( ) ) ;
return false ;
}
printf ( " Bound to %s \n " , addrBind . ToString ( ) . c_str ( ) ) ;
// Listen for incoming connections
if ( listen ( hListenSocket , SOMAXCONN ) = = SOCKET_ERROR )
{
strError = strprintf ( " Error: Listening for incoming connections failed (listen returned error %d) " , WSAGetLastError ( ) ) ;
printf ( " %s \n " , strError . c_str ( ) ) ;
return false ;
}
vhListenSocket . push_back ( hListenSocket ) ;
if ( addrBind . IsRoutable ( ) & & fDiscover )
AddLocal ( addrBind , LOCAL_BIND ) ;
return true ;
}
void static Discover ( )
{
if ( ! fDiscover )
return ;
# ifdef WIN32
// Get local host IP
char pszHostName [ 1000 ] = " " ;
if ( gethostname ( pszHostName , sizeof ( pszHostName ) ) ! = SOCKET_ERROR )
{
vector < CNetAddr > vaddr ;
if ( LookupHost ( pszHostName , vaddr ) )
{
BOOST_FOREACH ( const CNetAddr & addr , vaddr )
{
AddLocal ( addr , LOCAL_IF ) ;
}
}
}
# 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 ) ;
CNetAddr addr ( s4 - > sin_addr ) ;
if ( AddLocal ( addr , LOCAL_IF ) )
printf ( " IPv4 %s: %s \n " , ifa - > ifa_name , addr . ToString ( ) . c_str ( ) ) ;
}
# ifdef USE_IPV6
else if ( ifa - > ifa_addr - > sa_family = = AF_INET6 )
{
struct sockaddr_in6 * s6 = ( struct sockaddr_in6 * ) ( ifa - > ifa_addr ) ;
CNetAddr addr ( s6 - > sin6_addr ) ;
if ( AddLocal ( addr , LOCAL_IF ) )
printf ( " IPv6 %s: %s \n " , ifa - > ifa_name , addr . ToString ( ) . c_str ( ) ) ;
}
# endif
}
freeifaddrs ( myaddrs ) ;
}
# endif
// Don't use external IPv4 discovery, when -onlynet="IPv6"
if ( ! IsLimited ( NET_IPV4 ) )
NewThread ( ThreadGetMyExternalIP , NULL ) ;
}
void StartNode ( void * parg )
{
// Make this thread recognisable as the startup thread
RenameThread ( " bitcoin-start " ) ;
if ( semOutbound = = NULL ) {
// initialize semaphore
int nMaxOutbound = min ( MAX_OUTBOUND_CONNECTIONS , ( int ) GetArg ( " -maxconnections " , 125 ) ) ;
semOutbound = new CSemaphore ( nMaxOutbound ) ;
}
if ( pnodeLocalHost = = NULL )
pnodeLocalHost = new CNode ( INVALID_SOCKET , CAddress ( CService ( " 127.0.0.1 " , 0 ) , nLocalServices ) ) ;
Discover ( ) ;
//
// Start threads
//
if ( ! GetBoolArg ( " -dnsseed " , true ) )
printf ( " DNS seeding disabled \n " ) ;
else
if ( ! NewThread ( ThreadDNSAddressSeed , NULL ) )
printf ( " Error: NewThread(ThreadDNSAddressSeed) failed \n " ) ;
// Map ports with UPnP
if ( fUseUPnP )
MapPort ( ) ;
// Get addresses from IRC and advertise ours
if ( ! NewThread ( ThreadIRCSeed , NULL ) )
printf ( " Error: NewThread(ThreadIRCSeed) failed \n " ) ;
// Send and receive from sockets, accept connections
if ( ! NewThread ( ThreadSocketHandler , NULL ) )
printf ( " Error: NewThread(ThreadSocketHandler) failed \n " ) ;
// Initiate outbound connections from -addnode
if ( ! NewThread ( ThreadOpenAddedConnections , NULL ) )
printf ( " Error: NewThread(ThreadOpenAddedConnections) failed \n " ) ;
// Initiate outbound connections
if ( ! NewThread ( ThreadOpenConnections , NULL ) )
printf ( " Error: NewThread(ThreadOpenConnections) failed \n " ) ;
// Process messages
if ( ! NewThread ( ThreadMessageHandler , NULL ) )
printf ( " Error: NewThread(ThreadMessageHandler) failed \n " ) ;
// Dump network addresses
if ( ! NewThread ( ThreadDumpAddress , NULL ) )
printf ( " Error; NewThread(ThreadDumpAddress) failed \n " ) ;
// Generate coins in the background
GenerateBitcoins ( GetBoolArg ( " -gen " , false ) , pwalletMain ) ;
}
bool StopNode ( )
{
printf ( " StopNode() \n " ) ;
fShutdown = true ;
nTransactionsUpdated + + ;
int64 nStart = GetTime ( ) ;
if ( semOutbound )
for ( int i = 0 ; i < MAX_OUTBOUND_CONNECTIONS ; i + + )
semOutbound - > post ( ) ;
do
{
int nThreadsRunning = 0 ;
for ( int n = 0 ; n < THREAD_MAX ; n + + )
nThreadsRunning + = vnThreadsRunning [ n ] ;
if ( nThreadsRunning = = 0 )
break ;
if ( GetTime ( ) - nStart > 20 )
break ;
Sleep ( 20 ) ;
} while ( true ) ;
if ( vnThreadsRunning [ THREAD_SOCKETHANDLER ] > 0 ) printf ( " ThreadSocketHandler still running \n " ) ;
if ( vnThreadsRunning [ THREAD_OPENCONNECTIONS ] > 0 ) printf ( " ThreadOpenConnections still running \n " ) ;
if ( vnThreadsRunning [ THREAD_MESSAGEHANDLER ] > 0 ) printf ( " ThreadMessageHandler still running \n " ) ;
if ( vnThreadsRunning [ THREAD_MINER ] > 0 ) printf ( " ThreadBitcoinMiner still running \n " ) ;
if ( vnThreadsRunning [ THREAD_RPCLISTENER ] > 0 ) printf ( " ThreadRPCListener still running \n " ) ;
if ( vnThreadsRunning [ THREAD_RPCHANDLER ] > 0 ) printf ( " ThreadsRPCServer still running \n " ) ;
# ifdef USE_UPNP
if ( vnThreadsRunning [ THREAD_UPNP ] > 0 ) printf ( " ThreadMapPort still running \n " ) ;
# endif
if ( vnThreadsRunning [ THREAD_DNSSEED ] > 0 ) printf ( " ThreadDNSAddressSeed still running \n " ) ;
if ( vnThreadsRunning [ THREAD_ADDEDCONNECTIONS ] > 0 ) printf ( " ThreadOpenAddedConnections still running \n " ) ;
if ( vnThreadsRunning [ THREAD_DUMPADDRESS ] > 0 ) printf ( " ThreadDumpAddresses still running \n " ) ;
while ( vnThreadsRunning [ THREAD_MESSAGEHANDLER ] > 0 | | vnThreadsRunning [ THREAD_RPCHANDLER ] > 0 )
Sleep ( 20 ) ;
Sleep ( 50 ) ;
DumpAddresses ( ) ;
return true ;
}
class CNetCleanup
{
public :
CNetCleanup ( )
{
}
~ CNetCleanup ( )
{
// Close sockets
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( pnode - > hSocket ! = INVALID_SOCKET )
closesocket ( pnode - > hSocket ) ;
BOOST_FOREACH ( SOCKET hListenSocket , vhListenSocket )
if ( hListenSocket ! = INVALID_SOCKET )
if ( closesocket ( hListenSocket ) = = SOCKET_ERROR )
printf ( " closesocket(hListenSocket) failed with error %d \n " , WSAGetLastError ( ) ) ;
# ifdef WIN32
// Shutdown Windows Sockets
WSACleanup ( ) ;
# endif
}
}
instance_of_cnetcleanup ;
void RelayTransaction ( const CTransaction & tx , const uint256 & hash )
{
CDataStream ss ( SER_NETWORK , PROTOCOL_VERSION ) ;
ss . reserve ( 10000 ) ;
ss < < tx ;
RelayTransaction ( tx , hash , ss ) ;
}
void RelayTransaction ( const CTransaction & tx , const uint256 & hash , const CDataStream & ss )
{
CInv inv ( MSG_TX , hash ) ;
{
LOCK ( cs_mapRelay ) ;
// Expire old relay messages
while ( ! vRelayExpiration . empty ( ) & & vRelayExpiration . front ( ) . first < GetTime ( ) )
{
mapRelay . erase ( vRelayExpiration . front ( ) . second ) ;
vRelayExpiration . pop_front ( ) ;
}
// Save original serialized message so newer versions are preserved
mapRelay . insert ( std : : make_pair ( inv , ss ) ) ;
vRelayExpiration . push_back ( std : : make_pair ( GetTime ( ) + 15 * 60 , inv ) ) ;
}
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
{
if ( ! pnode - > fRelayTxes )
continue ;
LOCK ( pnode - > cs_filter ) ;
if ( pnode - > pfilter )
{
if ( pnode - > pfilter - > IsRelevantAndUpdate ( tx , hash ) )
pnode - > PushInventory ( inv ) ;
} else
pnode - > PushInventory ( inv ) ;
}
}