Gavin: BIO_FLAGS_BASE64_NO_NL
[bitcoinplatinum.git] / irc.cpp
blobdaa9a0db618a7feb747f115266af20702df30580
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
5 #include "headers.h"
7 int nGotIRCAddresses = 0;
11 #pragma pack(push, 1)
12 struct ircaddr
14 int ip;
15 short port;
17 #pragma pack(pop)
19 string EncodeAddress(const CAddress& addr)
21 struct ircaddr tmp;
22 tmp.ip = addr.ip;
23 tmp.port = addr.port;
25 vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
26 return string("u") + EncodeBase58Check(vch);
29 bool DecodeAddress(string str, CAddress& addr)
31 vector<unsigned char> vch;
32 if (!DecodeBase58Check(str.substr(1), vch))
33 return false;
35 struct ircaddr tmp;
36 if (vch.size() != sizeof(tmp))
37 return false;
38 memcpy(&tmp, &vch[0], sizeof(tmp));
40 addr = CAddress(tmp.ip, tmp.port, NODE_NETWORK);
41 return true;
49 static bool Send(SOCKET hSocket, const char* pszSend)
51 if (strstr(pszSend, "PONG") != pszSend)
52 printf("IRC SENDING: %s\n", pszSend);
53 const char* psz = pszSend;
54 const char* pszEnd = psz + strlen(psz);
55 while (psz < pszEnd)
57 int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
58 if (ret < 0)
59 return false;
60 psz += ret;
62 return true;
65 bool RecvLine(SOCKET hSocket, string& strLine)
67 strLine = "";
68 loop
70 char c;
71 int nBytes = recv(hSocket, &c, 1, 0);
72 if (nBytes > 0)
74 if (c == '\n')
75 continue;
76 if (c == '\r')
77 return true;
78 strLine += c;
79 if (strLine.size() >= 9000)
80 return true;
82 else if (nBytes <= 0)
84 if (!strLine.empty())
85 return true;
86 // socket closed
87 printf("IRC socket closed\n");
88 return false;
90 else
92 // socket error
93 int nErr = WSAGetLastError();
94 if (nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
96 printf("IRC recv failed: %d\n", nErr);
97 return false;
103 bool RecvLineIRC(SOCKET hSocket, string& strLine)
105 loop
107 bool fRet = RecvLine(hSocket, strLine);
108 if (fRet)
110 if (fShutdown)
111 return false;
112 vector<string> vWords;
113 ParseString(strLine, ' ', vWords);
114 if (vWords.size() >= 1 && vWords[0] == "PING")
116 strLine[1] = 'O';
117 strLine += '\r';
118 Send(hSocket, strLine.c_str());
119 continue;
122 return fRet;
126 int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL)
128 loop
130 string strLine;
131 if (!RecvLineIRC(hSocket, strLine))
132 return 0;
133 printf("IRC %s\n", strLine.c_str());
134 if (psz1 && strLine.find(psz1) != -1)
135 return 1;
136 if (psz2 && strLine.find(psz2) != -1)
137 return 2;
138 if (psz3 && strLine.find(psz3) != -1)
139 return 3;
143 bool Wait(int nSeconds)
145 if (fShutdown)
146 return false;
147 printf("IRC waiting %d seconds to reconnect\n", nSeconds);
148 for (int i = 0; i < nSeconds; i++)
150 if (fShutdown)
151 return false;
152 Sleep(1000);
154 return true;
159 void ThreadIRCSeed(void* parg)
161 if (mapArgs.count("-connect"))
162 return;
163 if (mapArgs.count("-noirc"))
164 return;
165 printf("ThreadIRCSeed started\n");
166 int nErrorWait = 10;
167 int nRetryWait = 10;
168 bool fNameInUse = false;
169 bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
171 while (!fShutdown)
173 //CAddress addrConnect("216.155.130.130:6667"); // chat.freenode.net
174 CAddress addrConnect("92.243.23.21:6667"); // irc.lfnet.org
175 if (!fTOR)
177 //struct hostent* phostent = gethostbyname("chat.freenode.net");
178 struct hostent* phostent = gethostbyname("irc.lfnet.org");
179 if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])
180 addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(6667));
183 SOCKET hSocket;
184 if (!ConnectSocket(addrConnect, hSocket))
186 printf("IRC connect failed\n");
187 nErrorWait = nErrorWait * 11 / 10;
188 if (Wait(nErrorWait += 60))
189 continue;
190 else
191 return;
194 if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname"))
196 closesocket(hSocket);
197 hSocket = INVALID_SOCKET;
198 nErrorWait = nErrorWait * 11 / 10;
199 if (Wait(nErrorWait += 60))
200 continue;
201 else
202 return;
205 string strMyName;
206 if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
207 strMyName = EncodeAddress(addrLocalHost);
208 else
209 strMyName = strprintf("x%u", GetRand(1000000000));
211 Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
212 Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
214 int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
215 if (nRet != 1)
217 closesocket(hSocket);
218 hSocket = INVALID_SOCKET;
219 if (nRet == 2)
221 printf("IRC name already in use\n");
222 fNameInUse = true;
223 Wait(10);
224 continue;
226 nErrorWait = nErrorWait * 11 / 10;
227 if (Wait(nErrorWait += 60))
228 continue;
229 else
230 return;
232 Sleep(500);
234 Send(hSocket, "JOIN #bitcoin\r");
235 Send(hSocket, "WHO #bitcoin\r");
237 int64 nStart = GetTime();
238 string strLine;
239 while (!fShutdown && RecvLineIRC(hSocket, strLine))
241 if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
242 continue;
244 vector<string> vWords;
245 ParseString(strLine, ' ', vWords);
246 if (vWords.size() < 2)
247 continue;
249 char pszName[10000];
250 pszName[0] = '\0';
252 if (vWords[1] == "352" && vWords.size() >= 8)
254 // index 7 is limited to 16 characters
255 // could get full length name at index 10, but would be different from join messages
256 strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
257 printf("IRC got who\n");
260 if (vWords[1] == "JOIN" && vWords[0].size() > 1)
262 // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
263 strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
264 if (strchr(pszName, '!'))
265 *strchr(pszName, '!') = '\0';
266 printf("IRC got join\n");
269 if (pszName[0] == 'u')
271 CAddress addr;
272 if (DecodeAddress(pszName, addr))
274 addr.nTime = GetAdjustedTime() - 51 * 60;
275 if (AddAddress(addr))
276 printf("IRC got new address\n");
277 nGotIRCAddresses++;
279 else
281 printf("IRC decode failed\n");
285 closesocket(hSocket);
286 hSocket = INVALID_SOCKET;
288 // IRC usually blocks TOR, so only try once
289 if (fTOR)
290 return;
292 if (GetTime() - nStart > 20 * 60)
294 nErrorWait /= 3;
295 nRetryWait /= 3;
298 nRetryWait = nRetryWait * 11 / 10;
299 if (!Wait(nRetryWait += 60))
300 return;
313 #ifdef TEST
314 int main(int argc, char *argv[])
316 WSADATA wsadata;
317 if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
319 printf("Error at WSAStartup()\n");
320 return false;
323 ThreadIRCSeed(NULL);
325 WSACleanup();
326 return 0;
328 #endif