An open and free bittorrent tracker https://erdgeist.org/gitweb/opentracker
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

458 wiersze
15 KiB

  1. /* This software was written by Dirk Engling <erdgeist@erdgeist.org>
  2. It is considered beerware. Prost. Skol. Cheers or whatever.
  3. $id$ */
  4. /* System */
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <stdio.h>
  8. #include <arpa/inet.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include <stdint.h>
  12. /* Libowfat */
  13. #include "byte.h"
  14. #include "io.h"
  15. #include "iob.h"
  16. #include "array.h"
  17. /* Opentracker */
  18. #include "trackerlogic.h"
  19. #include "ot_mutex.h"
  20. #include "ot_stats.h"
  21. #include "ot_clean.h"
  22. #include "ot_http.h"
  23. #include "ot_accesslist.h"
  24. #include "ot_fullscrape.h"
  25. #include "ot_livesync.h"
  26. /* Forward declaration */
  27. size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto );
  28. void free_peerlist( ot_peerlist *peer_list ) {
  29. if( peer_list->peers.data ) {
  30. if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
  31. ot_vector *bucket_list = (ot_vector*)(peer_list->peers.data);
  32. while( peer_list->peers.size-- )
  33. free( bucket_list++->data );
  34. }
  35. free( peer_list->peers.data );
  36. }
  37. free( peer_list );
  38. }
  39. void add_torrent_from_saved_state( ot_hash hash, ot_time base, size_t down_count ) {
  40. int exactmatch;
  41. ot_torrent *torrent;
  42. ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
  43. if( !accesslist_hashisvalid( hash ) )
  44. return mutex_bucket_unlock_by_hash( hash, 0 );
  45. torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
  46. if( !torrent || exactmatch )
  47. return mutex_bucket_unlock_by_hash( hash, 0 );
  48. /* Create a new torrent entry, then */
  49. memcpy( torrent->hash, hash, sizeof(ot_hash) );
  50. if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
  51. vector_remove_torrent( torrents_list, torrent );
  52. return mutex_bucket_unlock_by_hash( hash, 0 );
  53. }
  54. byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
  55. torrent->peer_list->base = base;
  56. torrent->peer_list->down_count = down_count;
  57. return mutex_bucket_unlock_by_hash( hash, 1 );
  58. }
  59. size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ) {
  60. int exactmatch, delta_torrentcount = 0;
  61. ot_torrent *torrent;
  62. ot_peer *peer_dest;
  63. ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
  64. if( !accesslist_hashisvalid( *ws->hash ) ) {
  65. mutex_bucket_unlock_by_hash( *ws->hash, 0 );
  66. if( proto == FLAG_TCP ) {
  67. const char invalid_hash[] = "d14:failure reason63:Requested download is not authorized for use with this tracker.e";
  68. memcpy( ws->reply, invalid_hash, strlen( invalid_hash ) );
  69. return strlen( invalid_hash );
  70. }
  71. return 0;
  72. }
  73. torrent = vector_find_or_insert( torrents_list, (void*)ws->hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
  74. if( !torrent ) {
  75. mutex_bucket_unlock_by_hash( *ws->hash, 0 );
  76. return 0;
  77. }
  78. if( !exactmatch ) {
  79. /* Create a new torrent entry, then */
  80. memcpy( torrent->hash, *ws->hash, sizeof(ot_hash) );
  81. if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
  82. vector_remove_torrent( torrents_list, torrent );
  83. mutex_bucket_unlock_by_hash( *ws->hash, 0 );
  84. return 0;
  85. }
  86. byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
  87. delta_torrentcount = 1;
  88. } else
  89. clean_single_torrent( torrent );
  90. torrent->peer_list->base = g_now_minutes;
  91. /* Check for peer in torrent */
  92. peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), &ws->peer, &exactmatch );
  93. if( !peer_dest ) {
  94. mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
  95. return 0;
  96. }
  97. /* Tell peer that it's fresh */
  98. OT_PEERTIME( &ws->peer ) = 0;
  99. /* Sanitize flags: Whoever claims to have completed download, must be a seeder */
  100. if( ( OT_PEERFLAG( &ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
  101. OT_PEERFLAG( &ws->peer ) ^= PEER_FLAG_COMPLETED;
  102. /* If we hadn't had a match create peer there */
  103. if( !exactmatch ) {
  104. #ifdef WANT_SYNC_LIVE
  105. if( proto == FLAG_MCA )
  106. OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_FROM_SYNC;
  107. else
  108. livesync_tell( ws );
  109. #endif
  110. torrent->peer_list->peer_count++;
  111. if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) {
  112. torrent->peer_list->down_count++;
  113. stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
  114. }
  115. if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING )
  116. torrent->peer_list->seed_count++;
  117. } else {
  118. stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest ) );
  119. #ifdef WANT_SPOT_WOODPECKER
  120. if( ( OT_PEERTIME(peer_dest) > 0 ) && ( OT_PEERTIME(peer_dest) < 20 ) )
  121. stats_issue_event( EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer );
  122. #endif
  123. #ifdef WANT_SYNC_LIVE
  124. /* Won't live sync peers that come back too fast. Only exception:
  125. fresh "completed" reports */
  126. if( proto != FLAG_MCA ) {
  127. if( OT_PEERTIME( peer_dest ) > OT_CLIENT_SYNC_RENEW_BOUNDARY ||
  128. ( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) )
  129. livesync_tell( ws );
  130. }
  131. #endif
  132. if( (OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) )
  133. torrent->peer_list->seed_count--;
  134. if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) )
  135. torrent->peer_list->seed_count++;
  136. if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) {
  137. torrent->peer_list->down_count++;
  138. stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
  139. }
  140. if( OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED )
  141. OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED;
  142. }
  143. memcpy( peer_dest, &ws->peer, sizeof(ot_peer) );
  144. #ifdef WANT_SYNC
  145. if( proto == FLAG_MCA ) {
  146. mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
  147. return 0;
  148. }
  149. #endif
  150. ws->reply_size = return_peers_for_torrent( torrent, amount, ws->reply, proto );
  151. mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
  152. return ws->reply_size;
  153. }
  154. static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) {
  155. unsigned int bucket, num_buckets = 1;
  156. ot_vector * bucket_list = &peer_list->peers;
  157. size_t result = OT_PEER_COMPARE_SIZE * peer_list->peer_count;
  158. char * r_end = reply + result;
  159. if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
  160. num_buckets = bucket_list->size;
  161. bucket_list = (ot_vector *)bucket_list->data;
  162. }
  163. for( bucket = 0; bucket<num_buckets; ++bucket ) {
  164. ot_peer * peers = (ot_peer*)bucket_list[bucket].data;
  165. size_t peer_count = bucket_list[bucket].size;
  166. while( peer_count-- ) {
  167. if( OT_PEERFLAG(peers) & PEER_FLAG_SEEDING ) {
  168. r_end-=OT_PEER_COMPARE_SIZE;
  169. memcpy(r_end,peers++,OT_PEER_COMPARE_SIZE);
  170. } else {
  171. memcpy(reply,peers++,OT_PEER_COMPARE_SIZE);
  172. reply+=OT_PEER_COMPARE_SIZE;
  173. }
  174. }
  175. }
  176. return result;
  177. }
  178. static size_t return_peers_selection( ot_peerlist *peer_list, size_t amount, char *reply ) {
  179. unsigned int bucket_offset, bucket_index = 0, num_buckets = 1;
  180. ot_vector * bucket_list = &peer_list->peers;
  181. unsigned int shifted_pc = peer_list->peer_count;
  182. unsigned int shifted_step = 0;
  183. unsigned int shift = 0;
  184. size_t result = OT_PEER_COMPARE_SIZE * amount;
  185. char * r_end = reply + result;
  186. if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
  187. num_buckets = bucket_list->size;
  188. bucket_list = (ot_vector *)bucket_list->data;
  189. }
  190. /* Make fixpoint arithmetic as exact as possible */
  191. #define MAXPRECBIT (1<<(8*sizeof(int)-3))
  192. while( !(shifted_pc & MAXPRECBIT ) ) { shifted_pc <<= 1; shift++; }
  193. shifted_step = shifted_pc/amount;
  194. #undef MAXPRECBIT
  195. /* Initialize somewhere in the middle of peers so that
  196. fixpoint's aliasing doesn't alway miss the same peers */
  197. bucket_offset = random() % peer_list->peer_count;
  198. while( amount-- ) {
  199. ot_peer * peer;
  200. /* This is the aliased, non shifted range, next value may fall into */
  201. unsigned int diff = ( ( ( amount + 1 ) * shifted_step ) >> shift ) -
  202. ( ( amount * shifted_step ) >> shift );
  203. bucket_offset += 1 + random() % diff;
  204. while( bucket_offset >= bucket_list[bucket_index].size ) {
  205. bucket_offset -= bucket_list[bucket_index].size;
  206. bucket_index = ( bucket_index + 1 ) % num_buckets;
  207. }
  208. peer = ((ot_peer*)bucket_list[bucket_index].data) + bucket_offset;
  209. if( OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) {
  210. r_end-=OT_PEER_COMPARE_SIZE;
  211. memcpy(r_end,peer,OT_PEER_COMPARE_SIZE);
  212. } else {
  213. memcpy(reply,peer,OT_PEER_COMPARE_SIZE);
  214. reply+=OT_PEER_COMPARE_SIZE;
  215. }
  216. }
  217. return result;
  218. }
  219. /* Compiles a list of random peers for a torrent
  220. * reply must have enough space to hold 92+6*amount bytes
  221. * does not yet check not to return self
  222. */
  223. size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) {
  224. ot_peerlist *peer_list = torrent->peer_list;
  225. char *r = reply;
  226. if( amount > peer_list->peer_count )
  227. amount = peer_list->peer_count;
  228. if( proto == FLAG_TCP ) {
  229. int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
  230. r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie" PEERS_BENCODED "%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, erval, erval/2, OT_PEER_COMPARE_SIZE*amount );
  231. } else {
  232. *(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
  233. *(uint32_t*)(r+4) = htonl( peer_list->peer_count - peer_list->seed_count );
  234. *(uint32_t*)(r+8) = htonl( peer_list->seed_count );
  235. r += 12;
  236. }
  237. if( amount ) {
  238. if( amount == peer_list->peer_count )
  239. r += return_peers_all( peer_list, r );
  240. else
  241. r += return_peers_selection( peer_list, amount, r );
  242. }
  243. if( proto == FLAG_TCP )
  244. *r++ = 'e';
  245. return r - reply;
  246. }
  247. /* Fetches scrape info for a specific torrent */
  248. size_t return_udp_scrape_for_torrent( ot_hash hash, char *reply ) {
  249. int exactmatch, delta_torrentcount = 0;
  250. ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
  251. ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
  252. if( !exactmatch ) {
  253. memset( reply, 0, 12);
  254. } else {
  255. uint32_t *r = (uint32_t*) reply;
  256. if( clean_single_torrent( torrent ) ) {
  257. vector_remove_torrent( torrents_list, torrent );
  258. memset( reply, 0, 12);
  259. delta_torrentcount = -1;
  260. } else {
  261. r[0] = htonl( torrent->peer_list->seed_count );
  262. r[1] = htonl( torrent->peer_list->down_count );
  263. r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count );
  264. }
  265. }
  266. mutex_bucket_unlock_by_hash( hash, delta_torrentcount );
  267. return 12;
  268. }
  269. /* Fetches scrape info for a specific torrent */
  270. size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) {
  271. char *r = reply;
  272. int exactmatch, i;
  273. r += sprintf( r, "d5:filesd" );
  274. for( i=0; i<amount; ++i ) {
  275. int delta_torrentcount = 0;
  276. ot_hash *hash = hash_list + i;
  277. ot_vector *torrents_list = mutex_bucket_lock_by_hash( *hash );
  278. ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
  279. if( exactmatch ) {
  280. if( clean_single_torrent( torrent ) ) {
  281. vector_remove_torrent( torrents_list, torrent );
  282. delta_torrentcount = -1;
  283. } else {
  284. *r++='2';*r++='0';*r++=':';
  285. memcpy( r, hash, sizeof(ot_hash) ); r+=sizeof(ot_hash);
  286. r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee",
  287. torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count );
  288. }
  289. }
  290. mutex_bucket_unlock_by_hash( *hash, delta_torrentcount );
  291. }
  292. *r++ = 'e'; *r++ = 'e';
  293. return r - reply;
  294. }
  295. static ot_peerlist dummy_list;
  296. size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) {
  297. int exactmatch;
  298. ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
  299. ot_torrent *torrent = binary_search( ws->hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
  300. ot_peerlist *peer_list = &dummy_list;
  301. #ifdef WANT_SYNC_LIVE
  302. if( proto != FLAG_MCA ) {
  303. OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED;
  304. livesync_tell( ws );
  305. }
  306. #endif
  307. if( exactmatch ) {
  308. peer_list = torrent->peer_list;
  309. switch( vector_remove_peer( &peer_list->peers, &ws->peer ) ) {
  310. case 2: peer_list->seed_count--; /* Fall throughs intended */
  311. case 1: peer_list->peer_count--; /* Fall throughs intended */
  312. default: break;
  313. }
  314. }
  315. if( proto == FLAG_TCP ) {
  316. int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
  317. ws->reply_size = sprintf( ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie" PEERS_BENCODED "0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, erval, erval / 2 );
  318. }
  319. /* Handle UDP reply */
  320. if( proto == FLAG_UDP ) {
  321. ((uint32_t*)ws->reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
  322. ((uint32_t*)ws->reply)[3] = htonl( peer_list->peer_count - peer_list->seed_count );
  323. ((uint32_t*)ws->reply)[4] = htonl( peer_list->seed_count);
  324. ws->reply_size = 20;
  325. }
  326. mutex_bucket_unlock_by_hash( *ws->hash, 0 );
  327. return ws->reply_size;
  328. }
  329. void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data ), uintptr_t data ) {
  330. int bucket;
  331. size_t j;
  332. for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
  333. ot_vector *torrents_list = mutex_bucket_lock( bucket );
  334. ot_torrent *torrents = (ot_torrent*)(torrents_list->data);
  335. for( j=0; j<torrents_list->size; ++j )
  336. if( for_each( torrents + j, data ) )
  337. break;
  338. mutex_bucket_unlock( bucket, 0 );
  339. if( !g_opentracker_running ) return;
  340. }
  341. }
  342. void exerr( char * message ) {
  343. fprintf( stderr, "%s\n", message );
  344. exit( 111 );
  345. }
  346. void trackerlogic_init( ) {
  347. g_tracker_id = random();
  348. if( !g_stats_path )
  349. g_stats_path = "stats";
  350. g_stats_path_len = strlen( g_stats_path );
  351. /* Initialise background worker threads */
  352. mutex_init( );
  353. clean_init( );
  354. fullscrape_init( );
  355. accesslist_init( );
  356. livesync_init( );
  357. stats_init( );
  358. }
  359. void trackerlogic_deinit( void ) {
  360. int bucket, delta_torrentcount = 0;
  361. size_t j;
  362. /* Free all torrents... */
  363. for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
  364. ot_vector *torrents_list = mutex_bucket_lock( bucket );
  365. if( torrents_list->size ) {
  366. for( j=0; j<torrents_list->size; ++j ) {
  367. ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j;
  368. free_peerlist( torrent->peer_list );
  369. delta_torrentcount -= 1;
  370. }
  371. free( torrents_list->data );
  372. }
  373. mutex_bucket_unlock( bucket, delta_torrentcount );
  374. }
  375. /* Deinitialise background worker threads */
  376. stats_deinit( );
  377. livesync_deinit( );
  378. accesslist_deinit( );
  379. fullscrape_deinit( );
  380. clean_deinit( );
  381. /* Release mutexes */
  382. mutex_deinit( );
  383. }
  384. const char *g_version_trackerlogic_c = "$Source: /home/cvsroot/opentracker/trackerlogic.c,v $: $Revision: 1.139 $\n";