Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F10615301
net.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
64 KB
Subscribers
None
net.cpp
View Options
// 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
"strlcpy.h"
#include
"addrman.h"
#include
"ui_interface.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
fClient
=
false
;
bool
fDiscover
=
true
;
bool
fUseUPnP
=
false
;
uint64
nLocalServices
=
(
fClient
?
0
:
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
;
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
;
info
.
nPort
=
addr
.
GetPort
()
+
(
fAlready
?
1
:
0
);
}
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
)
{
IMPLEMENT_RANDOMIZE_STACK
(
ThreadSocketHandler
(
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_mapRequests
,
lockReq
);
if
(
lockReq
)
{
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
;
BOOST_FOREACH
(
SOCKET
hListenSocket
,
vhListenSocket
)
{
FD_SET
(
hListenSocket
,
&
fdsetRecv
);
hSocketMax
=
max
(
hSocketMax
,
hListenSocket
);
}
{
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
);
{
TRY_LOCK
(
pnode
->
cs_vSend
,
lockSend
);
if
(
lockSend
&&
!
pnode
->
vSend
.
empty
())
FD_SET
(
pnode
->
hSocket
,
&
fdsetSend
);
}
}
}
vnThreadsRunning
[
THREAD_SOCKETHANDLER
]
--
;
int
nSelect
=
select
(
hSocketMax
+
1
,
&
fdsetRecv
,
&
fdsetSend
,
&
fdsetError
,
&
timeout
);
vnThreadsRunning
[
THREAD_SOCKETHANDLER
]
++
;
if
(
fShutdown
)
return
;
if
(
nSelect
==
SOCKET_ERROR
)
{
int
nErr
=
WSAGetLastError
();
if
(
hSocketMax
!=
INVALID_SOCKET
)
{
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
)
{
if
(
WSAGetLastError
()
!=
WSAEWOULDBLOCK
)
printf
(
"socket error accept failed: %d
\n
"
,
WSAGetLastError
());
}
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 (%d 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
)
{
IMPLEMENT_RANDOMIZE_STACK
(
ThreadMapPort
(
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
"
);
char
port
[
6
];
sprintf
(
port
,
"%d"
,
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
,
port
,
lanaddr
,
strDesc
.
c_str
(),
"TCP"
,
0
);
#else
/* miniupnpc 1.6 */
r
=
UPNP_AddPortMapping
(
urls
.
controlURL
,
data
.
first
.
servicetype
,
port
,
port
,
lanaddr
,
strDesc
.
c_str
(),
"TCP"
,
0
,
"0"
);
#endif
if
(
r
!=
UPNPCOMMAND_SUCCESS
)
printf
(
"AddPortMapping(%s, %s, %s) failed with code %d (%s)
\n
"
,
port
,
port
,
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
,
"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
,
port
,
lanaddr
,
strDesc
.
c_str
(),
"TCP"
,
0
);
#else
/* miniupnpc 1.6 */
r
=
UPNP_AddPortMapping
(
urls
.
controlURL
,
data
.
first
.
servicetype
,
port
,
port
,
lanaddr
,
strDesc
.
c_str
(),
"TCP"
,
0
,
"0"
);
#endif
if
(
r
!=
UPNPCOMMAND_SUCCESS
)
printf
(
"AddPortMapping(%s, %s, %s) failed with code %d (%s)
\n
"
,
port
,
port
,
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
(
!
CreateThread
(
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
)
{
IMPLEMENT_RANDOMIZE_STACK
(
ThreadDNSAddressSeed
(
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
(
GetNameProxy
())
{
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
)
{
vnThreadsRunning
[
THREAD_DUMPADDRESS
]
++
;
while
(
!
fShutdown
)
{
DumpAddresses
();
vnThreadsRunning
[
THREAD_DUMPADDRESS
]
--
;
Sleep
(
100000
);
vnThreadsRunning
[
THREAD_DUMPADDRESS
]
++
;
}
vnThreadsRunning
[
THREAD_DUMPADDRESS
]
--
;
}
void
ThreadDumpAddress
(
void
*
parg
)
{
IMPLEMENT_RANDOMIZE_STACK
(
ThreadDumpAddress
(
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
)
{
IMPLEMENT_RANDOMIZE_STACK
(
ThreadOpenConnections
(
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
)
{
IMPLEMENT_RANDOMIZE_STACK
(
ThreadOpenAddedConnections
(
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
"
);
if
(
mapArgs
.
count
(
"-addnode"
)
==
0
)
return
;
if
(
GetNameProxy
())
{
while
(
!
fShutdown
)
{
BOOST_FOREACH
(
string
&
strAddNode
,
mapMultiArgs
[
"-addnode"
])
{
CAddress
addr
;
CSemaphoreGrant
grant
(
*
semOutbound
);
OpenNetworkConnection
(
addr
,
&
grant
,
strAddNode
.
c_str
());
Sleep
(
500
);
}
vnThreadsRunning
[
THREAD_ADDEDCONNECTIONS
]
--
;
Sleep
(
120000
);
// Retry every 2 minutes
vnThreadsRunning
[
THREAD_ADDEDCONNECTIONS
]
++
;
}
return
;
}
vector
<
vector
<
CService
>
>
vservAddressesToAdd
(
0
);
BOOST_FOREACH
(
string
&
strAddNode
,
mapMultiArgs
[
"-addnode"
])
{
vector
<
CService
>
vservNode
(
0
);
if
(
Lookup
(
strAddNode
.
c_str
(),
vservNode
,
GetDefaultPort
(),
fNameLookup
,
0
))
{
vservAddressesToAdd
.
push_back
(
vservNode
);
{
LOCK
(
cs_setservAddNodeAddresses
);
BOOST_FOREACH
(
CService
&
serv
,
vservNode
)
setservAddNodeAddresses
.
insert
(
serv
);
}
}
}
loop
{
vector
<
vector
<
CService
>
>
vservConnectAddresses
=
vservAddressesToAdd
;
// 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
(
vector
<
vector
<
CService
>
>::
iterator
it
=
vservConnectAddresses
.
begin
();
it
!=
vservConnectAddresses
.
end
();
it
++
)
BOOST_FOREACH
(
CService
&
addrNode
,
*
(
it
))
if
(
pnode
->
addr
==
addrNode
)
{
it
=
vservConnectAddresses
.
erase
(
it
);
it
--
;
break
;
}
}
BOOST_FOREACH
(
vector
<
CService
>&
vserv
,
vservConnectAddresses
)
{
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
)
{
IMPLEMENT_RANDOMIZE_STACK
(
ThreadMessageHandler
(
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
))
CreateThread
(
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
(
!
CreateThread
(
ThreadDNSAddressSeed
,
NULL
))
printf
(
"Error: CreateThread(ThreadDNSAddressSeed) failed
\n
"
);
// Map ports with UPnP
if
(
fUseUPnP
)
MapPort
();
// Get addresses from IRC and advertise ours
if
(
!
CreateThread
(
ThreadIRCSeed
,
NULL
))
printf
(
"Error: CreateThread(ThreadIRCSeed) failed
\n
"
);
// Send and receive from sockets, accept connections
if
(
!
CreateThread
(
ThreadSocketHandler
,
NULL
))
printf
(
"Error: CreateThread(ThreadSocketHandler) failed
\n
"
);
// Initiate outbound connections from -addnode
if
(
!
CreateThread
(
ThreadOpenAddedConnections
,
NULL
))
printf
(
"Error: CreateThread(ThreadOpenAddedConnections) failed
\n
"
);
// Initiate outbound connections
if
(
!
CreateThread
(
ThreadOpenConnections
,
NULL
))
printf
(
"Error: CreateThread(ThreadOpenConnections) failed
\n
"
);
// Process messages
if
(
!
CreateThread
(
ThreadMessageHandler
,
NULL
))
printf
(
"Error: CreateThread(ThreadMessageHandler) failed
\n
"
);
// Dump network addresses
if
(
!
CreateThread
(
ThreadDumpAddress
,
NULL
))
printf
(
"Error; CreateThread(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
;
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sat, Nov 23, 10:04 (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4518506
Default Alt Text
net.cpp (64 KB)
Attached To
rSTAGING Bitcoin ABC staging
Event Timeline
Log In to Comment