-
+ 775141F07CE491A331E51FE97B43D4F2D1891EB720FC6706D06747959653E8171CB46DAA77EFD73E202B1E1419F26036C92CC106DE34D22245489B3F7B333BCB
bitcoin/src/irc.cpp
(0 . 0)(1 . 440)
6082 // Copyright (c) 2009-2010 Satoshi Nakamoto
6083 // Copyright (c) 2009-2012 The Bitcoin developers
6084 // Distributed under the MIT/X11 software license, see the accompanying
6085 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
6086
6087 #include "headers.h"
6088 #include "irc.h"
6089 #include "net.h"
6090 #include "strlcpy.h"
6091
6092 using namespace std;
6093 using namespace boost;
6094
6095 int nGotIRCAddresses = 0;
6096 bool fGotExternalIP = false;
6097
6098 void ThreadIRCSeed2(void* parg);
6099
6100
6101
6102
6103 #pragma pack(push, 1)
6104 struct ircaddr
6105 {
6106 int ip;
6107 short port;
6108 };
6109 #pragma pack(pop)
6110
6111 string EncodeAddress(const CAddress& addr)
6112 {
6113 struct ircaddr tmp;
6114 tmp.ip = addr.ip;
6115 tmp.port = addr.port;
6116
6117 vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
6118 return string("u") + EncodeBase58Check(vch);
6119 }
6120
6121 bool DecodeAddress(string str, CAddress& addr)
6122 {
6123 vector<unsigned char> vch;
6124 if (!DecodeBase58Check(str.substr(1), vch))
6125 return false;
6126
6127 struct ircaddr tmp;
6128 if (vch.size() != sizeof(tmp))
6129 return false;
6130 memcpy(&tmp, &vch[0], sizeof(tmp));
6131
6132 addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
6133 return true;
6134 }
6135
6136
6137
6138
6139
6140
6141 static bool Send(SOCKET hSocket, const char* pszSend)
6142 {
6143 if (strstr(pszSend, "PONG") != pszSend)
6144 printf("IRC SENDING: %s\n", pszSend);
6145 const char* psz = pszSend;
6146 const char* pszEnd = psz + strlen(psz);
6147 while (psz < pszEnd)
6148 {
6149 int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
6150 if (ret < 0)
6151 return false;
6152 psz += ret;
6153 }
6154 return true;
6155 }
6156
6157 bool RecvLine(SOCKET hSocket, string& strLine)
6158 {
6159 strLine = "";
6160 loop
6161 {
6162 char c;
6163 int nBytes = recv(hSocket, &c, 1, 0);
6164 if (nBytes > 0)
6165 {
6166 if (c == '\n')
6167 continue;
6168 if (c == '\r')
6169 return true;
6170 strLine += c;
6171 if (strLine.size() >= 9000)
6172 return true;
6173 }
6174 else if (nBytes <= 0)
6175 {
6176 if (fShutdown)
6177 return false;
6178 if (nBytes < 0)
6179 {
6180 int nErr = WSAGetLastError();
6181 if (nErr == WSAEMSGSIZE)
6182 continue;
6183 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
6184 {
6185 Sleep(10);
6186 continue;
6187 }
6188 }
6189 if (!strLine.empty())
6190 return true;
6191 if (nBytes == 0)
6192 {
6193 // socket closed
6194 printf("socket closed\n");
6195 return false;
6196 }
6197 else
6198 {
6199 // socket error
6200 int nErr = WSAGetLastError();
6201 printf("recv failed: %d\n", nErr);
6202 return false;
6203 }
6204 }
6205 }
6206 }
6207
6208 bool RecvLineIRC(SOCKET hSocket, string& strLine)
6209 {
6210 loop
6211 {
6212 bool fRet = RecvLine(hSocket, strLine);
6213 if (fRet)
6214 {
6215 if (fShutdown)
6216 return false;
6217 vector<string> vWords;
6218 ParseString(strLine, ' ', vWords);
6219 if (vWords.size() >= 1 && vWords[0] == "PING")
6220 {
6221 strLine[1] = 'O';
6222 strLine += '\r';
6223 Send(hSocket, strLine.c_str());
6224 continue;
6225 }
6226 }
6227 return fRet;
6228 }
6229 }
6230
6231 int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
6232 {
6233 loop
6234 {
6235 string strLine;
6236 strLine.reserve(10000);
6237 if (!RecvLineIRC(hSocket, strLine))
6238 return 0;
6239 printf("IRC %s\n", strLine.c_str());
6240 if (psz1 && strLine.find(psz1) != -1)
6241 return 1;
6242 if (psz2 && strLine.find(psz2) != -1)
6243 return 2;
6244 if (psz3 && strLine.find(psz3) != -1)
6245 return 3;
6246 if (psz4 && strLine.find(psz4) != -1)
6247 return 4;
6248 }
6249 }
6250
6251 bool Wait(int nSeconds)
6252 {
6253 if (fShutdown)
6254 return false;
6255 printf("IRC waiting %d seconds to reconnect\n", nSeconds);
6256 for (int i = 0; i < nSeconds; i++)
6257 {
6258 if (fShutdown)
6259 return false;
6260 Sleep(1000);
6261 }
6262 return true;
6263 }
6264
6265 bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
6266 {
6267 strRet.clear();
6268 loop
6269 {
6270 string strLine;
6271 if (!RecvLineIRC(hSocket, strLine))
6272 return false;
6273
6274 vector<string> vWords;
6275 ParseString(strLine, ' ', vWords);
6276 if (vWords.size() < 2)
6277 continue;
6278
6279 if (vWords[1] == psz1)
6280 {
6281 printf("IRC %s\n", strLine.c_str());
6282 strRet = strLine;
6283 return true;
6284 }
6285 }
6286 }
6287
6288 bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
6289 {
6290 Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
6291
6292 string strLine;
6293 if (!RecvCodeLine(hSocket, "302", strLine))
6294 return false;
6295
6296 vector<string> vWords;
6297 ParseString(strLine, ' ', vWords);
6298 if (vWords.size() < 4)
6299 return false;
6300
6301 string str = vWords[3];
6302 if (str.rfind("@") == string::npos)
6303 return false;
6304 string strHost = str.substr(str.rfind("@")+1);
6305
6306 // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
6307 // but in case another IRC is ever used this should work.
6308 printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
6309 if (fUseProxy)
6310 return false;
6311 CAddress addr(strHost, 0, true);
6312 if (!addr.IsValid())
6313 return false;
6314 ipRet = addr.ip;
6315
6316 return true;
6317 }
6318
6319
6320
6321 void ThreadIRCSeed(void* parg)
6322 {
6323 IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
6324 try
6325 {
6326 ThreadIRCSeed2(parg);
6327 }
6328 catch (std::exception& e) {
6329 PrintExceptionContinue(&e, "ThreadIRCSeed()");
6330 } catch (...) {
6331 PrintExceptionContinue(NULL, "ThreadIRCSeed()");
6332 }
6333 printf("ThreadIRCSeed exiting\n");
6334 }
6335
6336 void ThreadIRCSeed2(void* parg)
6337 {
6338 /* Dont advertise on IRC if we don't allow incoming connections */
6339 if (mapArgs.count("-connect") || fNoListen)
6340 return;
6341
6342 if (GetBoolArg("-noirc"))
6343 return;
6344 printf("ThreadIRCSeed started\n");
6345 int nErrorWait = 10;
6346 int nRetryWait = 10;
6347 bool fNameInUse = false;
6348
6349 while (!fShutdown)
6350 {
6351 CAddress addrConnect("92.243.23.21", 6667); // irc.lfnet.org
6352
6353 CAddress addrIRC("irc.lfnet.org", 6667, true);
6354 if (addrIRC.IsValid())
6355 addrConnect = addrIRC;
6356
6357 SOCKET hSocket;
6358 if (!ConnectSocket(addrConnect, hSocket))
6359 {
6360 printf("IRC connect failed\n");
6361 nErrorWait = nErrorWait * 11 / 10;
6362 if (Wait(nErrorWait += 60))
6363 continue;
6364 else
6365 return;
6366 }
6367
6368 if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
6369 {
6370 closesocket(hSocket);
6371 hSocket = INVALID_SOCKET;
6372 nErrorWait = nErrorWait * 11 / 10;
6373 if (Wait(nErrorWait += 60))
6374 continue;
6375 else
6376 return;
6377 }
6378
6379 string strMyName;
6380 if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
6381 strMyName = EncodeAddress(addrLocalHost);
6382 else
6383 strMyName = strprintf("x%u", GetRand(1000000000));
6384
6385 Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
6386 Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
6387
6388 int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
6389 if (nRet != 1)
6390 {
6391 closesocket(hSocket);
6392 hSocket = INVALID_SOCKET;
6393 if (nRet == 2)
6394 {
6395 printf("IRC name already in use\n");
6396 fNameInUse = true;
6397 Wait(10);
6398 continue;
6399 }
6400 nErrorWait = nErrorWait * 11 / 10;
6401 if (Wait(nErrorWait += 60))
6402 continue;
6403 else
6404 return;
6405 }
6406 Sleep(500);
6407
6408 // Get our external IP from the IRC server and re-nick before joining the channel
6409 CAddress addrFromIRC;
6410 if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
6411 {
6412 printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
6413 if (!fUseProxy && addrFromIRC.IsRoutable())
6414 {
6415 // IRC lets you to re-nick
6416 fGotExternalIP = true;
6417 addrLocalHost.ip = addrFromIRC.ip;
6418 strMyName = EncodeAddress(addrLocalHost);
6419 Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
6420 }
6421 }
6422
6423 if (fTestNet) {
6424 Send(hSocket, "JOIN #bitcoinTEST\r");
6425 Send(hSocket, "WHO #bitcoinTEST\r");
6426 } else {
6427 // randomly join #bitcoin00-#bitcoin99
6428 int channel_number = GetRandInt(100);
6429 Send(hSocket, strprintf("JOIN #bitcoin%02d\r", channel_number).c_str());
6430 Send(hSocket, strprintf("WHO #bitcoin%02d\r", channel_number).c_str());
6431 }
6432
6433 int64 nStart = GetTime();
6434 string strLine;
6435 strLine.reserve(10000);
6436 while (!fShutdown && RecvLineIRC(hSocket, strLine))
6437 {
6438 if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
6439 continue;
6440
6441 vector<string> vWords;
6442 ParseString(strLine, ' ', vWords);
6443 if (vWords.size() < 2)
6444 continue;
6445
6446 char pszName[10000];
6447 pszName[0] = '\0';
6448
6449 if (vWords[1] == "352" && vWords.size() >= 8)
6450 {
6451 // index 7 is limited to 16 characters
6452 // could get full length name at index 10, but would be different from join messages
6453 strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
6454 printf("IRC got who\n");
6455 }
6456
6457 if (vWords[1] == "JOIN" && vWords[0].size() > 1)
6458 {
6459 // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
6460 strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
6461 if (strchr(pszName, '!'))
6462 *strchr(pszName, '!') = '\0';
6463 printf("IRC got join\n");
6464 }
6465
6466 if (pszName[0] == 'u')
6467 {
6468 CAddress addr;
6469 if (DecodeAddress(pszName, addr))
6470 {
6471 addr.nTime = GetAdjustedTime();
6472 if (AddAddress(addr, 51 * 60))
6473 printf("IRC got new address: %s\n", addr.ToString().c_str());
6474 nGotIRCAddresses++;
6475 }
6476 else
6477 {
6478 printf("IRC decode failed\n");
6479 }
6480 }
6481 }
6482 closesocket(hSocket);
6483 hSocket = INVALID_SOCKET;
6484
6485 if (GetTime() - nStart > 20 * 60)
6486 {
6487 nErrorWait /= 3;
6488 nRetryWait /= 3;
6489 }
6490
6491 nRetryWait = nRetryWait * 11 / 10;
6492 if (!Wait(nRetryWait += 60))
6493 return;
6494 }
6495 }
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506 #ifdef TEST
6507 int main(int argc, char *argv[])
6508 {
6509 WSADATA wsadata;
6510 if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
6511 {
6512 printf("Error at WSAStartup()\n");
6513 return false;
6514 }
6515
6516 ThreadIRCSeed(NULL);
6517
6518 WSACleanup();
6519 return 0;
6520 }
6521 #endif