]> Git Repo - VerusCoin.git/blob - src/irc.cpp
Merge pull request #1354 from fanquake/master
[VerusCoin.git] / src / irc.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "irc.h"
7 #include "net.h"
8 #include "strlcpy.h"
9 #include "base58.h"
10
11 using namespace std;
12 using namespace boost;
13
14 int nGotIRCAddresses = 0;
15
16 void ThreadIRCSeed2(void* parg);
17
18
19
20
21 #pragma pack(push, 1)
22 struct ircaddr
23 {
24     struct in_addr ip;
25     short port;
26 };
27 #pragma pack(pop)
28
29 string EncodeAddress(const CService& addr)
30 {
31     struct ircaddr tmp;
32     if (addr.GetInAddr(&tmp.ip))
33     {
34         tmp.port = htons(addr.GetPort());
35
36         vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
37         return string("u") + EncodeBase58Check(vch);
38     }
39     return "";
40 }
41
42 bool DecodeAddress(string str, CService& addr)
43 {
44     vector<unsigned char> vch;
45     if (!DecodeBase58Check(str.substr(1), vch))
46         return false;
47
48     struct ircaddr tmp;
49     if (vch.size() != sizeof(tmp))
50         return false;
51     memcpy(&tmp, &vch[0], sizeof(tmp));
52
53     addr = CService(tmp.ip, ntohs(tmp.port));
54     return true;
55 }
56
57
58
59
60
61
62 static bool Send(SOCKET hSocket, const char* pszSend)
63 {
64     if (strstr(pszSend, "PONG") != pszSend)
65         printf("IRC SENDING: %s\n", pszSend);
66     const char* psz = pszSend;
67     const char* pszEnd = psz + strlen(psz);
68     while (psz < pszEnd)
69     {
70         int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
71         if (ret < 0)
72             return false;
73         psz += ret;
74     }
75     return true;
76 }
77
78 bool RecvLineIRC(SOCKET hSocket, string& strLine)
79 {
80     loop
81     {
82         bool fRet = RecvLine(hSocket, strLine);
83         if (fRet)
84         {
85             if (fShutdown)
86                 return false;
87             vector<string> vWords;
88             ParseString(strLine, ' ', vWords);
89             if (vWords.size() >= 1 && vWords[0] == "PING")
90             {
91                 strLine[1] = 'O';
92                 strLine += '\r';
93                 Send(hSocket, strLine.c_str());
94                 continue;
95             }
96         }
97         return fRet;
98     }
99 }
100
101 int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
102 {
103     loop
104     {
105         string strLine;
106         strLine.reserve(10000);
107         if (!RecvLineIRC(hSocket, strLine))
108             return 0;
109         printf("IRC %s\n", strLine.c_str());
110         if (psz1 && strLine.find(psz1) != string::npos)
111             return 1;
112         if (psz2 && strLine.find(psz2) != string::npos)
113             return 2;
114         if (psz3 && strLine.find(psz3) != string::npos)
115             return 3;
116         if (psz4 && strLine.find(psz4) != string::npos)
117             return 4;
118     }
119 }
120
121 bool Wait(int nSeconds)
122 {
123     if (fShutdown)
124         return false;
125     printf("IRC waiting %d seconds to reconnect\n", nSeconds);
126     for (int i = 0; i < nSeconds; i++)
127     {
128         if (fShutdown)
129             return false;
130         Sleep(1000);
131     }
132     return true;
133 }
134
135 bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
136 {
137     strRet.clear();
138     loop
139     {
140         string strLine;
141         if (!RecvLineIRC(hSocket, strLine))
142             return false;
143
144         vector<string> vWords;
145         ParseString(strLine, ' ', vWords);
146         if (vWords.size() < 2)
147             continue;
148
149         if (vWords[1] == psz1)
150         {
151             printf("IRC %s\n", strLine.c_str());
152             strRet = strLine;
153             return true;
154         }
155     }
156 }
157
158 bool GetIPFromIRC(SOCKET hSocket, string strMyName, CNetAddr& ipRet)
159 {
160     Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
161
162     string strLine;
163     if (!RecvCodeLine(hSocket, "302", strLine))
164         return false;
165
166     vector<string> vWords;
167     ParseString(strLine, ' ', vWords);
168     if (vWords.size() < 4)
169         return false;
170
171     string str = vWords[3];
172     if (str.rfind("@") == string::npos)
173         return false;
174     string strHost = str.substr(str.rfind("@")+1);
175
176     // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
177     // but in case another IRC is ever used this should work.
178     printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
179     if (fUseProxy)
180         return false;
181     CNetAddr addr(strHost, true);
182     if (!addr.IsValid())
183         return false;
184     ipRet = addr;
185
186     return true;
187 }
188
189
190
191 void ThreadIRCSeed(void* parg)
192 {
193     IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
194     try
195     {
196         ThreadIRCSeed2(parg);
197     }
198     catch (std::exception& e) {
199         PrintExceptionContinue(&e, "ThreadIRCSeed()");
200     } catch (...) {
201         PrintExceptionContinue(NULL, "ThreadIRCSeed()");
202     }
203     printf("ThreadIRCSeed exited\n");
204 }
205
206 void ThreadIRCSeed2(void* parg)
207 {
208     /* Dont advertise on IRC if we don't allow incoming connections */
209     if (mapArgs.count("-connect") || fNoListen)
210         return;
211
212     if (!GetBoolArg("-irc", false))
213         return;
214
215     printf("ThreadIRCSeed started\n");
216     int nErrorWait = 10;
217     int nRetryWait = 10;
218
219     while (!fShutdown)
220     {
221         CService addrConnect("92.243.23.21", 6667); // irc.lfnet.org
222
223         CService addrIRC("irc.lfnet.org", 6667, true);
224         if (addrIRC.IsValid())
225             addrConnect = addrIRC;
226
227         SOCKET hSocket;
228         if (!ConnectSocket(addrConnect, hSocket))
229         {
230             printf("IRC connect failed\n");
231             nErrorWait = nErrorWait * 11 / 10;
232             if (Wait(nErrorWait += 60))
233                 continue;
234             else
235                 return;
236         }
237
238         if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
239         {
240             closesocket(hSocket);
241             hSocket = INVALID_SOCKET;
242             nErrorWait = nErrorWait * 11 / 10;
243             if (Wait(nErrorWait += 60))
244                 continue;
245             else
246                 return;
247         }
248
249         CNetAddr addrIPv4("1.2.3.4"); // arbitrary IPv4 address to make GetLocal prefer IPv4 addresses
250         CService addrLocal;
251         string strMyName;
252         if (GetLocal(addrLocal, &addrIPv4))
253             strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
254         if (strMyName == "")
255             strMyName = strprintf("x%u", GetRand(1000000000));
256
257         Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
258         Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
259
260         int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
261         if (nRet != 1)
262         {
263             closesocket(hSocket);
264             hSocket = INVALID_SOCKET;
265             if (nRet == 2)
266             {
267                 printf("IRC name already in use\n");
268                 Wait(10);
269                 continue;
270             }
271             nErrorWait = nErrorWait * 11 / 10;
272             if (Wait(nErrorWait += 60))
273                 continue;
274             else
275                 return;
276         }
277         Sleep(500);
278
279         // Get our external IP from the IRC server and re-nick before joining the channel
280         CNetAddr addrFromIRC;
281         if (GetIPFromIRC(hSocket, strMyName, addrFromIRC))
282         {
283             printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str());
284             if (!fUseProxy && addrFromIRC.IsRoutable())
285             {
286                 // IRC lets you to re-nick
287                 AddLocal(addrFromIRC, LOCAL_IRC);
288                 strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
289                 Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
290             }
291         }
292         
293         if (fTestNet) {
294             Send(hSocket, "JOIN #bitcoinTEST\r");
295             Send(hSocket, "WHO #bitcoinTEST\r");
296         } else {
297             // randomly join #bitcoin00-#bitcoin99
298             int channel_number = GetRandInt(100);
299             Send(hSocket, strprintf("JOIN #bitcoin%02d\r", channel_number).c_str());
300             Send(hSocket, strprintf("WHO #bitcoin%02d\r", channel_number).c_str());
301         }
302
303         int64 nStart = GetTime();
304         string strLine;
305         strLine.reserve(10000);
306         while (!fShutdown && RecvLineIRC(hSocket, strLine))
307         {
308             if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
309                 continue;
310
311             vector<string> vWords;
312             ParseString(strLine, ' ', vWords);
313             if (vWords.size() < 2)
314                 continue;
315
316             char pszName[10000];
317             pszName[0] = '\0';
318
319             if (vWords[1] == "352" && vWords.size() >= 8)
320             {
321                 // index 7 is limited to 16 characters
322                 // could get full length name at index 10, but would be different from join messages
323                 strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
324                 printf("IRC got who\n");
325             }
326
327             if (vWords[1] == "JOIN" && vWords[0].size() > 1)
328             {
329                 // :[email protected] JOIN :#channelname
330                 strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
331                 if (strchr(pszName, '!'))
332                     *strchr(pszName, '!') = '\0';
333                 printf("IRC got join\n");
334             }
335
336             if (pszName[0] == 'u')
337             {
338                 CAddress addr;
339                 if (DecodeAddress(pszName, addr))
340                 {
341                     addr.nTime = GetAdjustedTime();
342                     if (addrman.Add(addr, addrConnect, 51 * 60))
343                         printf("IRC got new address: %s\n", addr.ToString().c_str());
344                     nGotIRCAddresses++;
345                 }
346                 else
347                 {
348                     printf("IRC decode failed\n");
349                 }
350             }
351         }
352         closesocket(hSocket);
353         hSocket = INVALID_SOCKET;
354
355         if (GetTime() - nStart > 20 * 60)
356         {
357             nErrorWait /= 3;
358             nRetryWait /= 3;
359         }
360
361         nRetryWait = nRetryWait * 11 / 10;
362         if (!Wait(nRetryWait += 60))
363             return;
364     }
365 }
366
367
368
369
370
371
372
373
374
375
376 #ifdef TEST
377 int main(int argc, char *argv[])
378 {
379     WSADATA wsadata;
380     if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
381     {
382         printf("Error at WSAStartup()\n");
383         return false;
384     }
385
386     ThreadIRCSeed(NULL);
387
388     WSACleanup();
389     return 0;
390 }
391 #endif
This page took 0.051163 seconds and 4 git commands to generate.