transmission 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,767 @@
1
+ /******************************************************************************
2
+ * $Id: tracker.c 400 2006-06-20 00:28:16Z titer $
3
+ *
4
+ * Copyright (c) 2005-2006 Transmission authors and contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ * DEALINGS IN THE SOFTWARE.
23
+ *****************************************************************************/
24
+
25
+ #include "transmission.h"
26
+
27
+ struct tr_tracker_s
28
+ {
29
+ tr_torrent_t * tor;
30
+
31
+ char * id;
32
+
33
+ char started;
34
+ char completed;
35
+ char stopped;
36
+
37
+ int interval;
38
+ int seeders;
39
+ int leechers;
40
+ int hasManyPeers;
41
+
42
+ uint64_t dateTry;
43
+ uint64_t dateOk;
44
+
45
+ #define TC_STATUS_IDLE 1
46
+ #define TC_STATUS_RESOLVE 2
47
+ #define TC_STATUS_CONNECT 4
48
+ #define TC_STATUS_RECV 8
49
+ char status;
50
+
51
+ #define TC_ATTEMPT_NOREACH 1
52
+ #define TC_ATTEMPT_ERROR 2
53
+ #define TC_ATTEMPT_OK 4
54
+ char lastAttempt;
55
+
56
+ tr_resolve_t * resolve;
57
+ int socket;
58
+ uint8_t * buf;
59
+ int size;
60
+ int pos;
61
+
62
+ int bindPort;
63
+ int newPort;
64
+
65
+ uint64_t download;
66
+ uint64_t upload;
67
+ };
68
+
69
+ static void sendQuery ( tr_tracker_t * tc );
70
+ static void recvAnswer ( tr_tracker_t * tc );
71
+
72
+ tr_tracker_t * tr_trackerInit( tr_torrent_t * tor )
73
+ {
74
+ tr_tracker_t * tc;
75
+
76
+ tc = calloc( 1, sizeof( tr_tracker_t ) );
77
+ tc->tor = tor;
78
+ tc->id = tor->id;
79
+
80
+ tc->started = 1;
81
+
82
+ tc->interval = 300;
83
+ tc->seeders = -1;
84
+ tc->leechers = -1;
85
+
86
+ tc->status = TC_STATUS_IDLE;
87
+ tc->lastAttempt = TC_ATTEMPT_NOREACH;
88
+ tc->size = 1024;
89
+ tc->buf = malloc( tc->size );
90
+
91
+ tc->bindPort = *(tor->bindPort);
92
+ tc->newPort = -1;
93
+
94
+ tc->download = tor->downloaded;
95
+ tc->upload = tor->uploaded;
96
+
97
+ return tc;
98
+ }
99
+
100
+ static int shouldConnect( tr_tracker_t * tc )
101
+ {
102
+ uint64_t now = tr_date();
103
+
104
+ /* Unreachable tracker, try 10 seconds before trying again */
105
+ if( tc->lastAttempt == TC_ATTEMPT_NOREACH &&
106
+ now < tc->dateTry + 10000 )
107
+ {
108
+ return 0;
109
+ }
110
+
111
+ /* The tracker rejected us (like 4XX code, unauthorized IP...),
112
+ don't hammer it - we'll probably get the same answer next time
113
+ anyway */
114
+ if( tc->lastAttempt == TC_ATTEMPT_ERROR &&
115
+ now < tc->dateTry + 1000 * tc->interval )
116
+ {
117
+ return 0;
118
+ }
119
+
120
+ /* Do we need to send an event? */
121
+ if( tc->started || tc->completed || tc->stopped || 0 < tc->newPort )
122
+ {
123
+ return 1;
124
+ }
125
+
126
+ /* Should we try and get more peers? */
127
+ if( now > tc->dateOk + 1000 * tc->interval )
128
+ {
129
+ return 1;
130
+ }
131
+
132
+ /* If there is quite a lot of people on this torrent, stress
133
+ the tracker a bit until we get a decent number of peers */
134
+ if( tc->hasManyPeers )
135
+ {
136
+ if( tc->tor->peerCount < 5 && now > tc->dateOk + 10000 )
137
+ {
138
+ return 1;
139
+ }
140
+ if( tc->tor->peerCount < 10 && now > tc->dateOk + 20000 )
141
+ {
142
+ return 1;
143
+ }
144
+ if( tc->tor->peerCount < 15 && now > tc->dateOk + 30000 )
145
+ {
146
+ return 1;
147
+ }
148
+ }
149
+
150
+ return 0;
151
+ }
152
+
153
+ void tr_trackerChangePort( tr_tracker_t * tc, int port )
154
+ {
155
+ tc->newPort = port;
156
+ }
157
+
158
+ int tr_trackerPulse( tr_tracker_t * tc )
159
+ {
160
+ tr_torrent_t * tor = tc->tor;
161
+ tr_info_t * inf = &tor->info;
162
+ uint64_t now = tr_date();
163
+
164
+ if( ( tc->status & TC_STATUS_IDLE ) && shouldConnect( tc ) )
165
+ {
166
+ tc->resolve = tr_netResolveInit( inf->trackerAddress );
167
+
168
+ tr_inf( "Tracker: connecting to %s:%d (%s)",
169
+ inf->trackerAddress, inf->trackerPort,
170
+ tc->started ? "sending 'started'" :
171
+ ( tc->completed ? "sending 'completed'" :
172
+ ( tc->stopped ? "sending 'stopped'" :
173
+ ( 0 < tc->newPort ? "sending 'stopped' to change port" :
174
+ "getting peers" ) ) ) );
175
+
176
+ tc->status = TC_STATUS_RESOLVE;
177
+ tc->dateTry = tr_date();
178
+ }
179
+
180
+ if( tc->status & TC_STATUS_RESOLVE )
181
+ {
182
+ int ret;
183
+ struct in_addr addr;
184
+
185
+ ret = tr_netResolvePulse( tc->resolve, &addr );
186
+ if( ret == TR_RESOLVE_WAIT )
187
+ {
188
+ return 0;
189
+ }
190
+ else
191
+ {
192
+ tr_netResolveClose( tc->resolve );
193
+ }
194
+
195
+ if( ret == TR_RESOLVE_ERROR )
196
+ {
197
+ tc->status = TC_STATUS_IDLE;
198
+ return 0;
199
+ }
200
+
201
+ if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) )
202
+ {
203
+ tc->status = TC_STATUS_IDLE;
204
+ return 0;
205
+ }
206
+
207
+ tc->socket = tr_netOpen( addr, htons( inf->trackerPort ) );
208
+ if( tc->socket < 0 )
209
+ {
210
+ tr_fdSocketClosed( tor->fdlimit, 1 );
211
+ tc->status = TC_STATUS_IDLE;
212
+ return 0;
213
+ }
214
+
215
+ tc->status = TC_STATUS_CONNECT;
216
+ }
217
+
218
+ if( tc->status & TC_STATUS_CONNECT )
219
+ {
220
+ /* We are connecting to the tracker. Try to send the query */
221
+ sendQuery( tc );
222
+ }
223
+
224
+ if( tc->status & TC_STATUS_RECV )
225
+ {
226
+ /* Try to get something */
227
+ recvAnswer( tc );
228
+ }
229
+
230
+ if( tc->status > TC_STATUS_IDLE && now > tc->dateTry + 60000 )
231
+ {
232
+ /* Give up if the request wasn't successful within 60 seconds */
233
+ tr_inf( "Tracker: timeout reached (60 s)" );
234
+
235
+ tr_netClose( tc->socket );
236
+ tr_fdSocketClosed( tor->fdlimit, 1 );
237
+
238
+ tc->status = TC_STATUS_IDLE;
239
+ tc->dateTry = tr_date();
240
+ }
241
+
242
+ return 0;
243
+ }
244
+
245
+ void tr_trackerCompleted( tr_tracker_t * tc )
246
+ {
247
+ tc->started = 0;
248
+ tc->completed = 1;
249
+ tc->stopped = 0;
250
+ }
251
+
252
+ void tr_trackerStopped( tr_tracker_t * tc )
253
+ {
254
+ tr_torrent_t * tor = tc->tor;
255
+
256
+ if( tc->status > TC_STATUS_CONNECT )
257
+ {
258
+ /* If we are already sendy a query at the moment, we need to
259
+ reconnect */
260
+ tr_netClose( tc->socket );
261
+ tr_fdSocketClosed( tor->fdlimit, 1 );
262
+ tc->status = TC_STATUS_IDLE;
263
+ }
264
+
265
+ tc->started = 0;
266
+ tc->completed = 0;
267
+ tc->stopped = 1;
268
+
269
+ /* Even if we have connected recently, reconnect right now */
270
+ if( tc->status & TC_STATUS_IDLE )
271
+ {
272
+ tc->dateTry = 0;
273
+ }
274
+ }
275
+
276
+ void tr_trackerClose( tr_tracker_t * tc )
277
+ {
278
+ tr_torrent_t * tor = tc->tor;
279
+
280
+ if( tc->status == TC_STATUS_RESOLVE )
281
+ {
282
+ tr_netResolveClose( tc->resolve );
283
+ }
284
+ else if( tc->status > TC_STATUS_RESOLVE )
285
+ {
286
+ tr_netClose( tc->socket );
287
+ tr_fdSocketClosed( tor->fdlimit, 1 );
288
+ }
289
+ free( tc->buf );
290
+ free( tc );
291
+ }
292
+
293
+ static void sendQuery( tr_tracker_t * tc )
294
+ {
295
+ tr_torrent_t * tor = tc->tor;
296
+ tr_info_t * inf = &tor->info;
297
+
298
+ char * event;
299
+ uint64_t left;
300
+ int ret;
301
+ uint64_t down;
302
+ uint64_t up;
303
+
304
+ down = tor->downloaded - tc->download;
305
+ up = tor->uploaded - tc->upload;
306
+ if( tc->started )
307
+ {
308
+ event = "&event=started";
309
+ down = up = 0;
310
+
311
+ if( 0 < tc->newPort )
312
+ {
313
+ tc->bindPort = tc->newPort;
314
+ tc->newPort = -1;
315
+ }
316
+ }
317
+ else if( tc->completed )
318
+ {
319
+ event = "&event=completed";
320
+ }
321
+ else if( tc->stopped || 0 < tc->newPort )
322
+ {
323
+ event = "&event=stopped";
324
+ }
325
+ else
326
+ {
327
+ event = "";
328
+ }
329
+
330
+ left = tr_cpLeftBytes( tor->completion );
331
+
332
+ ret = snprintf( (char *) tc->buf, tc->size,
333
+ "GET %s?"
334
+ "info_hash=%s&"
335
+ "peer_id=%s&"
336
+ "port=%d&"
337
+ "uploaded=%"PRIu64"&"
338
+ "downloaded=%"PRIu64"&"
339
+ "left=%"PRIu64"&"
340
+ "compact=1&"
341
+ "numwant=50&"
342
+ "key=%s"
343
+ "%s "
344
+ "HTTP/1.1\r\n"
345
+ "Host: %s\r\n"
346
+ "User-Agent: Transmission/%d.%d\r\n"
347
+ "Connection: close\r\n\r\n",
348
+ inf->trackerAnnounce, tor->hashString, tc->id,
349
+ tc->bindPort, up, down,
350
+ left, tor->key, event, inf->trackerAddress,
351
+ VERSION_MAJOR, VERSION_MINOR );
352
+
353
+ ret = tr_netSend( tc->socket, tc->buf, ret );
354
+ if( ret & TR_NET_CLOSE )
355
+ {
356
+ tr_inf( "Tracker: connection failed" );
357
+ tr_netClose( tc->socket );
358
+ tr_fdSocketClosed( tor->fdlimit, 1 );
359
+ tc->status = TC_STATUS_IDLE;
360
+ tc->dateTry = tr_date();
361
+ }
362
+ else if( !( ret & TR_NET_BLOCK ) )
363
+ {
364
+ // printf( "Tracker: sent %s", tc->buf );
365
+ tc->status = TC_STATUS_RECV;
366
+ tc->pos = 0;
367
+ }
368
+ }
369
+
370
+ static void recvAnswer( tr_tracker_t * tc )
371
+ {
372
+ tr_torrent_t * tor = tc->tor;
373
+ int ret;
374
+ int i;
375
+ benc_val_t beAll;
376
+ benc_val_t * bePeers, * beFoo;
377
+ uint8_t * body;
378
+ int bodylen;
379
+
380
+ if( tc->pos == tc->size )
381
+ {
382
+ tc->size *= 2;
383
+ tc->buf = realloc( tc->buf, tc->size );
384
+ }
385
+
386
+ ret = tr_netRecv( tc->socket, &tc->buf[tc->pos],
387
+ tc->size - tc->pos );
388
+
389
+ if( ret & TR_NET_BLOCK )
390
+ {
391
+ return;
392
+ }
393
+ if( !( ret & TR_NET_CLOSE ) )
394
+ {
395
+ // printf( "got %d bytes\n", ret );
396
+ tc->pos += ret;
397
+ return;
398
+ }
399
+
400
+ tr_netClose( tc->socket );
401
+ tr_fdSocketClosed( tor->fdlimit, 1 );
402
+ // printf( "connection closed, got total %d bytes\n", tc->pos );
403
+
404
+ tc->status = TC_STATUS_IDLE;
405
+ tc->dateTry = tr_date();
406
+
407
+ if( tc->pos < 12 || ( 0 != memcmp( tc->buf, "HTTP/1.0 ", 9 ) &&
408
+ 0 != memcmp( tc->buf, "HTTP/1.1 ", 9 ) ) )
409
+ {
410
+ /* We don't have a complete HTTP status line */
411
+ tr_inf( "Tracker: incomplete HTTP status line" );
412
+ tc->lastAttempt = TC_ATTEMPT_NOREACH;
413
+ return;
414
+ }
415
+
416
+ if( '2' != tc->buf[9] )
417
+ {
418
+ /* we didn't get a 2xx status code */
419
+ tr_err( "Tracker: invalid HTTP status code: %c%c%c",
420
+ tc->buf[9], tc->buf[10], tc->buf[11] );
421
+ tc->lastAttempt = TC_ATTEMPT_ERROR;
422
+ return;
423
+ }
424
+
425
+ /* find the end of the http headers */
426
+ body = tr_memmem( tc->buf, tc->pos, "\015\012\015\012", 4 );
427
+ if( NULL != body )
428
+ {
429
+ body += 4;
430
+ }
431
+ /* hooray for trackers that violate the HTTP spec */
432
+ else if( NULL != ( body = tr_memmem( tc->buf, tc->pos, "\015\015", 2 ) ) ||
433
+ NULL != ( body = tr_memmem( tc->buf, tc->pos, "\012\012", 2 ) ) )
434
+ {
435
+ body += 2;
436
+ }
437
+ else
438
+ {
439
+ tr_err( "Tracker: could not find end of HTTP headers" );
440
+ tc->lastAttempt = TC_ATTEMPT_NOREACH;
441
+ return;
442
+ }
443
+ bodylen = tc->pos - (body - tc->buf);
444
+
445
+ /* Find and load the dictionary */
446
+ for( i = 0; i < bodylen; i++ )
447
+ {
448
+ if( !tr_bencLoad( &body[i], bodylen - i, &beAll, NULL ) )
449
+ {
450
+ break;
451
+ }
452
+ }
453
+
454
+ if( i >= bodylen )
455
+ {
456
+ if( tc->stopped || 0 < tc->newPort )
457
+ {
458
+ tc->lastAttempt = TC_ATTEMPT_OK;
459
+ goto nodict;
460
+ }
461
+ tr_err( "Tracker: no valid dictionary found in answer" );
462
+ tc->lastAttempt = TC_ATTEMPT_ERROR;
463
+ return;
464
+ }
465
+
466
+ // tr_bencPrint( &beAll );
467
+
468
+ if( ( bePeers = tr_bencDictFind( &beAll, "failure reason" ) ) )
469
+ {
470
+ tr_err( "Tracker: %s", bePeers->val.s.s );
471
+ tor->error |= TR_ETRACKER;
472
+ snprintf( tor->trackerError, sizeof( tor->trackerError ),
473
+ "%s", bePeers->val.s.s );
474
+ tc->lastAttempt = TC_ATTEMPT_ERROR;
475
+ goto cleanup;
476
+ }
477
+
478
+ tor->error &= ~TR_ETRACKER;
479
+ tc->lastAttempt = TC_ATTEMPT_OK;
480
+
481
+ if( !tc->interval )
482
+ {
483
+ /* Get the tracker interval, ignore it if it is not between
484
+ 10 sec and 5 mins */
485
+ if( !( beFoo = tr_bencDictFind( &beAll, "interval" ) ) ||
486
+ !( beFoo->type & TYPE_INT ) )
487
+ {
488
+ tr_err( "Tracker: no 'interval' field" );
489
+ goto cleanup;
490
+ }
491
+
492
+ tc->interval = beFoo->val.i;
493
+ tc->interval = MIN( tc->interval, 300 );
494
+ tc->interval = MAX( 10, tc->interval );
495
+
496
+ tr_inf( "Tracker: interval = %d seconds", tc->interval );
497
+ }
498
+
499
+ if( ( beFoo = tr_bencDictFind( &beAll, "complete" ) ) &&
500
+ ( beFoo->type & TYPE_INT ) )
501
+ {
502
+ tc->seeders = beFoo->val.i;
503
+ }
504
+ if( ( beFoo = tr_bencDictFind( &beAll, "incomplete" ) ) &&
505
+ ( beFoo->type & TYPE_INT ) )
506
+ {
507
+ tc->leechers = beFoo->val.i;
508
+ }
509
+ if( tc->seeders + tc->leechers >= 50 )
510
+ {
511
+ tc->hasManyPeers = 1;
512
+ }
513
+
514
+ if( !( bePeers = tr_bencDictFind( &beAll, "peers" ) ) )
515
+ {
516
+ if( tc->stopped || 0 < tc->newPort )
517
+ {
518
+ goto nodict;
519
+ }
520
+ tr_err( "Tracker: no \"peers\" field" );
521
+ goto cleanup;
522
+ }
523
+
524
+ if( bePeers->type & TYPE_LIST )
525
+ {
526
+ char * ip;
527
+ int port;
528
+
529
+ /* Original protocol */
530
+ tr_inf( "Tracker: got %d peers", bePeers->val.l.count );
531
+
532
+ for( i = 0; i < bePeers->val.l.count; i++ )
533
+ {
534
+ beFoo = tr_bencDictFind( &bePeers->val.l.vals[i], "ip" );
535
+ if( !beFoo )
536
+ continue;
537
+ ip = beFoo->val.s.s;
538
+ beFoo = tr_bencDictFind( &bePeers->val.l.vals[i], "port" );
539
+ if( !beFoo )
540
+ continue;
541
+ port = beFoo->val.i;
542
+
543
+ tr_peerAddOld( tor, ip, port );
544
+ }
545
+
546
+ if( bePeers->val.l.count >= 50 )
547
+ {
548
+ tc->hasManyPeers = 1;
549
+ }
550
+ }
551
+ else if( bePeers->type & TYPE_STR )
552
+ {
553
+ struct in_addr addr;
554
+ in_port_t port;
555
+
556
+ /* "Compact" extension */
557
+ if( bePeers->val.s.i % 6 )
558
+ {
559
+ tr_err( "Tracker: \"peers\" of size %d",
560
+ bePeers->val.s.i );
561
+ tr_lockUnlock( &tor->lock );
562
+ goto cleanup;
563
+ }
564
+
565
+ tr_inf( "Tracker: got %d peers", bePeers->val.s.i / 6 );
566
+ for( i = 0; i < bePeers->val.s.i / 6; i++ )
567
+ {
568
+ memcpy( &addr, &bePeers->val.s.s[6*i], 4 );
569
+ memcpy( &port, &bePeers->val.s.s[6*i+4], 2 );
570
+
571
+ tr_peerAddCompact( tor, addr, port );
572
+ }
573
+
574
+ if( bePeers->val.s.i / 6 >= 50 )
575
+ {
576
+ tc->hasManyPeers = 1;
577
+ }
578
+ }
579
+
580
+ nodict:
581
+ /* Success */
582
+ tc->started = 0;
583
+ tc->completed = 0;
584
+ tc->dateOk = tr_date();
585
+
586
+ if( tc->stopped )
587
+ {
588
+ tor->status = TR_STATUS_STOPPED;
589
+ tc->stopped = 0;
590
+ }
591
+ else if( 0 < tc->newPort )
592
+ {
593
+ tc->started = 1;
594
+ tc->download = tor->downloaded;
595
+ tc->upload = tor->uploaded;
596
+ }
597
+
598
+ cleanup:
599
+ tr_bencFree( &beAll );
600
+ }
601
+
602
+ int tr_trackerScrape( tr_torrent_t * tor, int * seeders, int * leechers )
603
+ {
604
+ tr_info_t * inf = &tor->info;
605
+
606
+ int s, i, ret;
607
+ uint8_t buf[1024];
608
+ benc_val_t scrape, * val1, * val2;
609
+ struct in_addr addr;
610
+ uint64_t date;
611
+ int pos, len;
612
+ tr_resolve_t * resolve;
613
+
614
+ if( !tor->scrape[0] )
615
+ {
616
+ /* scrape not supported */
617
+ return 1;
618
+ }
619
+
620
+ resolve = tr_netResolveInit( inf->trackerAddress );
621
+ for( date = tr_date();; )
622
+ {
623
+ ret = tr_netResolvePulse( resolve, &addr );
624
+ if( ret == TR_RESOLVE_OK )
625
+ {
626
+ tr_netResolveClose( resolve );
627
+ break;
628
+ }
629
+ if( ret == TR_RESOLVE_ERROR ||
630
+ ( ret == TR_RESOLVE_WAIT && tr_date() > date + 10000 ) )
631
+ {
632
+ /* fprintf( stderr, "Could not resolve %s\n", inf->trackerAddress );*/
633
+ tr_netResolveClose( resolve );
634
+ return TR_SCRAPE_RESOLVE;
635
+ }
636
+ tr_wait( 10 );
637
+ }
638
+
639
+ s = tr_netOpen( addr, htons( inf->trackerPort ) );
640
+ if( s < 0 )
641
+ {
642
+ return 1;
643
+ }
644
+
645
+ len = snprintf( (char *) buf, sizeof( buf ),
646
+ "GET %s?info_hash=%s HTTP/1.1\r\n"
647
+ "Host: %s\r\n"
648
+ "Connection: close\r\n\r\n",
649
+ tor->scrape, tor->hashString,
650
+ inf->trackerAddress );
651
+
652
+ for( date = tr_date();; )
653
+ {
654
+ ret = tr_netSend( s, buf, len );
655
+ if( ret & TR_NET_CLOSE )
656
+ {
657
+ /* fprintf( stderr, "Could not connect to tracker\n" );*/
658
+ tr_netClose( s );
659
+ return TR_SCRAPE_CONNECT;
660
+ }
661
+ else if( ret & TR_NET_BLOCK )
662
+ {
663
+ if( tr_date() > date + 10000 )
664
+ {
665
+ /* fprintf( stderr, "Could not connect to tracker\n" );*/
666
+ tr_netClose( s );
667
+ return TR_SCRAPE_CONNECT;
668
+ }
669
+ }
670
+ else
671
+ {
672
+ break;
673
+ }
674
+ tr_wait( 10 );
675
+ }
676
+
677
+ pos = 0;
678
+ for( date = tr_date();; )
679
+ {
680
+ ret = tr_netRecv( s, &buf[pos], sizeof( buf ) - pos );
681
+ if( ret & TR_NET_CLOSE )
682
+ {
683
+ break;
684
+ }
685
+ else if( ret & TR_NET_BLOCK )
686
+ {
687
+ if( tr_date() > date + 10000 )
688
+ {
689
+ /* fprintf( stderr, "Could not read from tracker\n" );*/
690
+ tr_netClose( s );
691
+ return TR_SCRAPE_READ;
692
+ }
693
+ }
694
+ else
695
+ {
696
+ pos += ret;
697
+ }
698
+ tr_wait( 10 );
699
+ }
700
+
701
+ if( pos < 1 )
702
+ {
703
+ /* fprintf( stderr, "Could not read from tracker\n" );*/
704
+ tr_netClose( s );
705
+ return TR_SCRAPE_READ;
706
+ }
707
+
708
+ for( i = 0; i < pos - 8; i++ )
709
+ {
710
+ if( !memcmp( &buf[i], "d5:files", 8 ) )
711
+ {
712
+ break;
713
+ }
714
+ }
715
+ if( i >= pos - 8 )
716
+ {
717
+ return 1;
718
+ }
719
+ if( tr_bencLoad( &buf[i], pos - i, &scrape, NULL ) )
720
+ {
721
+ return 1;
722
+ }
723
+
724
+ val1 = tr_bencDictFind( &scrape, "files" );
725
+ if( !val1 )
726
+ {
727
+ return 1;
728
+ }
729
+ val1 = &val1->val.l.vals[1];
730
+ if( !val1 )
731
+ {
732
+ return 1;
733
+ }
734
+ val2 = tr_bencDictFind( val1, "complete" );
735
+ if( !val2 )
736
+ {
737
+ return 1;
738
+ }
739
+ *seeders = val2->val.i;
740
+ val2 = tr_bencDictFind( val1, "incomplete" );
741
+ if( !val2 )
742
+ {
743
+ return 1;
744
+ }
745
+ *leechers = val2->val.i;
746
+ tr_bencFree( &scrape );
747
+
748
+ return 0;
749
+ }
750
+
751
+ int tr_trackerSeeders( tr_tracker_t * tc )
752
+ {
753
+ if( !tc )
754
+ {
755
+ return -1;
756
+ }
757
+ return tc->seeders;
758
+ }
759
+
760
+ int tr_trackerLeechers( tr_tracker_t * tc )
761
+ {
762
+ if( !tc )
763
+ {
764
+ return -1;
765
+ }
766
+ return tc->leechers;
767
+ }