Updated init script.
[dtbartle/bnbt.git] / link.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 "atom.h"\r
26 #include "bencode.h"\r
27 #include "config.h"\r
28 #include "link.h"\r
29 #include "md5.h"\r
30 #include "server.h"\r
31 #include "tracker.h"\r
32 #include "util.h"\r
33 \r
34 //\r
35 // CLink\r
36 //\r
37 \r
38 CLink :: CLink( )\r
39 {\r
40         m_mtxQueued.Initialize( );\r
41 \r
42         m_bKill = false;\r
43 \r
44         m_strIP = CFG_GetString( "bnbt_tlink_connect", string( ) );\r
45         m_strPass = CFG_GetString( "bnbt_tlink_password", string( ) );\r
46 \r
47         memset( &sin, 0, sizeof( sin ) );\r
48 \r
49         sin.sin_family = AF_INET;\r
50 \r
51         // map host name\r
52 \r
53         struct hostent *pHE;\r
54 \r
55         if( pHE = gethostbyname( m_strIP.c_str( ) ) )\r
56                 memcpy( &sin.sin_addr, pHE->h_addr, pHE->h_length );\r
57         else if( ( sin.sin_addr.s_addr = inet_addr( m_strIP.c_str( ) ) ) == INADDR_NONE )\r
58         {\r
59                 UTIL_LogPrint( "link error (%s) - unable to get host entry\n", getName( ).c_str( ) );\r
60 \r
61                 Kill( );\r
62         }\r
63 \r
64         if( ( sin.sin_port = htons( (u_short)CFG_GetInt( "bnbt_tlink_port", 5204 ) ) ) == 0 )\r
65         {\r
66                 UTIL_LogPrint( "link error (%s) - invalid port %d\n", getName( ).c_str( ), CFG_GetInt( "bnbt_tlink_port", 5204 ) );\r
67 \r
68                 Kill( );\r
69         }\r
70 \r
71         m_sckLink = INVALID_SOCKET;\r
72 }\r
73 \r
74 CLink :: ~CLink( )\r
75 {\r
76         linkmsg_t lmClose;\r
77 \r
78         lmClose.len = 0;\r
79         lmClose.type = LINKMSG_CLOSE;\r
80         lmClose.msg.erase( );\r
81 \r
82         Send( lmClose );\r
83 \r
84         closesocket( m_sckLink );\r
85 \r
86         m_mtxQueued.Destroy( );\r
87 \r
88         UTIL_LogPrint( "link (%s) - link broken\n", getName( ).c_str( ) );\r
89 }\r
90 \r
91 void CLink :: Kill( )\r
92 {\r
93         m_bKill = true;\r
94 }\r
95 \r
96 void CLink :: Go( )\r
97 {\r
98         if( m_bKill )\r
99                 return;\r
100 \r
101         // map protocol name to protocol number\r
102 \r
103         struct protoent *pPE;\r
104 \r
105         if( ( pPE = getprotobyname( "tcp" ) ) == 0 )\r
106         {\r
107                 UTIL_LogPrint( "link error (%s) - unable to get tcp protocol entry (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
108 \r
109                 return;\r
110         }\r
111 \r
112         // allocate socket\r
113 \r
114         if( ( m_sckLink = socket( PF_INET, SOCK_STREAM, pPE->p_proto ) ) == INVALID_SOCKET )\r
115         {\r
116                 UTIL_LogPrint( "link error (%s) - unable to allocate socket (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
117 \r
118                 return;\r
119         }\r
120 \r
121         // connect socket\r
122 \r
123         if( connect( m_sckLink, (struct sockaddr *)&sin, sizeof( sin ) ) == SOCKET_ERROR )\r
124         {\r
125                 UTIL_LogPrint( "link error (%s) - unable to connect (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
126 \r
127                 return;\r
128         }\r
129 \r
130         UTIL_LogPrint( "link (%s) - link established\n", getName( ).c_str( ) );\r
131 \r
132         struct linkmsg_t lmSend;\r
133         struct linkmsg_t lmReceive;\r
134 \r
135         lmSend.len = strlen( LINK_VER );\r
136         lmSend.type = LINKMSG_VERSION;\r
137         lmSend.msg = LINK_VER;\r
138 \r
139         Send( lmSend );\r
140 \r
141         lmReceive = Receive( true );\r
142 \r
143         if( lmReceive.type != LINKMSG_VERSION || lmReceive.msg != LINK_VER )\r
144         {\r
145                 UTIL_LogPrint( "link error (%s) - incompatible version, disconnecting\n", getName( ).c_str( ) );\r
146 \r
147                 return;\r
148         }\r
149 \r
150         lmReceive = Receive( true );\r
151 \r
152         if( lmReceive.type != LINKMSG_INFO )\r
153         {\r
154                 UTIL_LogPrint( "link error (%s) - unexpected message, disconnecting\n", getName( ).c_str( ) );\r
155 \r
156                 return;\r
157         }\r
158 \r
159         CAtom *pInfo = Decode( lmReceive.msg );\r
160 \r
161         if( pInfo && pInfo->isDicti( ) )\r
162         {\r
163                 CAtom *pNonce = ( (CAtomDicti *)pInfo )->getItem( "nonce" );\r
164 \r
165                 string strHashMe;\r
166 \r
167                 if( pNonce )\r
168                         strHashMe = m_strPass + ":" + pNonce->toString( );\r
169                 else\r
170                         strHashMe = m_strPass;\r
171 \r
172                 unsigned char szMD5[16];\r
173 \r
174                 MD5_CTX md5;\r
175 \r
176                 MD5Init( &md5 );\r
177                 MD5Update( &md5, (unsigned char *)strHashMe.c_str( ), strHashMe.size( ) );\r
178                 MD5Final( szMD5, &md5 );\r
179 \r
180                 lmSend.len = 16;\r
181                 lmSend.type = LINKMSG_PASSWORD;\r
182                 lmSend.msg = string( (char *)szMD5, 16 );\r
183 \r
184                 Send( lmSend );\r
185 \r
186                 delete pInfo;\r
187         }\r
188         else\r
189         {\r
190                 UTIL_LogPrint( "link error (%s) - bad info message, disconnecting\n", getName( ).c_str( ) );\r
191 \r
192                 return;\r
193         }\r
194 \r
195         lmSend.len = 0;\r
196         lmSend.type = LINKMSG_READY;\r
197         lmSend.msg.erase( );\r
198 \r
199         Send( lmSend );\r
200 \r
201         UTIL_LogPrint( "link (%s) - ready\n", getName( ).c_str( ) );\r
202 \r
203         while( 1 )\r
204         {\r
205                 if( m_bKill )\r
206                         return;\r
207 \r
208                 // send\r
209 \r
210                 m_mtxQueued.Claim( );\r
211                 vector<struct linkmsg_t> vecTemp = m_vecQueued;\r
212                 m_vecQueued.clear( );\r
213                 m_mtxQueued.Release( );\r
214 \r
215                 for( vector<struct linkmsg_t> :: iterator i = vecTemp.begin( ); i != vecTemp.end( ); i++ )\r
216                         Send( *i );\r
217 \r
218                 // receive\r
219 \r
220                 lmReceive = Receive( false );\r
221 \r
222                 if( lmReceive.type == LINKMSG_ERROR || lmReceive.type == LINKMSG_NONE )\r
223                 {\r
224                         // ignore\r
225                 }\r
226                 else if( lmReceive.type == LINKMSG_ANNOUNCE )\r
227                 {\r
228                         CAtom *pParams = Decode( lmReceive.msg );\r
229 \r
230                         if( pParams && pParams->isDicti( ) )\r
231                         {\r
232                                 CAtomDicti *pParamsDicti = (CAtomDicti *)pParams;\r
233 \r
234                                 CAtom *pInfoHash = pParamsDicti->getItem( "info_hash" );\r
235                                 CAtom *pIP = pParamsDicti->getItem( "ip" );\r
236                                 CAtom *pEvent = pParamsDicti->getItem( "event" );\r
237                                 CAtom *pPort = pParamsDicti->getItem( "port" );\r
238                                 CAtom *pUploaded = pParamsDicti->getItem( "uploaded" );\r
239                                 CAtom *pDownloaded = pParamsDicti->getItem( "downloaded" );\r
240                                 CAtom *pLeft = pParamsDicti->getItem( "left" );\r
241                                 CAtom *pPeerID = pParamsDicti->getItem( "peer_id" );\r
242                                 CAtom *pKey = pParamsDicti->getItem( "key" );\r
243                                 CAtom *pAbusive = pParamsDicti->getItem( "abuse" );\r
244                                 CAtom *pIncrement = pParamsDicti->getItem( "increment" );\r
245 \r
246                                 struct announce_t ann;\r
247 \r
248                                 if( pInfoHash && pIP && pPort && pUploaded && pDownloaded && pLeft && pPeerID )\r
249                                 {\r
250                                         ann.strInfoHash = pInfoHash->toString( );\r
251                                         ann.strIP = pIP->toString( );\r
252                                         ann.iPort = (unsigned int)( (CAtomLong *)pPort )->getValue( );\r
253                                         ann.iUploaded = ( (CAtomLong *)pUploaded )->getValue( );\r
254                                         ann.iDownloaded = ( (CAtomLong *)pDownloaded )->getValue( );\r
255                                         ann.iLeft = ( (CAtomLong *)pLeft )->getValue( );\r
256                                         ann.strPeerID = pPeerID->toString( );\r
257                                         if( pKey )\r
258                                                 ann.strKey = pKey->toString( );\r
259                                         if( pAbusive && ((CAtomLong *)pAbusive)->getValue () == 1 )\r
260                                                 ann.bAbusive = true;\r
261                                         if( pIncrement && ((CAtomLong *)pIncrement)->getValue () == 1)\r
262                                                 ann.bIncrement = true;\r
263                                                 \r
264 \r
265                                         // assume strEvent is legit\r
266 \r
267                                         if( pEvent )\r
268                                                 ann.strEvent = pEvent->toString( );\r
269 \r
270                                         gpServer->getTracker( )->QueueAnnounce( ann );\r
271                                 }\r
272 \r
273                                 delete pParams;\r
274                         }\r
275                 }\r
276                 else if( lmReceive.type == LINKMSG_CLOSE )\r
277                 {\r
278                         UTIL_LogPrint( "link warning (%s) - other end closing connection\n", getName( ).c_str( ) );\r
279 \r
280                         return;\r
281                 }\r
282                 else\r
283                         UTIL_LogPrint( "link warning (%s) - unexpected message %d\n", getName( ).c_str( ), lmReceive.type );\r
284         }\r
285 }\r
286 \r
287 void CLink :: Send( struct linkmsg_t lm )\r
288 {\r
289         if( m_bKill )\r
290                 return;\r
291 \r
292         m_strSendBuf.erase( );\r
293         m_strSendBuf += CAtomLong( lm.len ).toString( );\r
294         m_strSendBuf += "|";\r
295         m_strSendBuf += CAtomInt( lm.type ).toString( );\r
296         m_strSendBuf += "|";\r
297         m_strSendBuf += lm.msg;\r
298 \r
299         while( !m_strSendBuf.empty( ) )\r
300         {\r
301                 int s = send( m_sckLink, m_strSendBuf.c_str( ), m_strSendBuf.size( ), MSG_NOSIGNAL );\r
302 \r
303                 if( s == SOCKET_ERROR )\r
304                 {\r
305                         UTIL_LogPrint( "link error (%s) - send error (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
306 \r
307                         Kill( );\r
308 \r
309                         return;\r
310                 }\r
311 \r
312                 if( s > 0 )\r
313                         m_strSendBuf = m_strSendBuf.substr( s );\r
314         }\r
315 }\r
316 \r
317 struct linkmsg_t CLink :: Receive( bool bBlock )\r
318 {\r
319         struct linkmsg_t lm;\r
320 \r
321         lm.len = 0;\r
322         lm.type = LINKMSG_NONE;\r
323 \r
324         if( m_bKill )\r
325                 return lm;\r
326 \r
327         if( bBlock )\r
328         {\r
329                 while( 1 )\r
330                 {\r
331                         char pTemp[16384];\r
332 \r
333                         memset( pTemp, 0, sizeof( char ) * 16384 );\r
334 \r
335                         int c = recv( m_sckLink, pTemp, 16384, 0 );\r
336 \r
337                         if( c == SOCKET_ERROR )\r
338                         {\r
339                                 UTIL_LogPrint( "link error (%s) - receive error (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
340 \r
341                                 Kill( );\r
342 \r
343                                 return lm;\r
344                         }\r
345 \r
346                         if( c > 0 )\r
347                                 m_strReceiveBuf += string( pTemp, c );\r
348 \r
349                         lm = Parse( );\r
350 \r
351                         if( lm.type != LINKMSG_NONE )\r
352                                 return lm;\r
353                 }\r
354         }\r
355         else\r
356         {\r
357                 fd_set fdLink;\r
358 \r
359                 FD_ZERO( &fdLink );\r
360                 FD_SET( m_sckLink, &fdLink );\r
361 \r
362                 // block for 100 ms to keep from eating up all cpu time\r
363 \r
364                 struct timeval tv;\r
365 \r
366                 tv.tv_sec = 0;\r
367                 tv.tv_usec = 100000;\r
368 \r
369 #ifdef WIN32\r
370                 if( select( 1, &fdLink, NULL, NULL, &tv ) == SOCKET_ERROR )\r
371 #else\r
372                 if( select( m_sckLink + 1, &fdLink, NULL, NULL, &tv ) == SOCKET_ERROR )\r
373 #endif\r
374                 {\r
375                         UTIL_LogPrint( "link warning (%s) - select error (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
376 \r
377                         FD_ZERO( &fdLink );\r
378 \r
379                         MILLISLEEP( 100 );\r
380                 }\r
381 \r
382                 if( FD_ISSET( m_sckLink, &fdLink ) )\r
383                 {\r
384                         char pTemp[16384];\r
385 \r
386                         memset( pTemp, 0, sizeof( char ) * 16384 );\r
387 \r
388                         int c = recv( m_sckLink, pTemp, 16384, 0 );\r
389 \r
390                         if( c == SOCKET_ERROR )\r
391                         {\r
392                                 UTIL_LogPrint( "link error (%s) - receive error (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
393 \r
394                                 Kill( );\r
395 \r
396                                 return lm;\r
397                         }\r
398 \r
399                         if( c > 0 )\r
400                                 m_strReceiveBuf += string( pTemp, c );\r
401                 }\r
402 \r
403                 lm = Parse( );\r
404         }\r
405 \r
406         return lm;\r
407 }\r
408 \r
409 struct linkmsg_t CLink :: Parse( )\r
410 {\r
411         linkmsg_t lm;\r
412 \r
413         lm.len = 0;\r
414         lm.type = LINKMSG_NONE;\r
415 \r
416         if( m_bKill )\r
417                 return lm;\r
418 \r
419         string :: size_type iDelim1 = m_strReceiveBuf.find_first_not_of( "1234567890" );\r
420 \r
421         if( iDelim1 != string :: npos )\r
422         {\r
423                 if( iDelim1 > 0 )\r
424                 {\r
425                         lm.len = atoi( m_strReceiveBuf.substr( 0, iDelim1 ).c_str( ) );\r
426 \r
427                         string :: size_type iDelim2 = m_strReceiveBuf.find_first_not_of( "1234567890", iDelim1 + 1 );\r
428 \r
429                         if( iDelim2 != string :: npos )\r
430                         {\r
431                                 if( iDelim2 > iDelim1 )\r
432                                 {\r
433                                         lm.type = atoi( m_strReceiveBuf.substr( iDelim1 + 1, iDelim2 - iDelim1 - 1 ).c_str( ) );\r
434 \r
435                                         if( m_strReceiveBuf.size( ) > iDelim2 + lm.len )\r
436                                         {\r
437                                                 lm.msg = m_strReceiveBuf.substr( iDelim2 + 1, lm.len );\r
438 \r
439                                                 m_strReceiveBuf = m_strReceiveBuf.substr( iDelim2 + lm.len + 1 );\r
440                                         }\r
441                                 }\r
442                                 else\r
443                                 {\r
444                                         UTIL_LogPrint( "link error (%s) - unexpected character, disconnecting\n", getName( ).c_str( ) );\r
445 \r
446                                         Kill( );\r
447                                 }\r
448                         }\r
449                 }\r
450                 else\r
451                 {\r
452                         UTIL_LogPrint( "link error (%s) - unexpected character, disconnecting\n", getName( ).c_str( ) );\r
453 \r
454                         Kill( );\r
455                 }\r
456         }\r
457 \r
458         return lm;\r
459 }\r
460 \r
461 string CLink :: getName( )\r
462 {\r
463         return m_strIP + ":" + CAtomInt( ntohs( sin.sin_port ) ).toString( );\r
464 }\r
465 \r
466 void CLink :: Queue( struct linkmsg_t lm )\r
467 {\r
468         m_mtxQueued.Claim( );\r
469         m_vecQueued.push_back( lm );\r
470         m_mtxQueued.Release( );\r
471 }\r
472 \r
473 void StartLink( )\r
474 {\r
475         while( gpServer )\r
476         {\r
477                 gpLink = new CLink( );\r
478 \r
479                 gpLink->Go( );\r
480 \r
481                 delete gpLink;\r
482 \r
483                 gpLink = NULL;\r
484 \r
485                 MILLISLEEP( 10000 );\r
486         }\r
487 }\r
488 \r
489 //\r
490 // CLinkClient\r
491 //\r
492 \r
493 CLinkClient :: CLinkClient( SOCKET sckLink, struct sockaddr_in sinAddress )\r
494 {\r
495         m_mtxQueued.Initialize( );\r
496 \r
497         m_bKill = false;\r
498         m_bActive = false;\r
499 \r
500         m_sckLink = sckLink;\r
501 \r
502         sin = sinAddress;\r
503 \r
504         UTIL_LogPrint( "link (%s) - link established\n", getName( ).c_str( ) );\r
505 }\r
506 \r
507 CLinkClient :: ~CLinkClient( )\r
508 {\r
509         linkmsg_t lmClose;\r
510 \r
511         lmClose.len = 0;\r
512         lmClose.type = LINKMSG_CLOSE;\r
513         lmClose.msg.erase( );\r
514 \r
515         Send( lmClose );\r
516 \r
517         closesocket( m_sckLink );\r
518 \r
519         m_mtxQueued.Destroy( );\r
520 \r
521         UTIL_LogPrint( "link (%s) - link broken\n", getName( ).c_str( ) );\r
522 }\r
523 \r
524 void CLinkClient :: Kill( )\r
525 {\r
526         m_bKill = true;\r
527 }\r
528 \r
529 void CLinkClient :: Go( )\r
530 {\r
531         struct linkmsg_t lmSend;\r
532         struct linkmsg_t lmReceive;\r
533 \r
534         lmSend.len = strlen( LINK_VER );\r
535         lmSend.type = LINKMSG_VERSION;\r
536         lmSend.msg = LINK_VER;\r
537 \r
538         Send( lmSend );\r
539 \r
540         lmReceive = Receive( true );\r
541 \r
542         if( lmReceive.type != LINKMSG_VERSION || lmReceive.msg != LINK_VER )\r
543         {\r
544                 UTIL_LogPrint( "link error (%s) - incompatible version, disconnecting\n", getName( ).c_str( ) );\r
545 \r
546                 return;\r
547         }\r
548 \r
549         // todo -> change nonce\r
550 \r
551         string strNonce = "hello";\r
552 \r
553         CAtomDicti *pInfo = new CAtomDicti( );\r
554 \r
555         pInfo->setItem( "nonce", new CAtomString( strNonce ) );\r
556 \r
557         lmSend.len = pInfo->EncodedLength( );\r
558         lmSend.type = LINKMSG_INFO;\r
559         lmSend.msg = Encode( pInfo );\r
560 \r
561     Send( lmSend );\r
562 \r
563         delete pInfo;\r
564 \r
565         lmReceive = Receive( true );\r
566 \r
567         if( lmReceive.type != LINKMSG_PASSWORD )\r
568         {\r
569                 UTIL_LogPrint( "link error (%s) - unexpected message, disconnecting\n", getName( ).c_str( ) );\r
570 \r
571                 return;\r
572         }\r
573 \r
574         string strHashMe = gpLinkServer->m_strPass + ":" + strNonce;\r
575 \r
576         unsigned char szMD5[16];\r
577 \r
578         MD5_CTX md5;\r
579 \r
580         MD5Init( &md5 );\r
581         MD5Update( &md5, (unsigned char *)strHashMe.c_str( ), strHashMe.size( ) );\r
582         MD5Final( szMD5, &md5 );\r
583 \r
584         string strMD5 = string( (char *)szMD5, 16 );\r
585 \r
586         if( strMD5 == lmReceive.msg )\r
587                 UTIL_LogPrint( "link (%s) - password accepted\n", getName( ).c_str( ) );\r
588         else\r
589         {\r
590                 UTIL_LogPrint( "link error (%s) - bad password, disconnecting\n", getName( ).c_str( ) );\r
591 \r
592                 return;\r
593         }\r
594 \r
595         while( 1 )\r
596         {\r
597                 if( m_bKill )\r
598                         return;\r
599 \r
600                 // send\r
601 \r
602                 if( m_bActive )\r
603                 {\r
604                         m_mtxQueued.Claim( );\r
605                         vector<struct linkmsg_t> vecTemp = m_vecQueued;\r
606                         m_vecQueued.clear( );\r
607                         m_mtxQueued.Release( );\r
608 \r
609                         for( vector<struct linkmsg_t> :: iterator i = vecTemp.begin( ); i != vecTemp.end( ); i++ )\r
610                                 Send( *i );\r
611                 }\r
612 \r
613                 // receive\r
614 \r
615                 lmReceive = Receive( false );\r
616 \r
617                 if( lmReceive.type == LINKMSG_ERROR || lmReceive.type == LINKMSG_NONE )\r
618                 {\r
619                         // ignore\r
620                 }\r
621                 else if( lmReceive.type == LINKMSG_READY )\r
622                 {\r
623                         if( gbDebug )\r
624                                 UTIL_LogPrint( "link (%s) - ready\n", getName( ).c_str( ) );\r
625 \r
626                         m_bActive = true;\r
627                 }\r
628                 else if( lmReceive.type == LINKMSG_ANNOUNCE )\r
629                 {\r
630                         CAtom *pParams = Decode( lmReceive.msg );\r
631 \r
632                         if( pParams && pParams->isDicti( ) )\r
633                         {\r
634                                 CAtomDicti *pParamsDicti = (CAtomDicti *)pParams;\r
635 \r
636                                 CAtom *pInfoHash = pParamsDicti->getItem( "info_hash" );\r
637                                 CAtom *pIP = pParamsDicti->getItem( "ip" );\r
638                                 CAtom *pEvent = pParamsDicti->getItem( "event" );\r
639                                 CAtom *pPort = pParamsDicti->getItem( "port" );\r
640                                 CAtom *pUploaded = pParamsDicti->getItem( "uploaded" );\r
641                                 CAtom *pDownloaded = pParamsDicti->getItem( "downloaded" );\r
642                                 CAtom *pLeft = pParamsDicti->getItem( "left" );\r
643                                 CAtom *pPeerID = pParamsDicti->getItem( "peer_id" );\r
644 \r
645                                 struct announce_t ann;\r
646 \r
647                                 if( pInfoHash && pIP && pPort && pUploaded && pDownloaded && pLeft && pPeerID )\r
648                                 {\r
649                                         ann.strInfoHash = pInfoHash->toString( );\r
650                                         ann.strIP = pIP->toString( );\r
651                                         ann.iPort = (unsigned int)( (CAtomLong *)pPort )->getValue( );\r
652                                         ann.iUploaded = ( (CAtomLong *)pUploaded )->getValue( );\r
653                                         ann.iDownloaded = ( (CAtomLong *)pDownloaded )->getValue( );\r
654                                         ann.iLeft = ( (CAtomLong *)pLeft )->getValue( );\r
655                                         ann.strPeerID = pPeerID->toString( );\r
656 \r
657                                         // assume strEvent is legit\r
658 \r
659                                         if( pEvent )\r
660                                                 ann.strEvent = pEvent->toString( );\r
661 \r
662                                         gpServer->getTracker( )->QueueAnnounce( ann );\r
663                                 }\r
664 \r
665                                 delete pParams;\r
666                         }\r
667 \r
668                         gpLinkServer->Queue( lmReceive, getName( ) );\r
669                 }\r
670                 else if( lmReceive.type == LINKMSG_CLOSE )\r
671                 {\r
672                         UTIL_LogPrint( "link warning (%s) - other end closing connection\n", getName( ).c_str( ) );\r
673 \r
674                         return;\r
675                 }\r
676                 else\r
677                         UTIL_LogPrint( "link warning (%s) - unexpected message %d\n", getName( ).c_str( ), lmReceive.type );\r
678         }\r
679 }\r
680 \r
681 void CLinkClient :: Send( struct linkmsg_t lm )\r
682 {\r
683         if( m_bKill )\r
684                 return;\r
685 \r
686         m_strSendBuf.erase( );\r
687         m_strSendBuf += CAtomLong( lm.len ).toString( );\r
688         m_strSendBuf += "|";\r
689         m_strSendBuf += CAtomInt( lm.type ).toString( );\r
690         m_strSendBuf += "|";\r
691         m_strSendBuf += lm.msg;\r
692 \r
693         while( !m_strSendBuf.empty( ) )\r
694         {\r
695                 int s = send( m_sckLink, m_strSendBuf.c_str( ), m_strSendBuf.size( ), MSG_NOSIGNAL );\r
696 \r
697                 if( s == SOCKET_ERROR )\r
698                 {\r
699                         UTIL_LogPrint( "link error (%s) - send error (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
700 \r
701                         Kill( );\r
702 \r
703                         return;\r
704                 }\r
705 \r
706                 if( s > 0 )\r
707                         m_strSendBuf = m_strSendBuf.substr( s );\r
708         }\r
709 }\r
710 \r
711 struct linkmsg_t CLinkClient :: Receive( bool bBlock )\r
712 {\r
713         struct linkmsg_t lm;\r
714 \r
715         lm.len = 0;\r
716         lm.type = LINKMSG_NONE;\r
717 \r
718         if( m_bKill )\r
719                 return lm;\r
720 \r
721         if( bBlock )\r
722         {\r
723                 while( 1 )\r
724                 {\r
725                         char pTemp[16384];\r
726 \r
727                         memset( pTemp, 0, sizeof( char ) * 16384 );\r
728 \r
729                         int c = recv( m_sckLink, pTemp, 16384, 0 );\r
730 \r
731                         if( c == SOCKET_ERROR )\r
732                         {\r
733                                 UTIL_LogPrint( "link error (%s) - receive error (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
734 \r
735                                 Kill( );\r
736 \r
737                                 return lm;\r
738                         }\r
739 \r
740                         if( c > 0 )\r
741                                 m_strReceiveBuf += string( pTemp, c );\r
742 \r
743                         lm = Parse( );\r
744 \r
745                         if( lm.type != LINKMSG_NONE )\r
746                                 return lm;\r
747                 }\r
748         }\r
749         else\r
750         {\r
751                 fd_set fdLink;\r
752 \r
753                 FD_ZERO( &fdLink );\r
754                 FD_SET( m_sckLink, &fdLink );\r
755 \r
756                 // block for 100 ms to keep from eating up all cpu time\r
757 \r
758                 struct timeval tv;\r
759 \r
760                 tv.tv_sec = 0;\r
761                 tv.tv_usec = 100000;\r
762 \r
763 #ifdef WIN32\r
764                 if( select( 1, &fdLink, NULL, NULL, &tv ) == SOCKET_ERROR )\r
765 #else\r
766                 if( select( m_sckLink + 1, &fdLink, NULL, NULL, &tv ) == SOCKET_ERROR )\r
767 #endif\r
768                 {\r
769                         UTIL_LogPrint( "link warning (%s) - select error (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
770 \r
771                         FD_ZERO( &fdLink );\r
772 \r
773                         MILLISLEEP( 100 );\r
774                 }\r
775 \r
776                 if( FD_ISSET( m_sckLink, &fdLink ) )\r
777                 {\r
778                         char pTemp[16384];\r
779 \r
780                         memset( pTemp, 0, sizeof( char ) * 16384 );\r
781 \r
782                         int c = recv( m_sckLink, pTemp, 16384, 0 );\r
783 \r
784                         if( c == SOCKET_ERROR )\r
785                         {\r
786                                 UTIL_LogPrint( "link error (%s) - receive error (error %d)\n", getName( ).c_str( ), GetLastError( ) );\r
787 \r
788                                 Kill( );\r
789 \r
790                                 return lm;\r
791                         }\r
792 \r
793                         if( c > 0 )\r
794                                 m_strReceiveBuf += string( pTemp, c );\r
795                 }\r
796 \r
797                 lm = Parse( );\r
798         }\r
799 \r
800         return lm;\r
801 }\r
802 \r
803 struct linkmsg_t CLinkClient :: Parse( )\r
804 {\r
805         linkmsg_t lm;\r
806 \r
807         lm.len = 0;\r
808         lm.type = LINKMSG_NONE;\r
809 \r
810         if( m_bKill )\r
811                 return lm;\r
812 \r
813         string :: size_type iDelim1 = m_strReceiveBuf.find_first_not_of( "1234567890" );\r
814 \r
815         if( iDelim1 != string :: npos )\r
816         {\r
817                 if( iDelim1 > 0 )\r
818                 {\r
819                         lm.len = atoi( m_strReceiveBuf.substr( 0, iDelim1 ).c_str( ) );\r
820 \r
821                         string :: size_type iDelim2 = m_strReceiveBuf.find_first_not_of( "1234567890", iDelim1 + 1 );\r
822 \r
823                         if( iDelim2 != string :: npos )\r
824                         {\r
825                                 if( iDelim2 > iDelim1 )\r
826                                 {\r
827                                         lm.type = atoi( m_strReceiveBuf.substr( iDelim1 + 1, iDelim2 - iDelim1 - 1 ).c_str( ) );\r
828 \r
829                                         if( m_strReceiveBuf.size( ) > iDelim2 + lm.len )\r
830                                         {\r
831                                                 lm.msg = m_strReceiveBuf.substr( iDelim2 + 1, lm.len );\r
832 \r
833                                                 m_strReceiveBuf = m_strReceiveBuf.substr( iDelim2 + lm.len + 1 );\r
834                                         }\r
835                                 }\r
836                                 else\r
837                                 {\r
838                                         UTIL_LogPrint( "link error (%s) - unexpected character, disconnecting\n", getName( ).c_str( ) );\r
839 \r
840                                         Kill( );\r
841                                 }\r
842                         }\r
843                 }\r
844                 else\r
845                 {\r
846                         UTIL_LogPrint( "link error (%s) - unexpected character, disconnecting\n", getName( ).c_str( ) );\r
847 \r
848                         Kill( );\r
849                 }\r
850         }\r
851 \r
852         return lm;\r
853 }\r
854 \r
855 string CLinkClient :: getName( )\r
856 {\r
857         return string( inet_ntoa( sin.sin_addr ) ) + ":" + CAtomInt( ntohs( sin.sin_port ) ).toString( );\r
858 }\r
859 \r
860 void CLinkClient :: Queue( struct linkmsg_t lm )\r
861 {\r
862         m_mtxQueued.Claim( );\r
863         m_vecQueued.push_back( lm );\r
864         m_mtxQueued.Release( );\r
865 }\r
866 \r
867 void StartLinkClient( CLinkClient *pLinkClient )\r
868 {\r
869         if( pLinkClient )\r
870         {\r
871                 pLinkClient->Go( );\r
872 \r
873                 gpLinkServer->m_mtxLinks.Claim( );\r
874 \r
875                 for( vector<CLinkClient *> :: iterator i = gpLinkServer->m_vecLinks.begin( ); i != gpLinkServer->m_vecLinks.end( ); i++ )\r
876                 {\r
877                         if( *i == pLinkClient )\r
878                         {\r
879                                 delete *i;\r
880 \r
881                                 gpLinkServer->m_vecLinks.erase( i );\r
882 \r
883                                 break;\r
884                         }\r
885                 }\r
886 \r
887                 gpLinkServer->m_mtxLinks.Release( );\r
888         }\r
889 }\r
890 \r
891 //\r
892 // CLinkServer\r
893 //\r
894 \r
895 CLinkServer :: CLinkServer( )\r
896 {\r
897         m_mtxLinks.Initialize( );\r
898 \r
899         m_strBind = CFG_GetString( "bnbt_tlink_bind", string( ) );\r
900         m_strPass = CFG_GetString( "bnbt_tlink_password", string( ) );\r
901 \r
902         struct sockaddr_in sin;\r
903 \r
904         memset( &sin, 0, sizeof( sin ) );\r
905 \r
906         sin.sin_family = AF_INET;\r
907 \r
908         if( !m_strBind.empty( ) )\r
909         {\r
910                 // bind to m_strBind\r
911 \r
912                 if( gbDebug )\r
913                         UTIL_LogPrint( "link server - binding to %s\n", m_strBind.c_str( ) );\r
914 \r
915                 if( ( sin.sin_addr.s_addr = inet_addr( m_strBind.c_str( ) ) ) == INADDR_NONE )\r
916                         UTIL_LogPrint( "link server error - unable to bind to %s\n", m_strBind.c_str( ) );\r
917         }\r
918         else\r
919         {\r
920                 // bind to all available addresses\r
921 \r
922                 if( gbDebug )\r
923                         UTIL_LogPrint( "link server - binding to all available addresses\n" );\r
924 \r
925                 sin.sin_addr.s_addr = INADDR_ANY;\r
926         }\r
927 \r
928         if( ( sin.sin_port = htons( (u_short)CFG_GetInt( "bnbt_tlink_port", 5204 ) ) ) == 0 )\r
929                 UTIL_LogPrint( "link server error - invalid port %d\n", CFG_GetInt( "bnbt_tlink_port", 5204 ) );\r
930 \r
931         // map protocol name to protocol number\r
932 \r
933         struct protoent *pPE;\r
934 \r
935         if( ( pPE = getprotobyname( "tcp" ) ) == 0 )\r
936                 UTIL_LogPrint( "link server error - unable to get tcp protocol entry (error %d)\n", GetLastError( ) );\r
937 \r
938         // allocate socket\r
939 \r
940         if( ( m_sckLinkServer = socket( PF_INET, SOCK_STREAM, pPE->p_proto ) ) == INVALID_SOCKET )\r
941                 UTIL_LogPrint( "link server error - unable to allocate socket (error %d)\n", GetLastError( ) );\r
942 \r
943         // bind socket\r
944 \r
945         int optval = 1;\r
946 \r
947 #ifdef WIN32\r
948         setsockopt( m_sckLinkServer, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof( int ) );\r
949 #else\r
950         setsockopt( m_sckLinkServer, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof( int ) );\r
951 #endif\r
952 \r
953         if( bind( m_sckLinkServer, (struct sockaddr *)&sin, sizeof( sin ) ) == SOCKET_ERROR )\r
954                 UTIL_LogPrint( "link server error - unable to bind socket (error %d)\n", GetLastError( ) );\r
955 \r
956         // listen, queue length 1\r
957 \r
958         if( listen( m_sckLinkServer, 1 ) == SOCKET_ERROR )\r
959                 UTIL_LogPrint( "link server error - unable to listen (error %d)\n", GetLastError( ) );\r
960 \r
961         UTIL_LogPrint( "link server - start\n" );\r
962 }\r
963 \r
964 CLinkServer :: ~CLinkServer( )\r
965 {\r
966         closesocket( m_sckLinkServer );\r
967 \r
968         for( vector<CLinkClient *> :: iterator i = m_vecLinks.begin( ); i != m_vecLinks.end( ); i++ )\r
969                 (*i)->Kill( );\r
970 \r
971         unsigned long iStart = GetTime( );\r
972 \r
973         while( 1 )\r
974         {\r
975                 if( !m_vecLinks.empty( ) )\r
976                 {\r
977                         UTIL_LogPrint( "link server - waiting for %d links to disconnect\n", m_vecLinks.size( ) );\r
978 \r
979                         MILLISLEEP( 1000 );\r
980                 }\r
981                 else\r
982                         break;\r
983 \r
984                 if( GetTime( ) - iStart > 60 )\r
985                 {\r
986                         UTIL_LogPrint( "link server - waited 60 seconds, exiting anyway\n" );\r
987 \r
988                         break;\r
989                 }\r
990         }\r
991 \r
992         m_mtxLinks.Destroy( );\r
993 \r
994         UTIL_LogPrint( "link server - exit\n" );\r
995 }\r
996 \r
997 void CLinkServer :: Update( )\r
998 {\r
999         fd_set fdLinkServer;\r
1000 \r
1001         FD_ZERO( &fdLinkServer );\r
1002         FD_SET( m_sckLinkServer, &fdLinkServer );\r
1003 \r
1004         struct timeval tv;\r
1005 \r
1006         tv.tv_sec = 0;\r
1007         tv.tv_usec = 0;\r
1008 \r
1009 #ifdef WIN32\r
1010         if( select( 1, &fdLinkServer, NULL, NULL, &tv ) == SOCKET_ERROR )\r
1011 #else\r
1012         if( select( m_sckLinkServer + 1, &fdLinkServer, NULL, NULL, &tv ) == SOCKET_ERROR )\r
1013 #endif\r
1014         {\r
1015                 UTIL_LogPrint( "link server error - select error (error %d)\n", GetLastError( ) );\r
1016 \r
1017                 FD_ZERO( &fdLinkServer );\r
1018 \r
1019                 MILLISLEEP( 100 );\r
1020         }\r
1021 \r
1022         if( FD_ISSET( m_sckLinkServer, &fdLinkServer ) )\r
1023         {\r
1024                 struct sockaddr_in adrFrom;\r
1025 \r
1026                 int iAddrLen = sizeof( adrFrom );\r
1027 \r
1028                 SOCKET sckLinkClient;\r
1029 \r
1030 #ifdef WIN32\r
1031                 if( ( sckLinkClient = accept( m_sckLinkServer, (struct sockaddr *)&adrFrom, &iAddrLen ) ) == INVALID_SOCKET )\r
1032 #else\r
1033                 if( ( sckLinkClient = accept( m_sckLinkServer, (struct sockaddr *)&adrFrom, (socklen_t *)&iAddrLen ) ) == INVALID_SOCKET )\r
1034 #endif\r
1035                         UTIL_LogPrint( "link server error - accept error (error %d)\n", GetLastError( ) );\r
1036                 else\r
1037                 {\r
1038                         CLinkClient *pLinkClient = new CLinkClient( sckLinkClient, adrFrom );\r
1039 \r
1040 #ifdef WIN32\r
1041                         if( _beginthread( ( void (*)(void *) )StartLinkClient, 0, (void *)pLinkClient ) == -1 )\r
1042                                 UTIL_LogPrint( "error - unable to spawn link client thread\n" );\r
1043 #else\r
1044                         pthread_t thread;\r
1045 \r
1046                         // set detached state since we don't need to join with any threads\r
1047 \r
1048                         pthread_attr_t attr;\r
1049                         pthread_attr_init( &attr );\r
1050                         pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );\r
1051 \r
1052                         int c = pthread_create( &thread, &attr, ( void * (*)(void *) )StartLinkClient, (void *)pLinkClient );\r
1053 \r
1054                         if( c != 0 )\r
1055                                 UTIL_LogPrint( "error - unable to spawn link thread (error %s)\n", strerror( c ) );\r
1056 #endif\r
1057 \r
1058                         m_mtxLinks.Claim( );\r
1059                         m_vecLinks.push_back( pLinkClient );\r
1060                         m_mtxLinks.Release( );\r
1061                 }\r
1062         }\r
1063 }\r
1064 \r
1065 void CLinkServer :: Queue( struct linkmsg_t lm )\r
1066 {\r
1067         m_mtxLinks.Claim( );\r
1068 \r
1069         for( vector<CLinkClient *> :: iterator i = m_vecLinks.begin( ); i != m_vecLinks.end( ); i++ )\r
1070                 (*i)->Queue( lm );\r
1071 \r
1072         m_mtxLinks.Release( );\r
1073 }\r
1074 \r
1075 void CLinkServer :: Queue( struct linkmsg_t lm, string strExclude )\r
1076 {\r
1077         m_mtxLinks.Claim( );\r
1078 \r
1079         for( vector<CLinkClient *> :: iterator i = m_vecLinks.begin( ); i != m_vecLinks.end( ); i++ )\r
1080         {\r
1081                 if( (*i)->getName( ) != strExclude )\r
1082                         (*i)->Queue( lm );\r
1083         }\r
1084 \r
1085         m_mtxLinks.Release( );\r
1086 }\r