// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#include <stdint.h>
+
#include "headers.h"
#include "irc.h"
#include "db.h"
#include "init.h"
#include "strlcpy.h"
-#ifdef __WXMSW__
+#ifdef WIN32
#include <string.h>
#endif
#ifdef USE_UPNP
void ThreadMapPort2(void* parg);
#endif
+void ThreadDNSAddressSeed2(void* parg);
bool OpenNetworkConnection(const CAddress& addrConnect);
//
bool fClient = false;
bool fAllowDNS = false;
-uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
+uint64_t nLocalServices = (fClient ? 0 : NODE_NETWORK);
CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices);
static CNode* pnodeLocalHost = NULL;
-uint64 nLocalHostNonce = 0;
+uint64_t nLocalHostNonce = 0;
array<int, 10> vnThreadsRunning;
static SOCKET hListenSocket = INVALID_SOCKET;
map<vector<unsigned char>, CAddress> mapAddresses;
CCriticalSection cs_mapAddresses;
map<CInv, CDataStream> mapRelay;
-deque<pair<int64, CInv> > vRelayExpiration;
+deque<pair<int64_t, CInv> > vRelayExpiration;
CCriticalSection cs_mapRelay;
-map<CInv, int64> mapAlreadyAskedFor;
+map<CInv, int64_t> mapAlreadyAskedFor;
// Settings
int fUseProxy = false;
bool fProxy = (fUseProxy && addrConnect.IsRoutable());
struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
-#ifdef __WXMSW__
+#ifdef WIN32
u_long fNonblock = 1;
if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
#else
return false;
}
socklen_t nRetSize = sizeof(nRet);
-#ifdef __WXMSW__
+#ifdef WIN32
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
#else
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
return false;
}
}
-#ifdef __WXMSW__
+#ifdef WIN32
else if (WSAGetLastError() != WSAEISCONN)
#else
else
CNode::ConnectNode immediately turns the socket back to non-blocking
but we'll turn it back to blocking just in case
*/
-#ifdef __WXMSW__
+#ifdef WIN32
fNonblock = 0;
if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
#else
else
pszColon[0] = 0;
port = portParsed;
- if (port < 0 || port > USHRT_MAX)
- port = USHRT_MAX;
+ if (port < 0 || port > std::numeric_limits<unsigned short>::max())
+ port = std::numeric_limits<unsigned short>::max();
}
}
-bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
+bool AddAddress(CAddress addr, int64_t nTimePenalty, CAddrDB *pAddrDB)
{
if (!addr.IsRoutable())
return false;
if (addr.ip == addrLocalHost.ip)
return false;
- addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
+ addr.nTime = max((int64_t)0, (int64_t)addr.nTime - nTimePenalty);
+ bool fUpdated = false;
+ bool fNew = false;
+ CAddress addrFound = addr;
+
CRITICAL_BLOCK(cs_mapAddresses)
{
map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
// New address
printf("AddAddress(%s)\n", addr.ToString().c_str());
mapAddresses.insert(make_pair(addr.GetKey(), addr));
- if (pAddrDB)
- pAddrDB->WriteAddress(addr);
- else
- CAddrDB().WriteAddress(addr);
- return true;
+ fUpdated = true;
+ fNew = true;
}
else
{
- bool fUpdated = false;
- CAddress& addrFound = (*it).second;
+ addrFound = (*it).second;
if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
{
// Services have been added
fUpdated = true;
}
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
- int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
+ int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
if (addrFound.nTime < addr.nTime - nUpdateInterval)
{
// Periodically update most recently seen time
addrFound.nTime = addr.nTime;
fUpdated = true;
}
- if (fUpdated)
- {
- if (pAddrDB)
- pAddrDB->WriteAddress(addrFound);
- else
- CAddrDB().WriteAddress(addrFound);
- }
}
}
- return false;
+ // There is a nasty deadlock bug if this is done inside the cs_mapAddresses
+ // CRITICAL_BLOCK:
+ // Thread 1: begin db transaction (locks inside-db-mutex)
+ // then AddAddress (locks cs_mapAddresses)
+ // Thread 2: AddAddress (locks cs_mapAddresses)
+ // ... then db operation hangs waiting for inside-db-mutex
+ if (fUpdated)
+ {
+ if (pAddrDB)
+ pAddrDB->WriteAddress(addrFound);
+ else
+ CAddrDB().WriteAddress(addrFound);
+ }
+ return fNew;
}
void AddressCurrentlyConnected(const CAddress& addr)
if (it != mapAddresses.end())
{
CAddress& addrFound = (*it).second;
- int64 nUpdateInterval = 20 * 60;
+ int64_t nUpdateInterval = 20 * 60;
if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)
{
// Periodically update most recently seen time
return NULL;
}
-CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
+CNode* ConnectNode(CAddress addrConnect, int64_t nTimeout)
{
if (addrConnect.ip == addrLocalHost.ip)
return NULL;
printf("connected %s\n", addrConnect.ToString().c_str());
// Set to nonblocking
-#ifdef __WXMSW__
+#ifdef WIN32
u_long nOne = 1;
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
}
+void CNode::PushVersion()
+{
+ /// when NTP implemented, change to just nTime = GetAdjustedTime()
+ int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
+ CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
+ CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
+ RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
+ PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
+ nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
+}
+
+
+
+
+
+std::map<unsigned int, int64_t> CNode::setBanned;
+CCriticalSection CNode::cs_setBanned;
+
+void CNode::ClearBanned()
+{
+ setBanned.clear();
+}
+
+bool CNode::IsBanned(unsigned int ip)
+{
+ bool fResult = false;
+ CRITICAL_BLOCK(cs_setBanned)
+ {
+ std::map<unsigned int, int64_t>::iterator i = setBanned.find(ip);
+ if (i != setBanned.end())
+ {
+ int64_t t = (*i).second;
+ if (GetTime() < t)
+ fResult = true;
+ }
+ }
+ return fResult;
+}
+
+bool CNode::Misbehaving(int howmuch)
+{
+ if (addr.IsLocal())
+ {
+ printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
+ return false;
+ }
+
+ nMisbehavior += howmuch;
+ if (nMisbehavior >= GetArg("-banscore", 100))
+ {
+ int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
+ CRITICAL_BLOCK(cs_setBanned)
+ if (setBanned[addr.ip] < banTime)
+ setBanned[addr.ip] = banTime;
+ CloseSocketDisconnect();
+ printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
+ return true;
+ }
+ return false;
+}
+
{
closesocket(hSocket);
}
+ else if (CNode::IsBanned(addr.ip))
+ {
+ printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
+ closesocket(hSocket);
+ }
else
{
printf("accepted connection %s\n", addr.ToString().c_str());
const char * rootdescurl = 0;
const char * multicastif = 0;
const char * minissdpdpath = 0;
- int error = 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;
char intClient[16];
char intPort[6];
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",
static const char *strDNSSeed[] = {
"bitseed.xf2.org",
- "bitseed.bitcoin.org.uk",
"dnsseed.bluematt.me",
+ "seed.bitcoin.sipa.be",
+ "dnsseed.bitcoin.dashjr.org",
};
-void DNSAddressSeed()
+void ThreadDNSAddressSeed(void* parg)
+{
+ IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg));
+ try
+ {
+ vnThreadsRunning[6]++;
+ ThreadDNSAddressSeed2(parg);
+ vnThreadsRunning[6]--;
+ }
+ catch (std::exception& e) {
+ vnThreadsRunning[6]--;
+ PrintException(&e, "ThreadDNSAddressSeed()");
+ } catch (...) {
+ vnThreadsRunning[6]--;
+ throw; // support pthread_cancel()
+ }
+ printf("ThreadDNSAddressSeed exiting\n");
+}
+
+void ThreadDNSAddressSeed2(void* parg)
{
+ printf("ThreadDNSAddressSeed started\n");
int found = 0;
if (!fTestNet)
+
+
+
+
+
+
+
+
+
unsigned int pnSeed[] =
{
0x6884ac63, 0x3ffecead, 0x2919b953, 0x0942fe50, 0x7a1d922e, 0xcdd6734a, 0x953a5bb6, 0x2c46922e,
// Connect to specific addresses
if (mapArgs.count("-connect"))
{
- for (int64 nLoop = 0;; nLoop++)
+ for (int64_t nLoop = 0;; nLoop++)
{
BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
{
}
// Initiate network connections
- int64 nStart = GetTime();
+ int64_t nStart = GetTime();
loop
{
// Limit outbound connections
// 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;
+ const int64_t nOneWeek = 7*24*60*60;
CAddress addr;
addr.ip = pnSeed[i];
addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect;
- int64 nBest = INT64_MIN;
+ int64_t nBest = std::numeric_limits<int64_t>::min();
// Only connect to one address per a.b.?.? range.
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
BOOST_FOREACH(CNode* pnode, vNodes)
setConnected.insert(pnode->addr.ip & 0x0000ffff);
+ int64_t nANow = GetAdjustedTime();
+
CRITICAL_BLOCK(cs_mapAddresses)
{
BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
const CAddress& addr = item.second;
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
continue;
- int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
- int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
+ int64_t nSinceLastSeen = nANow - addr.nTime;
+ int64_t nSinceLastTry = nANow - addr.nLastTry;
// Randomize the order in a deterministic way, putting the standard port first
- int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
+ int64_t nRandomizer = (uint64_t)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
if (addr.port != htons(GetDefaultPort()))
nRandomizer += 2 * 60 * 60;
// 30 days 27 hours
// 90 days 46 hours
// 365 days 93 hours
- int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
+ int64_t nDelay = (int64_t)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
// Fast reconnect for one hour after last seen
if (nSinceLastSeen < 60 * 60)
// If multiple addresses are ready, prioritize by time since
// last seen and time since last tried.
- int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
+ int64_t nScore = min(nSinceLastTry, (int64_t)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
if (nScore > nBest)
{
nBest = nScore;
//
if (fShutdown)
return false;
- if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
+ if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
+ FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
return false;
vnThreadsRunning[1]--;
int nOne = 1;
addrLocalHost.port = htons(GetListenPort());
-#ifdef __WXMSW__
+#ifdef WIN32
// Initialize Windows Sockets
WSADATA wsadata;
int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
-#ifndef __WXMSW__
+#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 __WXMSW__
+#ifdef WIN32
// Set to nonblocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
#else
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
-#ifdef __WXMSW__
+#ifdef WIN32
// Get local host ip
char pszHostName[1000] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
// Start threads
//
+ if (GetBoolArg("-nodnsseed"))
+ printf("DNS seeding disabled\n");
+ else
+ if (!CreateThread(ThreadDNSAddressSeed, NULL))
+ printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n");
+
// Map ports with UPnP
if (fHaveUPnP)
MapPort(fUseUPnP);
printf("Error: CreateThread(ThreadIRCSeed) failed\n");
// Send and receive from sockets, accept connections
- CreateThread(ThreadSocketHandler, NULL, true);
+ if (!CreateThread(ThreadSocketHandler, NULL))
+ printf("Error: CreateThread(ThreadSocketHandler) failed\n");
// Initiate outbound connections
if (!CreateThread(ThreadOpenConnections, NULL))
printf("StopNode()\n");
fShutdown = true;
nTransactionsUpdated++;
- int64 nStart = GetTime();
+ int64_t nStart = GetTime();
while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0
#ifdef USE_UPNP
|| vnThreadsRunning[5] > 0
if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n");
+ if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n");
while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
Sleep(20);
Sleep(50);
if (closesocket(hListenSocket) == SOCKET_ERROR)
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
-#ifdef __WXMSW__
+#ifdef WIN32
// Shutdown Windows Sockets
WSACleanup();
#endif