aboutsummaryrefslogtreecommitdiff
path: root/irc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'irc.cpp')
-rw-r--r--irc.cpp314
1 files changed, 314 insertions, 0 deletions
diff --git a/irc.cpp b/irc.cpp
new file mode 100644
index 0000000000..3518df2491
--- /dev/null
+++ b/irc.cpp
@@ -0,0 +1,314 @@
+// Copyright (c) 2009 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"
+
+
+map<vector<unsigned char>, CAddress> mapIRCAddresses;
+CCriticalSection cs_mapIRCAddresses;
+
+
+
+
+#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);
+ return true;
+}
+
+
+
+
+
+
+static bool Send(SOCKET hSocket, const char* pszSend)
+{
+ if (strstr(pszSend, "PONG") != pszSend)
+ printf("SENDING: %s\n", pszSend);
+ const char* psz = pszSend;
+ const char* pszEnd = psz + strlen(psz);
+ while (psz < pszEnd)
+ {
+ int ret = send(hSocket, psz, pszEnd - psz, 0);
+ 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;
+ }
+}
+
+bool RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL)
+{
+ loop
+ {
+ string strLine;
+ if (!RecvLineIRC(hSocket, strLine))
+ return false;
+ printf("IRC %s\n", strLine.c_str());
+ if (psz1 && strLine.find(psz1) != -1)
+ return true;
+ if (psz2 && strLine.find(psz2) != -1)
+ return true;
+ if (psz3 && strLine.find(psz3) != -1)
+ return true;
+ }
+}
+
+bool Wait(int nSeconds)
+{
+ if (fShutdown)
+ return false;
+ printf("Waiting %d seconds to reconnect to IRC\n", nSeconds);
+ for (int i = 0; i < nSeconds; i++)
+ {
+ if (fShutdown)
+ return false;
+ Sleep(1000);
+ }
+ return true;
+}
+
+
+
+void ThreadIRCSeed(void* parg)
+{
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+ int nErrorWait = 10;
+ int nRetryWait = 10;
+
+ while (!fShutdown)
+ {
+ CAddress addrConnect("216.155.130.130:6667");
+ 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);
+ nErrorWait = nErrorWait * 11 / 10;
+ if (Wait(nErrorWait += 60))
+ continue;
+ else
+ return;
+ }
+
+ string strMyName = EncodeAddress(addrLocalHost);
+
+ if (!addrLocalHost.IsRoutable())
+ 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());
+
+ if (!RecvUntil(hSocket, " 004 "))
+ {
+ closesocket(hSocket);
+ 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;
+ printf("IRC %s\n", strLine.c_str());
+
+ 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
+ strcpy(pszName, vWords[7].c_str());
+ printf("GOT WHO: [%s] ", pszName);
+ }
+
+ if (vWords[1] == "JOIN" && vWords[0].size() > 1)
+ {
+ // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
+ strcpy(pszName, vWords[0].c_str() + 1);
+ if (strchr(pszName, '!'))
+ *strchr(pszName, '!') = '\0';
+ printf("GOT JOIN: [%s] ", pszName);
+ }
+
+ if (pszName[0] == 'u')
+ {
+ CAddress addr;
+ if (DecodeAddress(pszName, addr))
+ {
+ CAddrDB addrdb;
+ if (AddAddress(addrdb, addr))
+ printf("new ");
+ else
+ {
+ // make it try connecting again
+ CRITICAL_BLOCK(cs_mapAddresses)
+ if (mapAddresses.count(addr.GetKey()))
+ mapAddresses[addr.GetKey()].nLastFailed = 0;
+ }
+ addr.print();
+
+ CRITICAL_BLOCK(cs_mapIRCAddresses)
+ mapIRCAddresses.insert(make_pair(addr.GetKey(), addr));
+ }
+ else
+ {
+ printf("decode failed\n");
+ }
+ }
+ }
+ closesocket(hSocket);
+
+ 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