Back to home page

Bitcoin sources

 
 

    


0001 // Copyright (c) 2009-2010 Satoshi Nakamoto
0002 // Copyright (c) 2009-2012 The Bitcoin developers
0003 // Distributed under the MIT/X11 software license, see the accompanying
0004 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
0005 
0006 #include "headers.h"
0007 #include "irc.h"
0008 #include "net.h"
0009 #include "strlcpy.h"
0010 
0011 using namespace std;
0012 using namespace boost;
0013 
0014 int nGotIRCAddresses = 0;
0015 bool fGotExternalIP = false;
0016 
0017 void ThreadIRCSeed2(void* parg);
0018 
0019 
0020 
0021 
0022 #pragma pack(push, 1)
0023 struct ircaddr
0024 {
0025     int ip;
0026     short port;
0027 };
0028 #pragma pack(pop)
0029 
0030 string EncodeAddress(const CAddress& addr)
0031 {
0032     struct ircaddr tmp;
0033     tmp.ip    = addr.ip;
0034     tmp.port  = addr.port;
0035 
0036     vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
0037     return string("u") + EncodeBase58Check(vch);
0038 }
0039 
0040 bool DecodeAddress(string str, CAddress& addr)
0041 {
0042     vector<unsigned char> vch;
0043     if (!DecodeBase58Check(str.substr(1), vch))
0044         return false;
0045 
0046     struct ircaddr tmp;
0047     if (vch.size() != sizeof(tmp))
0048         return false;
0049     memcpy(&tmp, &vch[0], sizeof(tmp));
0050 
0051     addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
0052     return true;
0053 }
0054 
0055 
0056 
0057 
0058 
0059 
0060 static bool Send(SOCKET hSocket, const char* pszSend)
0061 {
0062     if (strstr(pszSend, "PONG") != pszSend)
0063         printf("IRC SENDING: %s\n", pszSend);
0064     const char* psz = pszSend;
0065     const char* pszEnd = psz + strlen(psz);
0066     while (psz < pszEnd)
0067     {
0068         int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
0069         if (ret < 0)
0070             return false;
0071         psz += ret;
0072     }
0073     return true;
0074 }
0075 
0076 bool RecvLine(SOCKET hSocket, string& strLine)
0077 {
0078     strLine = "";
0079     loop
0080     {
0081         char c;
0082         int nBytes = recv(hSocket, &c, 1, 0);
0083         if (nBytes > 0)
0084         {
0085             if (c == '\n')
0086                 continue;
0087             if (c == '\r')
0088                 return true;
0089             strLine += c;
0090             if (strLine.size() >= 9000)
0091                 return true;
0092         }
0093         else if (nBytes <= 0)
0094         {
0095             if (fShutdown)
0096                 return false;
0097             if (nBytes < 0)
0098             {
0099                 int nErr = WSAGetLastError();
0100                 if (nErr == WSAEMSGSIZE)
0101                     continue;
0102                 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
0103                 {
0104                     Sleep(10);
0105                     continue;
0106                 }
0107             }
0108             if (!strLine.empty())
0109                 return true;
0110             if (nBytes == 0)
0111             {
0112                 // socket closed
0113                 printf("socket closed\n");
0114                 return false;
0115             }
0116             else
0117             {
0118                 // socket error
0119                 int nErr = WSAGetLastError();
0120                 printf("recv failed: %d\n", nErr);
0121                 return false;
0122             }
0123         }
0124     }
0125 }
0126 
0127 bool RecvLineIRC(SOCKET hSocket, string& strLine)
0128 {
0129     loop
0130     {
0131         bool fRet = RecvLine(hSocket, strLine);
0132         if (fRet)
0133         {
0134             if (fShutdown)
0135                 return false;
0136             vector<string> vWords;
0137             ParseString(strLine, ' ', vWords);
0138             if (vWords.size() >= 1 && vWords[0] == "PING")
0139             {
0140                 strLine[1] = 'O';
0141                 strLine += '\r';
0142                 Send(hSocket, strLine.c_str());
0143                 continue;
0144             }
0145         }
0146         return fRet;
0147     }
0148 }
0149 
0150 int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
0151 {
0152     loop
0153     {
0154         string strLine;
0155         strLine.reserve(10000);
0156         if (!RecvLineIRC(hSocket, strLine))
0157             return 0;
0158         printf("IRC %s\n", strLine.c_str());
0159         if (psz1 && strLine.find(psz1) != -1)
0160             return 1;
0161         if (psz2 && strLine.find(psz2) != -1)
0162             return 2;
0163         if (psz3 && strLine.find(psz3) != -1)
0164             return 3;
0165         if (psz4 && strLine.find(psz4) != -1)
0166             return 4;
0167     }
0168 }
0169 
0170 bool Wait(int nSeconds)
0171 {
0172     if (fShutdown)
0173         return false;
0174     printf("IRC waiting %d seconds to reconnect\n", nSeconds);
0175     for (int i = 0; i < nSeconds; i++)
0176     {
0177         if (fShutdown)
0178             return false;
0179         Sleep(1000);
0180     }
0181     return true;
0182 }
0183 
0184 bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
0185 {
0186     strRet.clear();
0187     loop
0188     {
0189         string strLine;
0190         if (!RecvLineIRC(hSocket, strLine))
0191             return false;
0192 
0193         vector<string> vWords;
0194         ParseString(strLine, ' ', vWords);
0195         if (vWords.size() < 2)
0196             continue;
0197 
0198         if (vWords[1] == psz1)
0199         {
0200             printf("IRC %s\n", strLine.c_str());
0201             strRet = strLine;
0202             return true;
0203         }
0204     }
0205 }
0206 
0207 bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
0208 {
0209     Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
0210 
0211     string strLine;
0212     if (!RecvCodeLine(hSocket, "302", strLine))
0213         return false;
0214 
0215     vector<string> vWords;
0216     ParseString(strLine, ' ', vWords);
0217     if (vWords.size() < 4)
0218         return false;
0219 
0220     string str = vWords[3];
0221     if (str.rfind("@") == string::npos)
0222         return false;
0223     string strHost = str.substr(str.rfind("@")+1);
0224 
0225     // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
0226     // but in case another IRC is ever used this should work.
0227     printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
0228     if (fUseProxy)
0229         return false;
0230     CAddress addr(strHost, 0, true);
0231     if (!addr.IsValid())
0232         return false;
0233     ipRet = addr.ip;
0234 
0235     return true;
0236 }
0237 
0238 
0239 
0240 void ThreadIRCSeed(void* parg)
0241 {
0242     IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
0243     try
0244     {
0245         ThreadIRCSeed2(parg);
0246     }
0247     catch (std::exception& e) {
0248         PrintExceptionContinue(&e, "ThreadIRCSeed()");
0249     } catch (...) {
0250         PrintExceptionContinue(NULL, "ThreadIRCSeed()");
0251     }
0252     printf("ThreadIRCSeed exiting\n");
0253 }
0254 
0255 void ThreadIRCSeed2(void* parg)
0256 {
0257     /* Dont advertise on IRC if we don't allow incoming connections */
0258     if (mapArgs.count("-connect") || fNoListen)
0259         return;
0260 
0261     if (GetBoolArg("-noirc"))
0262         return;
0263     printf("ThreadIRCSeed started\n");
0264     int nErrorWait = 10;
0265     int nRetryWait = 10;
0266     bool fNameInUse = false;
0267 
0268     while (!fShutdown)
0269     {
0270         CAddress addrConnect("92.243.23.21", 6667); // irc.lfnet.org
0271 
0272         CAddress addrIRC("irc.lfnet.org", 6667, true);
0273         if (addrIRC.IsValid())
0274             addrConnect = addrIRC;
0275 
0276         SOCKET hSocket;
0277         if (!ConnectSocket(addrConnect, hSocket))
0278         {
0279             printf("IRC connect failed\n");
0280             nErrorWait = nErrorWait * 11 / 10;
0281             if (Wait(nErrorWait += 60))
0282                 continue;
0283             else
0284                 return;
0285         }
0286 
0287         if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
0288         {
0289             closesocket(hSocket);
0290             hSocket = INVALID_SOCKET;
0291             nErrorWait = nErrorWait * 11 / 10;
0292             if (Wait(nErrorWait += 60))
0293                 continue;
0294             else
0295                 return;
0296         }
0297 
0298         string strMyName;
0299         if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
0300             strMyName = EncodeAddress(addrLocalHost);
0301         else
0302             strMyName = strprintf("x%u", GetRand(1000000000));
0303 
0304         Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
0305         Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
0306 
0307         int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
0308         if (nRet != 1)
0309         {
0310             closesocket(hSocket);
0311             hSocket = INVALID_SOCKET;
0312             if (nRet == 2)
0313             {
0314                 printf("IRC name already in use\n");
0315                 fNameInUse = true;
0316                 Wait(10);
0317                 continue;
0318             }
0319             nErrorWait = nErrorWait * 11 / 10;
0320             if (Wait(nErrorWait += 60))
0321                 continue;
0322             else
0323                 return;
0324         }
0325         Sleep(500);
0326 
0327         // Get our external IP from the IRC server and re-nick before joining the channel
0328         CAddress addrFromIRC;
0329         if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
0330         {
0331             printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
0332             if (!fUseProxy && addrFromIRC.IsRoutable())
0333             {
0334                 // IRC lets you to re-nick
0335                 fGotExternalIP = true;
0336                 addrLocalHost.ip = addrFromIRC.ip;
0337                 strMyName = EncodeAddress(addrLocalHost);
0338                 Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
0339             }
0340         }
0341         
0342         if (fTestNet) {
0343             Send(hSocket, "JOIN #bitcoinTEST\r");
0344             Send(hSocket, "WHO #bitcoinTEST\r");
0345         } else {
0346             // randomly join #bitcoin00-#bitcoin99
0347             int channel_number = GetRandInt(100);
0348             Send(hSocket, strprintf("JOIN #bitcoin%02d\r", channel_number).c_str());
0349             Send(hSocket, strprintf("WHO #bitcoin%02d\r", channel_number).c_str());
0350         }
0351 
0352         int64 nStart = GetTime();
0353         string strLine;
0354         strLine.reserve(10000);
0355         while (!fShutdown && RecvLineIRC(hSocket, strLine))
0356         {
0357             if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
0358                 continue;
0359 
0360             vector<string> vWords;
0361             ParseString(strLine, ' ', vWords);
0362             if (vWords.size() < 2)
0363                 continue;
0364 
0365             char pszName[10000];
0366             pszName[0] = '\0';
0367 
0368             if (vWords[1] == "352" && vWords.size() >= 8)
0369             {
0370                 // index 7 is limited to 16 characters
0371                 // could get full length name at index 10, but would be different from join messages
0372                 strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
0373                 printf("IRC got who\n");
0374             }
0375 
0376             if (vWords[1] == "JOIN" && vWords[0].size() > 1)
0377             {
0378                 // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
0379                 strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
0380                 if (strchr(pszName, '!'))
0381                     *strchr(pszName, '!') = '\0';
0382                 printf("IRC got join\n");
0383             }
0384 
0385             if (pszName[0] == 'u')
0386             {
0387                 CAddress addr;
0388                 if (DecodeAddress(pszName, addr))
0389                 {
0390                     addr.nTime = GetAdjustedTime();
0391                     if (AddAddress(addr, 51 * 60))
0392                         printf("IRC got new address: %s\n", addr.ToString().c_str());
0393                     nGotIRCAddresses++;
0394                 }
0395                 else
0396                 {
0397                     printf("IRC decode failed\n");
0398                 }
0399             }
0400         }
0401         closesocket(hSocket);
0402         hSocket = INVALID_SOCKET;
0403 
0404         if (GetTime() - nStart > 20 * 60)
0405         {
0406             nErrorWait /= 3;
0407             nRetryWait /= 3;
0408         }
0409 
0410         nRetryWait = nRetryWait * 11 / 10;
0411         if (!Wait(nRetryWait += 60))
0412             return;
0413     }
0414 }
0415 
0416 
0417 
0418 
0419 
0420 
0421 
0422 
0423 
0424 
0425 #ifdef TEST
0426 int main(int argc, char *argv[])
0427 {
0428     WSADATA wsadata;
0429     if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
0430     {
0431         printf("Error at WSAStartup()\n");
0432         return false;
0433     }
0434 
0435     ThreadIRCSeed(NULL);
0436 
0437     WSACleanup();
0438     return 0;
0439 }
0440 #endif