22f721dbf2
added SetBitcoinAddress and GetBitcoinAddress methods on CScript, critsect interlocks around mapAddressBook, added some random delays in tx broadcast to improve privacy, now compiles with MSVC 8.0
322 lines
8.2 KiB
C++
322 lines
8.2 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "headers.h"
|
|
|
|
int nGotIRCAddresses = 0;
|
|
|
|
|
|
|
|
#pragma pack(push, 1)
|
|
struct ircaddr
|
|
{
|
|
int ip;
|
|
short port;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
string EncodeAddress(const CAddress& addr)
|
|
{
|
|
struct ircaddr tmp;
|
|
tmp.ip = addr.ip;
|
|
tmp.port = addr.port;
|
|
|
|
vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
|
|
return string("u") + EncodeBase58Check(vch);
|
|
}
|
|
|
|
bool DecodeAddress(string str, CAddress& addr)
|
|
{
|
|
vector<unsigned char> vch;
|
|
if (!DecodeBase58Check(str.substr(1), vch))
|
|
return false;
|
|
|
|
struct ircaddr tmp;
|
|
if (vch.size() != sizeof(tmp))
|
|
return false;
|
|
memcpy(&tmp, &vch[0], sizeof(tmp));
|
|
|
|
addr = CAddress(tmp.ip, tmp.port, NODE_NETWORK);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool Send(SOCKET hSocket, const char* pszSend)
|
|
{
|
|
if (strstr(pszSend, "PONG") != pszSend)
|
|
printf("IRC SENDING: %s\n", pszSend);
|
|
const char* psz = pszSend;
|
|
const char* pszEnd = psz + strlen(psz);
|
|
while (psz < pszEnd)
|
|
{
|
|
int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
|
|
if (ret < 0)
|
|
return false;
|
|
psz += ret;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
else if (nBytes <= 0)
|
|
{
|
|
if (!strLine.empty())
|
|
return true;
|
|
// socket closed
|
|
printf("IRC socket closed\n");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// socket error
|
|
int nErr = WSAGetLastError();
|
|
if (nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
|
|
{
|
|
printf("IRC recv failed: %d\n", nErr);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RecvLineIRC(SOCKET hSocket, string& strLine)
|
|
{
|
|
loop
|
|
{
|
|
bool fRet = RecvLine(hSocket, strLine);
|
|
if (fRet)
|
|
{
|
|
if (fShutdown)
|
|
return false;
|
|
vector<string> vWords;
|
|
ParseString(strLine, ' ', vWords);
|
|
if (vWords[0] == "PING")
|
|
{
|
|
strLine[1] = 'O';
|
|
strLine += '\r';
|
|
Send(hSocket, strLine.c_str());
|
|
continue;
|
|
}
|
|
}
|
|
return fRet;
|
|
}
|
|
}
|
|
|
|
int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL)
|
|
{
|
|
loop
|
|
{
|
|
string strLine;
|
|
if (!RecvLineIRC(hSocket, strLine))
|
|
return 0;
|
|
printf("IRC %s\n", strLine.c_str());
|
|
if (psz1 && strLine.find(psz1) != -1)
|
|
return 1;
|
|
if (psz2 && strLine.find(psz2) != -1)
|
|
return 2;
|
|
if (psz3 && strLine.find(psz3) != -1)
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
bool Wait(int nSeconds)
|
|
{
|
|
if (fShutdown)
|
|
return false;
|
|
printf("IRC waiting %d seconds to reconnect\n", nSeconds);
|
|
for (int i = 0; i < nSeconds; i++)
|
|
{
|
|
if (fShutdown)
|
|
return false;
|
|
Sleep(1000);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
void ThreadIRCSeed(void* parg)
|
|
{
|
|
SetThreadPriority(THREAD_PRIORITY_NORMAL);
|
|
int nErrorWait = 10;
|
|
int nRetryWait = 10;
|
|
bool fNameInUse = false;
|
|
bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
|
|
|
|
while (!fShutdown)
|
|
{
|
|
CAddress addrConnect("216.155.130.130:6667");
|
|
if (!fTOR)
|
|
{
|
|
struct hostent* phostent = gethostbyname("chat.freenode.net");
|
|
if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])
|
|
addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(6667));
|
|
}
|
|
|
|
SOCKET hSocket;
|
|
if (!ConnectSocket(addrConnect, hSocket))
|
|
{
|
|
printf("IRC connect failed\n");
|
|
nErrorWait = nErrorWait * 11 / 10;
|
|
if (Wait(nErrorWait += 60))
|
|
continue;
|
|
else
|
|
return;
|
|
}
|
|
|
|
if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname"))
|
|
{
|
|
closesocket(hSocket);
|
|
hSocket = INVALID_SOCKET;
|
|
nErrorWait = nErrorWait * 11 / 10;
|
|
if (Wait(nErrorWait += 60))
|
|
continue;
|
|
else
|
|
return;
|
|
}
|
|
|
|
string strMyName;
|
|
if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
|
|
strMyName = EncodeAddress(addrLocalHost);
|
|
else
|
|
strMyName = strprintf("x%u", GetRand(1000000000));
|
|
|
|
|
|
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
|
|
Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
|
|
|
|
int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
|
|
if (nRet != 1)
|
|
{
|
|
closesocket(hSocket);
|
|
hSocket = INVALID_SOCKET;
|
|
if (nRet == 2)
|
|
{
|
|
printf("IRC name already in use\n");
|
|
fNameInUse = true;
|
|
Wait(10);
|
|
continue;
|
|
}
|
|
nErrorWait = nErrorWait * 11 / 10;
|
|
if (Wait(nErrorWait += 60))
|
|
continue;
|
|
else
|
|
return;
|
|
}
|
|
Sleep(500);
|
|
|
|
Send(hSocket, "JOIN #bitcoin\r");
|
|
Send(hSocket, "WHO #bitcoin\r");
|
|
|
|
int64 nStart = GetTime();
|
|
string strLine;
|
|
while (!fShutdown && RecvLineIRC(hSocket, strLine))
|
|
{
|
|
if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
|
|
continue;
|
|
|
|
vector<string> vWords;
|
|
ParseString(strLine, ' ', vWords);
|
|
if (vWords.size() < 2)
|
|
continue;
|
|
|
|
char pszName[10000];
|
|
pszName[0] = '\0';
|
|
|
|
if (vWords[1] == "352" && vWords.size() >= 8)
|
|
{
|
|
// index 7 is limited to 16 characters
|
|
// could get full length name at index 10, but would be different from join messages
|
|
strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
|
|
printf("IRC got who\n");
|
|
}
|
|
|
|
if (vWords[1] == "JOIN" && vWords[0].size() > 1)
|
|
{
|
|
// :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
|
|
strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
|
|
if (strchr(pszName, '!'))
|
|
*strchr(pszName, '!') = '\0';
|
|
printf("IRC got join\n");
|
|
}
|
|
|
|
if (pszName[0] == 'u')
|
|
{
|
|
CAddress addr;
|
|
if (DecodeAddress(pszName, addr))
|
|
{
|
|
addr.nTime = GetAdjustedTime() - 51 * 60;
|
|
if (AddAddress(addr))
|
|
printf("IRC got new address\n");
|
|
nGotIRCAddresses++;
|
|
}
|
|
else
|
|
{
|
|
printf("IRC decode failed\n");
|
|
}
|
|
}
|
|
}
|
|
closesocket(hSocket);
|
|
hSocket = INVALID_SOCKET;
|
|
|
|
// IRC usually blocks TOR, so only try once
|
|
if (fTOR)
|
|
return;
|
|
|
|
if (GetTime() - nStart > 20 * 60)
|
|
{
|
|
nErrorWait /= 3;
|
|
nRetryWait /= 3;
|
|
}
|
|
|
|
nRetryWait = nRetryWait * 11 / 10;
|
|
if (!Wait(nRetryWait += 60))
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef TEST
|
|
int main(int argc, char *argv[])
|
|
{
|
|
WSADATA wsadata;
|
|
if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
|
|
{
|
|
printf("Error at WSAStartup()\n");
|
|
return false;
|
|
}
|
|
|
|
ThreadIRCSeed(NULL);
|
|
|
|
WSACleanup();
|
|
return 0;
|
|
}
|
|
#endif
|