-
+ 0DFF7FB1FE32F1A2C7DFCC7F5259A9A7CD4995181A5F023A2F447D58AE91481808087CCC7E95F1EEA959F9FD20CED92A37B6BB46A78AE4EB60BF99C5299493D9
bitcoin/src/irc.cpp
(0 . 0)(1 . 471)
6547 // /****************************\
6548 // * EXPERIMENTAL BRANCH. *
6549 // * FOR LABORATORY USE ONLY. *
6550 // ********************************
6551 // ************
6552 // **************
6553 // ****************
6554 // **** **** ****
6555 // *** *** ***
6556 // *** *** ***
6557 // *** * * **
6558 // ******** ********
6559 // ******* ******
6560 // *** **
6561 // * ******* **
6562 // ** * * * * *
6563 // ** * * ***
6564 // **** * * * * ****
6565 // **** *** * * ** ***
6566 // **** ********* ******
6567 // ******* ***** *******
6568 // ********* ****** **
6569 // ** ****** ******
6570 // ** ******* **
6571 // ** ******* ***
6572 // **** ******** ************
6573 // ************ ************
6574 // ******** *******
6575 // ****** ****
6576 // *** ***
6577 // ********************************
6578 // Copyright (c) 2009-2010 Satoshi Nakamoto
6579 // Copyright (c) 2009-2012 The Bitcoin developers
6580 // Distributed under the MIT/X11 software license, see the accompanying
6581 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
6582
6583 #include "headers.h"
6584 #include "irc.h"
6585 #include "net.h"
6586 #include "strlcpy.h"
6587
6588 using namespace std;
6589 using namespace boost;
6590
6591 int nGotIRCAddresses = 0;
6592 bool fGotExternalIP = false;
6593
6594 void ThreadIRCSeed2(void* parg);
6595
6596
6597
6598
6599 #pragma pack(push, 1)
6600 struct ircaddr
6601 {
6602 int ip;
6603 short port;
6604 };
6605 #pragma pack(pop)
6606
6607 string EncodeAddress(const CAddress& addr)
6608 {
6609 struct ircaddr tmp;
6610 tmp.ip = addr.ip;
6611 tmp.port = addr.port;
6612
6613 vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
6614 return string("u") + EncodeBase58Check(vch);
6615 }
6616
6617 bool DecodeAddress(string str, CAddress& addr)
6618 {
6619 vector<unsigned char> vch;
6620 if (!DecodeBase58Check(str.substr(1), vch))
6621 return false;
6622
6623 struct ircaddr tmp;
6624 if (vch.size() != sizeof(tmp))
6625 return false;
6626 memcpy(&tmp, &vch[0], sizeof(tmp));
6627
6628 addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
6629 return true;
6630 }
6631
6632
6633
6634
6635
6636
6637 static bool Send(SOCKET hSocket, const char* pszSend)
6638 {
6639 if (strstr(pszSend, "PONG") != pszSend)
6640 printf("IRC SENDING: %s\n", pszSend);
6641 const char* psz = pszSend;
6642 const char* pszEnd = psz + strlen(psz);
6643 while (psz < pszEnd)
6644 {
6645 int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
6646 if (ret < 0)
6647 return false;
6648 psz += ret;
6649 }
6650 return true;
6651 }
6652
6653 bool RecvLine(SOCKET hSocket, string& strLine)
6654 {
6655 strLine = "";
6656 loop
6657 {
6658 char c;
6659 int nBytes = recv(hSocket, &c, 1, 0);
6660 if (nBytes > 0)
6661 {
6662 if (c == '\n')
6663 continue;
6664 if (c == '\r')
6665 return true;
6666 strLine += c;
6667 if (strLine.size() >= 9000)
6668 return true;
6669 }
6670 else if (nBytes <= 0)
6671 {
6672 if (fShutdown)
6673 return false;
6674 if (nBytes < 0)
6675 {
6676 int nErr = WSAGetLastError();
6677 if (nErr == WSAEMSGSIZE)
6678 continue;
6679 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
6680 {
6681 Sleep(10);
6682 continue;
6683 }
6684 }
6685 if (!strLine.empty())
6686 return true;
6687 if (nBytes == 0)
6688 {
6689 // socket closed
6690 printf("socket closed\n");
6691 return false;
6692 }
6693 else
6694 {
6695 // socket error
6696 int nErr = WSAGetLastError();
6697 printf("recv failed: %d\n", nErr);
6698 return false;
6699 }
6700 }
6701 }
6702 }
6703
6704 bool RecvLineIRC(SOCKET hSocket, string& strLine)
6705 {
6706 loop
6707 {
6708 bool fRet = RecvLine(hSocket, strLine);
6709 if (fRet)
6710 {
6711 if (fShutdown)
6712 return false;
6713 vector<string> vWords;
6714 ParseString(strLine, ' ', vWords);
6715 if (vWords.size() >= 1 && vWords[0] == "PING")
6716 {
6717 strLine[1] = 'O';
6718 strLine += '\r';
6719 Send(hSocket, strLine.c_str());
6720 continue;
6721 }
6722 }
6723 return fRet;
6724 }
6725 }
6726
6727 int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
6728 {
6729 loop
6730 {
6731 string strLine;
6732 strLine.reserve(10000);
6733 if (!RecvLineIRC(hSocket, strLine))
6734 return 0;
6735 printf("IRC %s\n", strLine.c_str());
6736 if (psz1 && strLine.find(psz1) != -1)
6737 return 1;
6738 if (psz2 && strLine.find(psz2) != -1)
6739 return 2;
6740 if (psz3 && strLine.find(psz3) != -1)
6741 return 3;
6742 if (psz4 && strLine.find(psz4) != -1)
6743 return 4;
6744 }
6745 }
6746
6747 bool Wait(int nSeconds)
6748 {
6749 if (fShutdown)
6750 return false;
6751 printf("IRC waiting %d seconds to reconnect\n", nSeconds);
6752 for (int i = 0; i < nSeconds; i++)
6753 {
6754 if (fShutdown)
6755 return false;
6756 Sleep(1000);
6757 }
6758 return true;
6759 }
6760
6761 bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
6762 {
6763 strRet.clear();
6764 loop
6765 {
6766 string strLine;
6767 if (!RecvLineIRC(hSocket, strLine))
6768 return false;
6769
6770 vector<string> vWords;
6771 ParseString(strLine, ' ', vWords);
6772 if (vWords.size() < 2)
6773 continue;
6774
6775 if (vWords[1] == psz1)
6776 {
6777 printf("IRC %s\n", strLine.c_str());
6778 strRet = strLine;
6779 return true;
6780 }
6781 }
6782 }
6783
6784 bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
6785 {
6786 Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
6787
6788 string strLine;
6789 if (!RecvCodeLine(hSocket, "302", strLine))
6790 return false;
6791
6792 vector<string> vWords;
6793 ParseString(strLine, ' ', vWords);
6794 if (vWords.size() < 4)
6795 return false;
6796
6797 string str = vWords[3];
6798 if (str.rfind("@") == string::npos)
6799 return false;
6800 string strHost = str.substr(str.rfind("@")+1);
6801
6802 // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
6803 // but in case another IRC is ever used this should work.
6804 printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
6805 if (fUseProxy)
6806 return false;
6807 CAddress addr(strHost, 0, true);
6808 if (!addr.IsValid())
6809 return false;
6810 ipRet = addr.ip;
6811
6812 return true;
6813 }
6814
6815
6816
6817 void ThreadIRCSeed(void* parg)
6818 {
6819 IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
6820 try
6821 {
6822 ThreadIRCSeed2(parg);
6823 }
6824 catch (std::exception& e) {
6825 PrintExceptionContinue(&e, "ThreadIRCSeed()");
6826 } catch (...) {
6827 PrintExceptionContinue(NULL, "ThreadIRCSeed()");
6828 }
6829 printf("ThreadIRCSeed exiting\n");
6830 }
6831
6832 void ThreadIRCSeed2(void* parg)
6833 {
6834 /* Dont advertise on IRC if we don't allow incoming connections */
6835 if (mapArgs.count("-connect") || fNoListen)
6836 return;
6837
6838 if (GetBoolArg("-noirc"))
6839 return;
6840 printf("ThreadIRCSeed started\n");
6841 int nErrorWait = 10;
6842 int nRetryWait = 10;
6843 bool fNameInUse = false;
6844
6845 while (!fShutdown)
6846 {
6847 CAddress addrConnect("92.243.23.21", 6667); // irc.lfnet.org
6848
6849 CAddress addrIRC("irc.lfnet.org", 6667, true);
6850 if (addrIRC.IsValid())
6851 addrConnect = addrIRC;
6852
6853 SOCKET hSocket;
6854 if (!ConnectSocket(addrConnect, hSocket))
6855 {
6856 printf("IRC connect failed\n");
6857 nErrorWait = nErrorWait * 11 / 10;
6858 if (Wait(nErrorWait += 60))
6859 continue;
6860 else
6861 return;
6862 }
6863
6864 if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
6865 {
6866 closesocket(hSocket);
6867 hSocket = INVALID_SOCKET;
6868 nErrorWait = nErrorWait * 11 / 10;
6869 if (Wait(nErrorWait += 60))
6870 continue;
6871 else
6872 return;
6873 }
6874
6875 string strMyName;
6876 if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
6877 strMyName = EncodeAddress(addrLocalHost);
6878 else
6879 strMyName = strprintf("x%u", GetRand(1000000000));
6880
6881 Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
6882 Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
6883
6884 int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
6885 if (nRet != 1)
6886 {
6887 closesocket(hSocket);
6888 hSocket = INVALID_SOCKET;
6889 if (nRet == 2)
6890 {
6891 printf("IRC name already in use\n");
6892 fNameInUse = true;
6893 Wait(10);
6894 continue;
6895 }
6896 nErrorWait = nErrorWait * 11 / 10;
6897 if (Wait(nErrorWait += 60))
6898 continue;
6899 else
6900 return;
6901 }
6902 Sleep(500);
6903
6904 // Get our external IP from the IRC server and re-nick before joining the channel
6905 CAddress addrFromIRC;
6906 if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
6907 {
6908 printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
6909 if (!fUseProxy && addrFromIRC.IsRoutable())
6910 {
6911 // IRC lets you to re-nick
6912 fGotExternalIP = true;
6913 addrLocalHost.ip = addrFromIRC.ip;
6914 strMyName = EncodeAddress(addrLocalHost);
6915 Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
6916 }
6917 }
6918
6919 if (fTestNet) {
6920 Send(hSocket, "JOIN #bitcoinTEST\r");
6921 Send(hSocket, "WHO #bitcoinTEST\r");
6922 } else {
6923 // randomly join #bitcoin00-#bitcoin99
6924 int channel_number = GetRandInt(100);
6925 Send(hSocket, strprintf("JOIN #bitcoin%02d\r", channel_number).c_str());
6926 Send(hSocket, strprintf("WHO #bitcoin%02d\r", channel_number).c_str());
6927 }
6928
6929 int64 nStart = GetTime();
6930 string strLine;
6931 strLine.reserve(10000);
6932 while (!fShutdown && RecvLineIRC(hSocket, strLine))
6933 {
6934 if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
6935 continue;
6936
6937 vector<string> vWords;
6938 ParseString(strLine, ' ', vWords);
6939 if (vWords.size() < 2)
6940 continue;
6941
6942 char pszName[10000];
6943 pszName[0] = '\0';
6944
6945 if (vWords[1] == "352" && vWords.size() >= 8)
6946 {
6947 // index 7 is limited to 16 characters
6948 // could get full length name at index 10, but would be different from join messages
6949 strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
6950 printf("IRC got who\n");
6951 }
6952
6953 if (vWords[1] == "JOIN" && vWords[0].size() > 1)
6954 {
6955 // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
6956 strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
6957 if (strchr(pszName, '!'))
6958 *strchr(pszName, '!') = '\0';
6959 printf("IRC got join\n");
6960 }
6961
6962 if (pszName[0] == 'u')
6963 {
6964 CAddress addr;
6965 if (DecodeAddress(pszName, addr))
6966 {
6967 addr.nTime = GetAdjustedTime();
6968 if (AddAddress(addr, 51 * 60))
6969 printf("IRC got new address: %s\n", addr.ToString().c_str());
6970 nGotIRCAddresses++;
6971 }
6972 else
6973 {
6974 printf("IRC decode failed\n");
6975 }
6976 }
6977 }
6978 closesocket(hSocket);
6979 hSocket = INVALID_SOCKET;
6980
6981 if (GetTime() - nStart > 20 * 60)
6982 {
6983 nErrorWait /= 3;
6984 nRetryWait /= 3;
6985 }
6986
6987 nRetryWait = nRetryWait * 11 / 10;
6988 if (!Wait(nRetryWait += 60))
6989 return;
6990 }
6991 }
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002 #ifdef TEST
7003 int main(int argc, char *argv[])
7004 {
7005 WSADATA wsadata;
7006 if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
7007 {
7008 printf("Error at WSAStartup()\n");
7009 return false;
7010 }
7011
7012 ThreadIRCSeed(NULL);
7013
7014 WSACleanup();
7015 return 0;
7016 }
7017 #endif