Updated init script.
[dtbartle/bnbt.git] / tracker_announce.cpp
1 /***\r
2 *\r
3 * BNBT Beta 8.0 - A C++ BitTorrent Tracker\r
4 * Copyright (C) 2003-2004 Trevor Hogan\r
5 *\r
6 * CBTT variations (C) 2003-2005 Harold Feit\r
7 *\r
8 * This library is free software; you can redistribute it and/or\r
9 * modify it under the terms of the GNU Lesser General Public\r
10 * License as published by the Free Software Foundation; either\r
11 * version 2.1 of the License, or (at your option) any later version.\r
12 *\r
13 * This library is distributed in the hope that it will be useful,\r
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
16 * Lesser General Public License for more details.\r
17 *\r
18 * You should have received a copy of the GNU Lesser General Public\r
19 * License along with this library; if not, write to the Free Software\r
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
21 *\r
22 ***/\r
23 \r
24 #include "bnbt.h"\r
25 #include "bnbt_mysql.h"\r
26 #include "atom.h"\r
27 #include "bencode.h"\r
28 #include "link.h"\r
29 #include "tracker.h"\r
30 #include "util.h"\r
31 \r
32 void CTracker :: serverResponseAnnounce( struct request_t *pRequest, struct response_t *pResponse, user_t user )\r
33 {\r
34         pResponse->strCode = "200 OK";\r
35 \r
36         pResponse->mapHeaders.insert( pair<string, string>( "Content-Type", "text/plain" ) );\r
37 \r
38         // retrieve info hash\r
39 \r
40         string strInfoHash = pRequest->mapParams["info_hash"];\r
41 \r
42         if( strInfoHash.empty( ) )\r
43         {\r
44                 pResponse->strContent = UTIL_FailureReason( "info hash missing" );\r
45                 pResponse->bCompressOK = false;\r
46 \r
47                 return;\r
48         }\r
49 \r
50         if( m_pAllowed )\r
51         {\r
52                 if( !m_pAllowed->getItem( strInfoHash ) )\r
53                 {\r
54                         pResponse->strContent = UTIL_FailureReason( "requested download is not authorized for use with this tracker" );\r
55                         pResponse->bCompressOK = false;\r
56 \r
57                         return;\r
58                 }\r
59         }\r
60 \r
61         // retrieve ip\r
62 \r
63         string strIP = inet_ntoa( pRequest->sin.sin_addr );\r
64         string strTempIP = pRequest->mapParams["ip"];\r
65         string strIPConv = strIP.c_str( );\r
66 \r
67         // Verify that the IP is permitted to access the tracker\r
68         if( ( isIPBanList( strIP.c_str( ) ) == 1 || isIPBanList( strTempIP ) == 1 ) && m_iIPBanMode == 1 )\r
69         {\r
70                 pResponse->strContent = UTIL_FailureReason( "Your IP has been banned from this tracker." );\r
71                 pResponse->bCompressOK = false;\r
72                 return;\r
73         }\r
74         else if( ( isIPBanList( strIP.c_str( ) ) == 0 && isIPBanList( strTempIP ) == 0 ) && m_iIPBanMode == 2 )\r
75         {\r
76                 pResponse->strContent = UTIL_FailureReason( "Your IP has not been cleared for use on this tracker." );\r
77                 pResponse->bCompressOK = false;\r
78                 return;\r
79         }\r
80 \r
81         CAtomDicti *pData = new CAtomDicti( );\r
82 \r
83         if( m_iBlockNATedIP == 1 && ( !strTempIP.empty( ) && ( strTempIP.substr(0,8) == "192.168." || strTempIP.substr(0,8) == "169.254." || strTempIP.substr(0,3) == "10." || strTempIP.substr(0,7) == "172.16." || strTempIP.substr(0,7) == "172.17." || strTempIP.substr(0,7) == "172.18." || strTempIP.substr(0,7) == "172.19." || strTempIP.substr(0,7) == "172.20." || strTempIP.substr(0,7) == "172.21." || strTempIP.substr(0,7) == "172.22." || strTempIP.substr(0,7) == "172.23." || strTempIP.substr(0,7) == "172.24." || strTempIP.substr(0,7) == "172.25." || strTempIP.substr(0,7) == "172.26." || strTempIP.substr(0,7) == "172.27." || strTempIP.substr(0,7) == "172.28." || strTempIP.substr(0,7) == "172.29." || strTempIP.substr(0,7) == "172.30." || strTempIP.substr(0,7) == "172.31." || strTempIP.substr(0,7) == "172.32." || strTempIP == "127.0.0.1" ) ) )\r
84         {\r
85                 strTempIP = "";\r
86                 pData->setItem("warning message", new CAtomString( "A122: This tracker does not permit you to specify your IP to it. Using the IP you are connecting from instead." ) );\r
87         }\r
88 \r
89         if( m_iLocalOnly == 1 && ( !strIPConv.empty( ) && ( strIPConv.substr(0,8) == "192.168." || strIPConv.substr(0,8) == "169.254." || strIPConv.substr(0,3) == "10." || strIPConv.substr(0,7) == "172.16." || strIPConv.substr(0,7) == "172.17." || strIPConv.substr(0,7) == "172.18." || strIPConv.substr(0,7) == "172.19." || strIPConv.substr(0,7) == "172.20." || strIPConv.substr(0,7) == "172.21." || strIPConv.substr(0,7) == "172.22." || strIPConv.substr(0,7) == "172.23." || strIPConv.substr(0,7) == "172.24." || strIPConv.substr(0,7) == "172.25." || strIPConv.substr(0,7) == "172.26." || strIPConv.substr(0,7) == "172.27." || strIPConv.substr(0,7) == "172.28." || strIPConv.substr(0,7) == "172.29." || strIPConv.substr(0,7) == "172.30." || strIPConv.substr(0,7) == "172.31." || strIPConv.substr(0,7) == "172.32." || strIPConv == "127.0.0.1" ) ) )\r
90         {\r
91                 if( !strTempIP.empty( ) && strTempIP.find_first_not_of( "1234567890." ) == string :: npos )\r
92                         strIP = strTempIP;\r
93                 else\r
94                 {\r
95                         if( !strTempIP.empty() )\r
96                 pData->setItem("warning message", new CAtomString( "A473: The IP you have specified is invalid. Using the IP you are connecting from instead." ) );\r
97                         strTempIP = "";\r
98                 }\r
99 \r
100         }\r
101 \r
102         else if( m_iLocalOnly == 1 && ( !strIPConv.empty( ) && !( strIPConv.substr(0,8) == "192.168." || strIPConv.substr(0,8) == "169.254." || strIPConv.substr(0,3) == "10." || strIPConv.substr(0,7) == "172.16." || strIPConv.substr(0,7) == "172.17." || strIPConv.substr(0,7) == "172.18." || strIPConv.substr(0,7) == "172.19." || strIPConv.substr(0,7) == "172.20." || strIPConv.substr(0,7) == "172.21." || strIPConv.substr(0,7) == "172.22." || strIPConv.substr(0,7) == "172.23." || strIPConv.substr(0,7) == "172.24." || strIPConv.substr(0,7) == "172.25." || strIPConv.substr(0,7) == "172.26." || strIPConv.substr(0,7) == "172.27." || strIPConv.substr(0,7) == "172.28." || strIPConv.substr(0,7) == "172.29." || strIPConv.substr(0,7) == "172.30." || strIPConv.substr(0,7) == "172.31." || strIPConv.substr(0,7) == "172.32." || strIPConv == "127.0.0.1" ) ) )\r
103     {\r
104                 if( !strTempIP.empty( ) && strTempIP != strIPConv )\r
105                         pData->setItem("warning message", new CAtomString( "A824: This tracker does not permit you to specify your IP to it. Using the IP you are connecting from instead." ) );\r
106                 strTempIP = "";\r
107         }\r
108 \r
109         else if( m_iLocalOnly == 0 )\r
110         {\r
111                 {\r
112                         if( !strTempIP.empty( ) && strTempIP.find_first_not_of( "1234567890." ) == string :: npos )\r
113                                 strIP = strTempIP;\r
114                         else\r
115                         {\r
116                                 if( !strTempIP.empty( ) )\r
117                                         pData->setItem("warning message", new CAtomString( "A373: The IP you have specified is invalid. Using the IP you are connecting from instead." ) );\r
118                                 strTempIP = "";\r
119                         }\r
120                 }\r
121         }\r
122 \r
123         // retrieve a ton of parameters\r
124 \r
125         string strEvent = pRequest->mapParams["event"];\r
126         string strPort = pRequest->mapParams["port"];\r
127         string strUploaded = pRequest->mapParams["uploaded"];\r
128         string strDownloaded = pRequest->mapParams["downloaded"];\r
129         string strLeft = pRequest->mapParams["left"];\r
130         string strPeerID = pRequest->mapParams["peer_id"];\r
131         string strNumWant = pRequest->mapParams["numwant"];\r
132         string strNoPeerID = pRequest->mapParams["no_peer_id"];\r
133         string strCompact = pRequest->mapParams["compact"];\r
134         string strKey = pRequest->mapParams["key"];\r
135 \r
136         if( m_bAnnounceKeySupport && strKey.empty( ) )\r
137         {\r
138                 if( m_bRequireKeySupport )\r
139                 {\r
140                         pResponse->strCode = "200 OK";\r
141                         pResponse->strContent = UTIL_FailureReason( "This tracker requires support for the \"key\" announce paramater. Please update or change your client." );\r
142                         return;\r
143                 }\r
144                 else\r
145                         pData->setItem("warning message", new CAtomString( "A290: This tracker supports key passing. Please enable your client." ) ); \r
146         }\r
147 \r
148         // Add support for MySQL DState Override checking here.\r
149     if( m_pDFile )\r
150         {\r
151                 if( !m_pDFile->getItem( strInfoHash ) )\r
152                         m_pDFile->setItem( strInfoHash, new CAtomDicti( ) );\r
153 \r
154                 CAtom *pPeers = m_pDFile->getItem( strInfoHash );\r
155                 if( pPeers && pPeers->isDicti( ) )\r
156                 {\r
157                         CAtom *pPeer = ( (CAtomDicti *)pPeers )->getItem( strPeerID );\r
158 \r
159                         if( pPeer && pPeer->isDicti( ) )\r
160                         {\r
161                                         CAtom *pKey = ((CAtomDicti *)pPeer)->getItem( "key" , NULL );\r
162                                         if( pKey && ((CAtomString *)pKey)->toString() != strKey.c_str( ) )\r
163                                         {\r
164                                                 pResponse->strCode = "200 OK";\r
165                                                 pResponse->strContent = UTIL_FailureReason( "Your client's \"key\" paramater and the key we have for you in our database do not match." );\r
166                                                 return;\r
167                                         }\r
168                         }\r
169                 }\r
170         }\r
171 \r
172 \r
173         // Check no_peer_id/compact requirement\r
174         // Do things sanely by ignoring requests with numwant=0\r
175         // This way we don't accidentally reject clients that don't want a peerlist\r
176         // numwant=0 and compact=1 are mutually exclusive\r
177         // numwant=0 and no_peer_id=1 are mutually exclusive\r
178         if( strNumWant != "0" )\r
179         {\r
180                 // Check compact Requirement\r
181                 if( m_bRequireCompact == true && strCompact != "1" )\r
182                 {\r
183                         pResponse->strCode = "200 OK";\r
184                         pResponse->strContent = UTIL_FailureReason( "This tracker requires support for compact tracker requests. Please update or change your client." );\r
185                         return;\r
186                 }\r
187 \r
188                 // Check no_peer_id Requirement - If Compact is supported, no_peer_id isn't required.\r
189                 // both no_peer_id and compact need to be unsupported for a tracker requiring no_peer_id to reject a client.\r
190                 if( m_bRequireNoPeerID == true && strNoPeerID != "1" && strCompact != "1" )\r
191                 {\r
192                         pResponse->strCode = "200 OK";\r
193                         pResponse->strContent = UTIL_FailureReason( "This tracker requires support for no_peer_id or compact tracker requests. Please update or change your client." );\r
194                         return;\r
195                 }\r
196 \r
197         }\r
198 \r
199         string strUserAgent = pRequest->mapHeaders["User-Agent"];\r
200     string struAgent = pRequest->mapHeaders["User-agent"];\r
201         if( strUserAgent.c_str() == "" )\r
202                 strUserAgent = "Unknown";\r
203 \r
204         if( struAgent.c_str() == "" )\r
205                 struAgent = "Unknown";\r
206 \r
207         if( i_intPeerSpoofRestrict == 1 )\r
208                 if( ( "-AZ" != strPeerID.substr(0,3) && "Azureus" == strUserAgent.substr(0,7) ) || ( "BitTorrent/3." == strUserAgent.substr(0,13) && ( "S5" == strPeerID.substr(0,2) || UTIL_EscapedToString("S%05") == strPeerID.substr(0,2) ) ) )\r
209                 {\r
210                         pResponse->strCode = "200 OK";\r
211                         pResponse->strContent = UTIL_FailureReason( "This tracker does not allow client spoofing. Please disable client spoofing in your client configuration." );\r
212                         return;\r
213                 }\r
214 \r
215         int isbanned = isClientBanList( strUserAgent , true );\r
216 \r
217         if( isbanned == 0 )\r
218                 isbanned = isClientBanList( struAgent , true );\r
219         if( isbanned == 0 )\r
220                 isbanned = isClientBanList( UTIL_EscapedToString( strPeerID ) );\r
221 \r
222         if (isbanned == 1 && i_intBanMode == 1)\r
223         {\r
224                 pResponse->strCode = "200 OK";\r
225                 pResponse->strContent = UTIL_FailureReason( "Client Version is banned. Check with the tracker administrator" );\r
226 //              UTIL_LogPrint("Banned client denied access\n");\r
227                 return;\r
228         }\r
229 \r
230         if (isbanned == 0 && i_intBanMode == 2)\r
231         {\r
232                 pResponse->strCode = "200 OK";\r
233                 pResponse->strContent = UTIL_FailureReason( "Client Version is banned. Check with the tracker administrator" );\r
234 //              UTIL_LogPrint("Non-Friendly Client denied access\n");\r
235                 return;\r
236         }\r
237 \r
238 \r
239         if( !strEvent.empty( ) && strEvent != "started" && strEvent != "completed" && strEvent != "stopped" )\r
240         {\r
241                 pResponse->strContent = UTIL_FailureReason( "invalid event" );\r
242                 pResponse->bCompressOK = false;\r
243 \r
244                 return;\r
245         }\r
246 \r
247         if( strPort.empty( ) )\r
248         {\r
249                 pResponse->strContent = UTIL_FailureReason( "port missing" );\r
250                 pResponse->bCompressOK = false;\r
251 \r
252                 return;\r
253         }\r
254 \r
255         if( strUploaded.empty( ) )\r
256         {\r
257                 pResponse->strContent = UTIL_FailureReason( "uploaded missing" );\r
258                 pResponse->bCompressOK = false;\r
259 \r
260                 return;\r
261         }\r
262 \r
263         if( strDownloaded.empty( ) )\r
264         {\r
265                 pResponse->strContent = UTIL_FailureReason( "downloaded missing" );\r
266                 pResponse->bCompressOK = false;\r
267 \r
268                 return;\r
269         }\r
270 \r
271         if( strLeft.empty( ) )\r
272         {\r
273                 pResponse->strContent = UTIL_FailureReason( "left missing" );\r
274                 pResponse->bCompressOK = false;\r
275 \r
276                 return;\r
277         }\r
278 \r
279         if( strPeerID.size( ) != 20 )\r
280         {\r
281                 pResponse->strContent = UTIL_FailureReason( "peer id not of length 20" );\r
282                 pResponse->bCompressOK = false;\r
283 \r
284                 return;\r
285         }\r
286 \r
287         struct announce_t ann;\r
288 \r
289         ann.strInfoHash = strInfoHash;\r
290         ann.strIP = strIP;\r
291         ann.strEvent = strEvent;\r
292         ann.iPort = (unsigned int)atoi( strPort.c_str( ) );\r
293         ann.iUploaded = UTIL_StringTo64( strUploaded.c_str( ) );\r
294         ann.iDownloaded = UTIL_StringTo64( strDownloaded.c_str( ) );\r
295         ann.iLeft = UTIL_StringTo64( strLeft.c_str( ) );\r
296         ann.strPeerID = strPeerID;\r
297         ann.strKey = strKey;\r
298         ann.bAbusive = false;\r
299     ann.bIncrement = false;\r
300 \r
301 \r
302         if( ( ann.iPort <= 1024 ) && m_iBlackListServicePorts )\r
303         {\r
304                 pResponse->strCode = "200 OK";\r
305                 pResponse->strContent = UTIL_FailureReason( "Listen port " + strPort + " is blacklisted from this server, please adjust your settings to use a port above 1024." );\r
306                 return;\r
307         }\r
308 \r
309         if( ( ( ann.iPort >= 6881 && ann.iPort <= 6999 ) || ( ann.iPort >= 411 && ann.iPort <= 413 ) || ann.iPort == 1214 || ann.iPort == 4662 || ( ann.iPort >= 6346 && ann.iPort <= 6347 ) ) && m_iBlacklistP2PPorts )\r
310         {\r
311                 pResponse->strCode = "200 OK";\r
312                 pResponse->strContent = UTIL_FailureReason( "Listen port " + strPort + " is blacklisted from this server, please adjust your settings to use a port outside of common p2p ranges." );\r
313                 return;\r
314         }\r
315 \r
316         int64 iOverFlowLimit = UTIL_StringTo64( strOverFlowLimit.c_str() );\r
317         int64 iOverFlowminimum = UTIL_StringTo64( "107374182400" );\r
318         if( iOverFlowLimit < iOverFlowminimum )\r
319                 iOverFlowLimit = iOverFlowminimum;\r
320 \r
321         if( ann.iDownloaded < 0 || ( m_iRestrictOverflow == 1 && ann.iDownloaded >= iOverFlowLimit ) )\r
322         {\r
323                 pResponse->strCode = "200 OK";\r
324                 pResponse->strContent = UTIL_FailureReason( "Amount reported downloaded is invaild" );\r
325                 //UTIL_LogPrint("Invalid downloaded value reported, client rejected\n");\r
326                 return;\r
327         }\r
328 \r
329         if( ann.iUploaded < 0 || ( m_iRestrictOverflow == 1 && ann.iUploaded >= iOverFlowLimit ) )\r
330         {\r
331                 pResponse->strCode = "200 OK";\r
332                 pResponse->strContent = UTIL_FailureReason( "Amount reported uploaded is invaild" );\r
333                 //UTIL_LogPrint("Invalid downloaded value reported, client rejected\n");\r
334                 return;\r
335         }\r
336 \r
337         if( ann.iLeft < 0 )\r
338         {\r
339                 pResponse->strCode = "200 OK";\r
340                 pResponse->strContent = UTIL_FailureReason( "Amount reported remaining is invalid" );\r
341                 return;\r
342         }\r
343 \r
344         if( m_bEnableAbuseBlock == true && m_pAbuse )\r
345         {\r
346                 if( m_pAbuse->getItem( strIP ) )\r
347                 {\r
348                         CAtom *pPeerIP = m_pAbuse->getItem( strIP );\r
349                         if( pPeerIP && pPeerIP->isDicti( ) )\r
350                         {\r
351                 CAtom *pPeerLastAnnounce = ((CAtomDicti *)pPeerIP)->getItem( "lastannounce", new CAtomLong ( 0 ) );\r
352                                 CAtom *pPeerAbuseHash = ((CAtomDicti *)pPeerIP)->getItem( "lastinfohash" , new CAtomString( "" ) );\r
353                                 CAtom *pPeerAbuses = ((CAtomDicti *)pPeerIP)->getItem( "totalabuses" , new CAtomLong ( 0 ) );\r
354                                 CAtom *pPeerAbuseByHash = ((CAtomDicti *)pPeerIP)->getItem( "abusesbyhash" );\r
355                                 long m_lPeerAbuses = ((CAtomLong *)pPeerAbuses)->getValue( );\r
356                                 if( gbDebug )\r
357                                         UTIL_LogPrint( " Checking Abuse Rating \n" );\r
358                                 bool m_bHammer;\r
359                                 m_bHammer = false;\r
360                                 if( gbDebug ){\r
361                                         UTIL_LogPrint( "Current Time is %i and last announce from this peer was %i\n",GetRealTime(), ((CAtomLong *)pPeerLastAnnounce)->getValue( ) );\r
362                                         UTIL_LogPrint( "The Difference is %i\n",GetRealTime() - ((CAtomLong *)pPeerLastAnnounce)->getValue( ) );\r
363                                 }\r
364                                 if( ann.strEvent == "completed" || ann.strEvent == "stopped" )\r
365                                 {\r
366                                         if( gbDebug )\r
367                                                 UTIL_LogPrint( "Resetting Due To Event sent \n" );\r
368 \r
369                                         ann.bIncrement = false;\r
370                                         ann.bAbusive = false;\r
371                                 }\r
372                                 else {\r
373                                 if( ( m_lPeerAbuses >= m_iGlobalAbuseHammer ) && ( ( (m_lPeerAbuses * m_iAnnounceInterval) - 5 ) > ( GetRealTime( ) - ((CAtomLong *)pPeerLastAnnounce)->getValue( ) ) ) )\r
374                                 {\r
375                                         if( gbDebug )\r
376                                                 UTIL_LogPrint( " Hammering Abuse - Abuse # %i\n", m_lPeerAbuses );\r
377                     pResponse->strCode = "200 OK";\r
378                                         pResponse->strContent = UTIL_FailureReason( "Your client has been banned for repeated abuse. " + ((CAtomLong *)pPeerAbuses)->toString( ) + " Abuses so far. Please check with Tracker Administration for details." );\r
379                                         ann.bAbusive = true;\r
380                                         ann.bIncrement = true;\r
381                                 }\r
382                                 else if( m_iMinAnnounceInterval - 5 > ( GetRealTime( ) - ((CAtomLong *)pPeerLastAnnounce)->getValue( ) ) )\r
383                                 {\r
384                                         if( gbDebug )\r
385                                                 UTIL_LogPrint( " Standard Abuse \n" );\r
386 \r
387                                         strNumWant = "0";\r
388                     if( ((CAtomLong *)pPeerAbuses)->getValue( ) >= m_iGlobalAbuseLimit )\r
389                                         {\r
390                                                 if( gbDebug )\r
391                                                         UTIL_LogPrint( "Banned for %i Abuses \n", m_lPeerAbuses );\r
392                         pResponse->strCode = "200 OK";\r
393                                                 pResponse->strContent = UTIL_FailureReason( "Your client has been banned for abuse. " + ((CAtomLong *)pPeerAbuses)->toString( ) + " Abuses so far. Please check with Tracker Administration for details." );\r
394                                                 ann.bIncrement = true;\r
395                                                 ann.bAbusive = true;\r
396                                         }\r
397                                         else \r
398                                         {\r
399                                                 if( ann.strEvent != "completed" || ann.strEvent != "stopped" )\r
400                                                 {\r
401                                                         if( gbDebug )\r
402                                                                 UTIL_LogPrint( " Warned for %i Abuses \n", m_lPeerAbuses );\r
403 \r
404                                                         pData->setItem("warning message", new CAtomString( "A58A: This tracker does not permit abusive announcing to get more peers. Your announce will contain 0 peers. Continued abuse will result in an automated ban." ) );\r
405                                                         ann.bIncrement = true;\r
406                                                 }\r
407                                         }\r
408 //                                      ((CAtomDicti *)pPeerIP)->setItem( "abusesbyhash", new CAtomLong( ((CAtomLong *)pPeerAbuses)->getValue( ) +1 ) );\r
409 /*                  if( pPeerAbuseByHash && pPeerAbuseByHash->isDicti( ))\r
410                                         {\r
411                                                 CAtom *pCurrentHash = ((CAtomDicti *)pPeerIP)->getItem( strInfoHash );\r
412                                                 if( pCurrentHash && pCurrentHash->isDicti( ) )\r
413                                                 {\r
414         \r
415                                                 }\r
416                                         }\r
417                                         */\r
418                                 }\r
419                                 }\r
420                         }\r
421                 }\r
422 \r
423         }\r
424 \r
425         Announce( ann );\r
426 \r
427         if( ann.bAbusive == true )\r
428                 return;\r
429 \r
430         unsigned int iRSize = m_iResponseSize;\r
431 \r
432         if( !strNumWant.empty( ) )\r
433                 iRSize = atoi( strNumWant.c_str( ) );\r
434 \r
435         if( iRSize > (unsigned int)m_iMaxGive )\r
436                 iRSize = (unsigned int)m_iMaxGive;\r
437 \r
438         // link\r
439 \r
440         if( gpLinkServer || gpLink )\r
441         {\r
442                 CAtomDicti *pAnnounce = new CAtomDicti( );\r
443 \r
444                 pAnnounce->setItem( "info_hash", new CAtomString( ann.strInfoHash ) );\r
445                 pAnnounce->setItem( "ip", new CAtomString( ann.strIP ) );\r
446 \r
447                 if( !strEvent.empty( ) )\r
448                         pAnnounce->setItem( "event", new CAtomString( ann.strEvent ) );\r
449 \r
450                 pAnnounce->setItem( "port", new CAtomLong( ann.iPort ) );\r
451                 pAnnounce->setItem( "uploaded", new CAtomLong( ann.iUploaded ) );\r
452                 pAnnounce->setItem( "downloaded", new CAtomLong( ann.iDownloaded ) );\r
453                 pAnnounce->setItem( "left", new CAtomLong( ann.iLeft ) );\r
454                 pAnnounce->setItem( "peer_id", new CAtomString( ann.strPeerID ) );\r
455                 pAnnounce->setItem( "key", new CAtomString( ann.strKey ) );\r
456                 if( ann.bAbusive == true )\r
457                         pAnnounce->setItem( "abuse", new CAtomLong( 1 ) );\r
458                 if( ann.bIncrement == true )\r
459                         pAnnounce->setItem( "increment", new CAtomLong( 1 ) );\r
460 \r
461                 struct linkmsg_t lm;\r
462 \r
463                 lm.len = pAnnounce->EncodedLength( );\r
464                 lm.type = LINKMSG_ANNOUNCE;\r
465                 lm.msg = Encode( pAnnounce );\r
466 \r
467                 if( gpLinkServer )\r
468                         gpLinkServer->Queue( lm );\r
469                 else if ( gpLink )\r
470                         gpLink->Queue( lm );\r
471 \r
472                 delete pAnnounce;\r
473         }\r
474 \r
475         // populate cache\r
476 \r
477         if( !m_pCached->getItem( ann.strInfoHash ) )\r
478                 m_pCached->setItem( ann.strInfoHash, new CAtomList( ) );\r
479 \r
480         CAtom *pCache = m_pCached->getItem( ann.strInfoHash );\r
481 \r
482         if( pCache && pCache->isList( ) )\r
483         {\r
484                 CAtomList *pCacheList = (CAtomList *)pCache;\r
485 \r
486                 if( pCacheList->getValuePtr( )->size( ) < iRSize )\r
487                 {\r
488 #ifdef BNBT_MYSQL\r
489                         if( m_bMySQLOverrideDState )\r
490                         {\r
491                                 CMySQLQuery *pQuery = new CMySQLQuery( "SELECT bid,bip,bport FROM dstate WHERE bhash=\'" + UTIL_StringToMySQL( ann.strInfoHash ) + "\'" );\r
492 \r
493                                 vector<string> vecQuery;\r
494 \r
495                                 while( ( vecQuery = pQuery->nextRow( ) ).size( ) == 3 )\r
496                                 {\r
497                                         CAtomDicti *pAdd = new CAtomDicti( );\r
498 \r
499                                         pAdd->setItem( "peer id", new CAtomString( vecQuery[0] ) );\r
500                                         pAdd->setItem( "ip", new CAtomString( vecQuery[1] ) );\r
501                                         pAdd->setItem( "port", new CAtomLong( atoi( vecQuery[2].c_str( ) ) ) );\r
502 \r
503                                         pCacheList->addItem( pAdd );\r
504                                 }\r
505 \r
506                                 delete pQuery;\r
507                         }\r
508                         else\r
509                         {\r
510 #endif\r
511                                 if( m_pDFile )\r
512                                 {\r
513                                         if( !m_pDFile->getItem( ann.strInfoHash ) )\r
514                                                 m_pDFile->setItem( ann.strInfoHash, new CAtomDicti( ) );\r
515 \r
516                                         CAtom *pPeers = m_pDFile->getItem( ann.strInfoHash );\r
517 \r
518                                         if( pPeers && pPeers->isDicti( ) )\r
519                                         {\r
520                                                 map<string, CAtom *> *pmapPeersDicti = ( (CAtomDicti *)pPeers )->getValuePtr( );\r
521 \r
522                                                 for( map<string, CAtom *> :: iterator i = pmapPeersDicti->begin( ); i != pmapPeersDicti->end( ); i++ )\r
523                                                 {\r
524                                                         if( (*i).second->isDicti( ) )\r
525                                                         {\r
526                                                                 CAtom *pIP = ( (CAtomDicti *)(*i).second )->getItem( "ip" );\r
527                                                                 CAtom *pPort = ( (CAtomDicti *)(*i).second )->getItem( "port" );\r
528                                                                 // check for oneself and remove from the list\r
529                                                                 if( pIP && pIP->toString( ) == strIP && pPort && pPort->toString( ) == strPort )\r
530                                                                 {\r
531                                                                         continue;\r
532                                                                 }\r
533                                                                 \r
534                                                                 // remove seeds if announce is from a seed\r
535                                                                 if( ann.iLeft == 0 )\r
536                                                                 {\r
537                                                                         CAtom *pLeft = ( (CAtomDicti *)(*i).second )->getItem( "left" );\r
538 \r
539                                                                         if( pLeft && atol( pLeft->toString( ).c_str( ) ) == 0 )\r
540                                                                         {\r
541                                                                                 continue;\r
542                                                                         }\r
543                                                                 }\r
544 \r
545                                                                 // Moved here to clean up from the memory leak\r
546                                                                 CAtomDicti *pAdd = new CAtomDicti( );\r
547 \r
548                                                                 pAdd->setItem( "peer id", new CAtomString( (*i).first ) );\r
549 \r
550                                                                 if( pIP )\r
551                                                                         pAdd->setItem( "ip", new CAtomString( pIP->toString( ) ) );\r
552 \r
553                                                                 if( pPort && pPort->isLong( ) )\r
554                                                                         pAdd->setItem( "port", new CAtomLong( *(CAtomLong *)pPort ) );\r
555 \r
556                                                                 pCacheList->addItem( pAdd );\r
557                                                         }\r
558                                                 }\r
559                                         }\r
560                                 }\r
561 \r
562 #ifdef BNBT_MYSQL\r
563                         }\r
564 #endif\r
565 \r
566                         pCacheList->Randomize( );\r
567                 }\r
568         }\r
569 \r
570         // clamp response\r
571 \r
572         if( pCache && pCache->isList( ) )\r
573         {\r
574                 CAtomList *pCacheList = (CAtomList *)pCache;\r
575 \r
576                 CAtom *pPeers = NULL;\r
577 \r
578                 if( strCompact == "1" )\r
579                 {\r
580                         // compact announce\r
581 \r
582                         string strPeers;\r
583 \r
584                         vector<CAtom *> *pvecList = pCacheList->getValuePtr( );\r
585 \r
586                         for( vector<CAtom *> :: iterator i = pvecList->begin( ); i != pvecList->end( ); )\r
587                         {\r
588                                 if( (*i)->isDicti( ) )\r
589                                 {\r
590                                         if( strPeers.size( ) / 6 >= iRSize )\r
591                                                 break;\r
592 \r
593                                         CAtom *pIP = ( (CAtomDicti *)(*i) )->getItem( "ip" );\r
594                                         CAtom *pPort = ( (CAtomDicti *)(*i) )->getItem( "port" );\r
595 \r
596                                         if( pIP && pPort && pPort->isLong( ) )\r
597                                         {\r
598                                                 // tphogan - this is a much more efficient version of UTIL_Compact\r
599 \r
600                                                 bool bOK = true;\r
601                                                 char pCompact[6];\r
602                                                 char *szIP = new char[pIP->Length( ) + 1];\r
603                                                 char *szCur = szIP;\r
604                                                 char *pSplit;\r
605                                                 strncpy( szIP, pIP->toString( ).c_str( ), pIP->Length( ) + 1 );\r
606 \r
607                                                 // first three octets\r
608 \r
609                                                 for( int i = 0; i < 3; i++ )\r
610                                                 {\r
611                                                         if( pSplit = strstr( szCur, "." ) )\r
612                                                         {\r
613                                                                 *pSplit = '\0';\r
614                                                                 pCompact[i] = (char)atoi( szCur );\r
615                                                                 szCur = pSplit + 1;\r
616                                                         }\r
617                                                         else\r
618                                                         {\r
619                                                                 bOK = false;\r
620 \r
621                                                                 break;\r
622                                                         }\r
623                                                 }\r
624 \r
625                                                 if( bOK )\r
626                                                 {\r
627                                                         // fourth octet\r
628 \r
629                                                         pCompact[3] = (char)atoi( szCur );\r
630 \r
631                                                         // port\r
632 \r
633                                                         unsigned int iPort = (unsigned int)dynamic_cast<CAtomLong *>( pPort )->getValue( );\r
634 \r
635 #ifdef BNBT_BIG_ENDIAN\r
636                                                         pCompact[5] = (char)( ( iPort & 0xFF00 ) >> 8 );\r
637                                                         pCompact[4] = (char)( iPort & 0xFF );\r
638 #else\r
639                                                         pCompact[4] = (char)( ( iPort & 0xFF00 ) >> 8 );\r
640                                                         pCompact[5] = (char)( iPort & 0xFF );\r
641 #endif\r
642 \r
643                                                         strPeers += string( pCompact, 6 );\r
644                                                 }\r
645 \r
646                                                 delete szIP;\r
647                                         }\r
648 \r
649                                         delete *i;\r
650 \r
651                                         i = pvecList->erase( i );\r
652                                 }\r
653                                 else\r
654                                         i++;\r
655                         }\r
656 \r
657                         pPeers = new CAtomString( strPeers );\r
658 \r
659                         // don't compress\r
660 \r
661                         pResponse->bCompressOK = false;\r
662                 }\r
663                 else\r
664                 {\r
665                         // regular announce\r
666 \r
667                         CAtomList *pPeersList = new CAtomList( );\r
668 \r
669                         vector<CAtom *> *pvecList = pCacheList->getValuePtr( );\r
670 \r
671                         for( vector<CAtom *> :: iterator i = pvecList->begin( ); i != pvecList->end( ); )\r
672                         {\r
673                                 if( (*i)->isDicti( ) )\r
674                                 {\r
675                                         if( pPeersList->getValuePtr( )->size( ) == iRSize )\r
676                                                 break;\r
677 \r
678                                         if( strNoPeerID == "1" )\r
679                                                 ( (CAtomDicti *)(*i) )->delItem( "peer id" );\r
680 \r
681                                         pPeersList->addItem( new CAtomDicti( *(CAtomDicti *)(*i) ) );\r
682 \r
683                                         delete *i;\r
684 \r
685                                         i = pvecList->erase( i );\r
686                                 }\r
687                                 else\r
688                                         i++;\r
689                         }\r
690 \r
691                         pPeers = pPeersList;\r
692                 }\r
693 \r
694                 // addition to support private tracker definitions.\r
695                 pData->setItem( "private", new CAtomLong( m_iPrivateTracker ) );\r
696                 pData->setItem( "interval", new CAtomLong( m_iAnnounceInterval ) );\r
697                 pData->setItem( "min interval", new CAtomLong( m_iMinAnnounceInterval ) );\r
698                 pData->setItem( "peers", pPeers );\r
699 \r
700                 CAtom *pFC = m_pFastCache->getItem( strInfoHash );\r
701 \r
702                 if( pFC && dynamic_cast<CAtomList *>( pFC ) )\r
703                 {\r
704                         vector<CAtom *> vecList = dynamic_cast<CAtomList *>( pFC )->getValue( );\r
705 \r
706                         pData->setItem( "complete", new CAtomInt( *dynamic_cast<CAtomInt *>( vecList[0] ) ) );\r
707                         pData->setItem( "incomplete", new CAtomInt( *dynamic_cast<CAtomInt *>( vecList[1] ) ) );\r
708                 }\r
709 \r
710                 pResponse->strContent = Encode( pData );\r
711 \r
712                 delete pData;\r
713         }\r
714 }\r