transmission 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,53 @@
1
+ /******************************************************************************
2
+ * $Id: tracker.h 261 2006-05-29 21:27:31Z 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
+ #ifndef TR_TRACKER_H
26
+ #define TR_TRACKER_H 1
27
+
28
+ typedef struct tr_tracker_s tr_tracker_t;
29
+
30
+ tr_tracker_t * tr_trackerInit ( tr_torrent_t * );
31
+ void tr_trackerChangePort( tr_tracker_t *, int );
32
+ int tr_trackerPulse ( tr_tracker_t * );
33
+ void tr_trackerCompleted ( tr_tracker_t * );
34
+ void tr_trackerStopped ( tr_tracker_t * );
35
+ void tr_trackerClose ( tr_tracker_t * );
36
+
37
+ /***********************************************************************
38
+ * tr_trackerSeeders
39
+ ***********************************************************************
40
+ * Looks for the seeders/leechers as returned by the tracker.
41
+ **********************************************************************/
42
+ int tr_trackerSeeders ( tr_tracker_t * );
43
+
44
+ /***********************************************************************
45
+ * tr_trackerLeechers
46
+ ***********************************************************************
47
+ * Looks for the seeders/leechers as returned by the tracker.
48
+ **********************************************************************/
49
+ int tr_trackerLeechers ( tr_tracker_t * );
50
+
51
+ int tr_trackerScrape ( tr_torrent_t *, int *, int * );
52
+
53
+ #endif
@@ -0,0 +1,776 @@
1
+ /******************************************************************************
2
+ * $Id: transmission.c 414 2006-06-20 14:29:12Z 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
+ /***********************************************************************
28
+ * Local prototypes
29
+ **********************************************************************/
30
+ static tr_torrent_t * torrentRealInit( tr_handle_t *, tr_torrent_t * tor,
31
+ int flags, int * error );
32
+ static void torrentReallyStop( tr_torrent_t * );
33
+ static void downloadLoop( void * );
34
+ static void acceptLoop( void * );
35
+ static void acceptStop( tr_handle_t * h );
36
+
37
+ /***********************************************************************
38
+ * tr_init
39
+ ***********************************************************************
40
+ * Allocates a tr_handle_t structure and initializes a few things
41
+ **********************************************************************/
42
+ tr_handle_t * tr_init()
43
+ {
44
+ tr_handle_t * h;
45
+ int i, r;
46
+
47
+ tr_netResolveThreadInit();
48
+
49
+ h = calloc( sizeof( tr_handle_t ), 1 );
50
+
51
+ /* Generate a peer id : "-TRxxyy-" + 12 random alphanumeric
52
+ characters, where xx is the major version number and yy the
53
+ minor version number (Azureus-style) */
54
+ sprintf( h->id, "-TR%02d%02d-", VERSION_MAJOR, VERSION_MINOR );
55
+ for( i = 8; i < 20; i++ )
56
+ {
57
+ r = tr_rand( 36 );
58
+ h->id[i] = ( r < 26 ) ? ( 'a' + r ) : ( '0' + r - 26 ) ;
59
+ }
60
+
61
+ /* Random key */
62
+ for( i = 0; i < 20; i++ )
63
+ {
64
+ r = tr_rand( 36 );
65
+ h->key[i] = ( r < 26 ) ? ( 'a' + r ) : ( '0' + r - 26 ) ;
66
+ }
67
+
68
+ /* Don't exit when writing on a broken socket */
69
+ signal( SIGPIPE, SIG_IGN );
70
+
71
+ /* Initialize rate and file descripts controls */
72
+ h->upload = tr_rcInit();
73
+ h->download = tr_rcInit();
74
+ h->fdlimit = tr_fdInit();
75
+ h->choking = tr_chokingInit( h );
76
+
77
+ h->bindPort = -1;
78
+ h->bindSocket = -1;
79
+
80
+ h->acceptDie = 0;
81
+ tr_lockInit( &h->acceptLock );
82
+ tr_threadCreate( &h->acceptThread, acceptLoop, h );
83
+
84
+ return h;
85
+ }
86
+
87
+ /***********************************************************************
88
+ * tr_setBindPort
89
+ ***********************************************************************
90
+ *
91
+ **********************************************************************/
92
+ void tr_setBindPort( tr_handle_t * h, int port )
93
+ {
94
+ int sock = -1;
95
+ tr_torrent_t * tor;
96
+
97
+ if( h->bindPort == port )
98
+ return;
99
+
100
+ #ifndef BEOS_NETSERVER
101
+ /* BeOS net_server seems to be unable to set incoming connections to
102
+ non-blocking. Too bad. */
103
+ if( !tr_fdSocketWillCreate( h->fdlimit, 0 ) )
104
+ {
105
+ /* XXX should handle failure here in a better way */
106
+ sock = tr_netBind( port );
107
+ }
108
+ #else
109
+ return;
110
+ #endif
111
+
112
+ tr_lockLock( &h->acceptLock );
113
+
114
+ h->bindPort = port;
115
+
116
+ for( tor = h->torrentList; tor; tor = tor->next )
117
+ {
118
+ tr_lockLock( &tor->lock );
119
+ if( NULL != tor->tracker )
120
+ {
121
+ tr_trackerChangePort( tor->tracker, port );
122
+ }
123
+ tr_lockUnlock( &tor->lock );
124
+ }
125
+
126
+ if( h->bindSocket > -1 )
127
+ {
128
+ tr_netClose( h->bindSocket );
129
+ tr_fdSocketClosed( h->fdlimit, 0 );
130
+ }
131
+
132
+ h->bindSocket = sock;
133
+
134
+ tr_lockUnlock( &h->acceptLock );
135
+ }
136
+
137
+ /***********************************************************************
138
+ * tr_setUploadLimit
139
+ ***********************************************************************
140
+ *
141
+ **********************************************************************/
142
+ void tr_setUploadLimit( tr_handle_t * h, int limit )
143
+ {
144
+ tr_rcSetLimit( h->upload, limit );
145
+ tr_chokingSetLimit( h->choking, limit );
146
+ }
147
+
148
+ /***********************************************************************
149
+ * tr_setDownloadLimit
150
+ ***********************************************************************
151
+ *
152
+ **********************************************************************/
153
+ void tr_setDownloadLimit( tr_handle_t * h, int limit )
154
+ {
155
+ tr_rcSetLimit( h->download, limit );
156
+ }
157
+
158
+ /***********************************************************************
159
+ * tr_torrentRates
160
+ ***********************************************************************
161
+ *
162
+ **********************************************************************/
163
+ void tr_torrentRates( tr_handle_t * h, float * dl, float * ul )
164
+ {
165
+ tr_torrent_t * tor;
166
+
167
+ *dl = 0.0;
168
+ *ul = 0.0;
169
+ for( tor = h->torrentList; tor; tor = tor->next )
170
+ {
171
+ tr_lockLock( &tor->lock );
172
+ if( tor->status & TR_STATUS_DOWNLOAD )
173
+ *dl += tr_rcRate( tor->download );
174
+ *ul += tr_rcRate( tor->upload );
175
+ tr_lockUnlock( &tor->lock );
176
+ }
177
+ }
178
+
179
+ tr_torrent_t * tr_torrentInit( tr_handle_t * h, const char * path,
180
+ int flags, int * error )
181
+ {
182
+ int err_code;
183
+ tr_torrent_t * tor = calloc( sizeof( tr_torrent_t ), 1 );
184
+ int saveCopy = ( TR_FSAVEPRIVATE & flags );
185
+
186
+ /* Parse torrent file */
187
+ if( (err_code = tr_metainfoParse( &tor->info, path, NULL, saveCopy )) )
188
+ {
189
+ *error = err_code;
190
+ free( tor );
191
+ return NULL;
192
+ }
193
+
194
+ return torrentRealInit( h, tor, flags, error );
195
+ }
196
+
197
+ tr_torrent_t * tr_torrentInitSaved( tr_handle_t * h, const char * hashStr,
198
+ int flags, int * error )
199
+ {
200
+ tr_torrent_t * tor = calloc( sizeof( tr_torrent_t ), 1 );
201
+
202
+ /* Parse torrent file */
203
+ if( tr_metainfoParse( &tor->info, NULL, hashStr, 0 ) )
204
+ {
205
+ *error = TR_EINVALID;
206
+ free( tor );
207
+ return NULL;
208
+ }
209
+
210
+ return torrentRealInit( h, tor, ( TR_FSAVEPRIVATE | flags ), error );
211
+ }
212
+
213
+ /***********************************************************************
214
+ * tr_torrentInit
215
+ ***********************************************************************
216
+ * Allocates a tr_torrent_t structure, then relies on tr_metainfoParse
217
+ * to fill it.
218
+ **********************************************************************/
219
+ static tr_torrent_t * torrentRealInit( tr_handle_t * h, tr_torrent_t * tor,
220
+ int flags, int * error )
221
+ {
222
+ tr_torrent_t * tor_tmp;
223
+ tr_info_t * inf;
224
+ int i;
225
+ char * s1, * s2;
226
+
227
+ inf = &tor->info;
228
+ inf->flags = flags;
229
+
230
+ /* Make sure this torrent is not already open */
231
+ for( tor_tmp = h->torrentList; tor_tmp; tor_tmp = tor_tmp->next )
232
+ {
233
+ if( !memcmp( tor->info.hash, tor_tmp->info.hash,
234
+ SHA_DIGEST_LENGTH ) )
235
+ {
236
+ *error = TR_EDUPLICATE;
237
+ free( tor );
238
+ return NULL;
239
+ }
240
+ }
241
+
242
+ tor->status = TR_STATUS_PAUSE;
243
+ tor->id = h->id;
244
+ tor->key = h->key;
245
+ tor->bindPort = &h->bindPort;
246
+ tor->finished = 0;
247
+
248
+
249
+ /* Guess scrape URL */
250
+ s1 = strchr( inf->trackerAnnounce, '/' );
251
+ while( ( s2 = strchr( s1 + 1, '/' ) ) )
252
+ {
253
+ s1 = s2;
254
+ }
255
+ s1++;
256
+ if( !strncmp( s1, "announce", 8 ) )
257
+ {
258
+ int pre = (long) s1 - (long) inf->trackerAnnounce;
259
+ int post = strlen( inf->trackerAnnounce ) - pre - 8;
260
+ memcpy( tor->scrape, inf->trackerAnnounce, pre );
261
+ sprintf( &tor->scrape[pre], "scrape" );
262
+ memcpy( &tor->scrape[pre+6], &inf->trackerAnnounce[pre+8], post );
263
+ }
264
+
265
+ /* Escaped info hash for HTTP queries */
266
+ for( i = 0; i < SHA_DIGEST_LENGTH; i++ )
267
+ {
268
+ sprintf( &tor->hashString[3*i], "%%%02x", inf->hash[i] );
269
+ }
270
+
271
+ /* Block size: usually 16 ko, or less if we have to */
272
+ tor->blockSize = MIN( inf->pieceSize, 1 << 14 );
273
+ tor->blockCount = ( inf->totalSize + tor->blockSize - 1 ) /
274
+ tor->blockSize;
275
+ tor->completion = tr_cpInit( tor );
276
+
277
+ tr_lockInit( &tor->lock );
278
+
279
+ tor->globalUpload = h->upload;
280
+ tor->globalDownload = h->download;
281
+ tor->fdlimit = h->fdlimit;
282
+ tor->upload = tr_rcInit();
283
+ tor->download = tr_rcInit();
284
+
285
+ /* We have a new torrent */
286
+ tr_lockLock( &h->acceptLock );
287
+ tor->prev = NULL;
288
+ tor->next = h->torrentList;
289
+ if( tor->next )
290
+ {
291
+ tor->next->prev = tor;
292
+ }
293
+ h->torrentList = tor;
294
+ (h->torrentCount)++;
295
+ tr_lockUnlock( &h->acceptLock );
296
+
297
+ if( 0 > h->bindPort )
298
+ {
299
+ tr_setBindPort( h, TR_DEFAULT_PORT );
300
+ }
301
+
302
+ return tor;
303
+ }
304
+
305
+ tr_info_t * tr_torrentInfo( tr_torrent_t * tor )
306
+ {
307
+ return &tor->info;
308
+ }
309
+
310
+ /***********************************************************************
311
+ * tr_torrentScrape
312
+ **********************************************************************/
313
+ int tr_torrentScrape( tr_torrent_t * tor, int * s, int * l )
314
+ {
315
+ return tr_trackerScrape( tor, s, l );
316
+ }
317
+
318
+ void tr_torrentSetFolder( tr_torrent_t * tor, const char * path )
319
+ {
320
+ tor->destination = strdup( path );
321
+ tr_ioLoadResume( tor );
322
+ }
323
+
324
+ char * tr_torrentGetFolder( tr_torrent_t * tor )
325
+ {
326
+ return tor->destination;
327
+ }
328
+
329
+ void tr_torrentStart( tr_torrent_t * tor )
330
+ {
331
+ if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
332
+ {
333
+ /* Join the thread first */
334
+ torrentReallyStop( tor );
335
+ }
336
+
337
+ tor->status = TR_STATUS_CHECK;
338
+ tor->tracker = tr_trackerInit( tor );
339
+
340
+ tor->date = tr_date();
341
+ tor->die = 0;
342
+ tr_threadCreate( &tor->thread, downloadLoop, tor );
343
+ }
344
+
345
+ void tr_torrentStop( tr_torrent_t * tor )
346
+ {
347
+ tr_lockLock( &tor->lock );
348
+ tr_trackerStopped( tor->tracker );
349
+ tr_rcReset( tor->download );
350
+ tr_rcReset( tor->upload );
351
+ tor->status = TR_STATUS_STOPPING;
352
+ tor->stopDate = tr_date();
353
+ tr_lockUnlock( &tor->lock );
354
+ }
355
+
356
+ /***********************************************************************
357
+ * torrentReallyStop
358
+ ***********************************************************************
359
+ * Joins the download thread and frees/closes everything related to it.
360
+ **********************************************************************/
361
+ static void torrentReallyStop( tr_torrent_t * tor )
362
+ {
363
+ tor->die = 1;
364
+ tr_threadJoin( &tor->thread );
365
+ tr_dbg( "Thread joined" );
366
+
367
+ tr_trackerClose( tor->tracker );
368
+ tor->tracker = NULL;
369
+
370
+ while( tor->peerCount > 0 )
371
+ {
372
+ tr_peerRem( tor, 0 );
373
+ }
374
+ }
375
+
376
+ /***********************************************************************
377
+ * tr_torrentCount
378
+ ***********************************************************************
379
+ *
380
+ **********************************************************************/
381
+ int tr_torrentCount( tr_handle_t * h )
382
+ {
383
+ return h->torrentCount;
384
+ }
385
+
386
+ void tr_torrentIterate( tr_handle_t * h, tr_callback_t func, void * d )
387
+ {
388
+ tr_torrent_t * tor;
389
+
390
+ for( tor = h->torrentList; tor; tor = tor->next )
391
+ {
392
+ func( tor, d );
393
+ }
394
+ }
395
+
396
+ int tr_getFinished( tr_torrent_t * tor )
397
+ {
398
+ if( tor->finished )
399
+ {
400
+ tor->finished = 0;
401
+ return 1;
402
+ }
403
+ return 0;
404
+ }
405
+
406
+ tr_stat_t * tr_torrentStat( tr_torrent_t * tor )
407
+ {
408
+ tr_stat_t * s;
409
+ tr_info_t * inf = &tor->info;
410
+ int i;
411
+
412
+ tor->statCur = ( tor->statCur + 1 ) % 2;
413
+ s = &tor->stats[tor->statCur];
414
+
415
+ if( ( tor->status & TR_STATUS_STOPPED ) ||
416
+ ( ( tor->status & TR_STATUS_STOPPING ) &&
417
+ tr_date() > tor->stopDate + 60000 ) )
418
+ {
419
+ torrentReallyStop( tor );
420
+ tor->status = TR_STATUS_PAUSE;
421
+ }
422
+
423
+ tr_lockLock( &tor->lock );
424
+
425
+ s->status = tor->status;
426
+ s->error = tor->error;
427
+ memcpy( s->trackerError, tor->trackerError,
428
+ sizeof( s->trackerError ) );
429
+
430
+ s->peersTotal = 0;
431
+ s->peersUploading = 0;
432
+ s->peersDownloading = 0;
433
+
434
+ for( i = 0; i < tor->peerCount; i++ )
435
+ {
436
+ if( tr_peerIsConnected( tor->peers[i] ) )
437
+ {
438
+ (s->peersTotal)++;
439
+ if( tr_peerIsUploading( tor->peers[i] ) )
440
+ {
441
+ (s->peersUploading)++;
442
+ }
443
+ if( tr_peerIsDownloading( tor->peers[i] ) )
444
+ {
445
+ (s->peersDownloading)++;
446
+ }
447
+ }
448
+ }
449
+
450
+ s->progress = tr_cpCompletionAsFloat( tor->completion );
451
+ if( tor->status & TR_STATUS_DOWNLOAD )
452
+ s->rateDownload = tr_rcRate( tor->download );
453
+ else
454
+ /* tr_rcRate() doesn't make the difference between 'piece'
455
+ messages and other messages, which causes a non-zero
456
+ download rate even tough we are not downloading. So we
457
+ force it to zero not to confuse the user. */
458
+ s->rateDownload = 0.0;
459
+ s->rateUpload = tr_rcRate( tor->upload );
460
+
461
+ s->seeders = tr_trackerSeeders(tor->tracker);
462
+ s->leechers = tr_trackerLeechers(tor->tracker);
463
+
464
+ if( s->rateDownload < 0.1 )
465
+ {
466
+ s->eta = -1;
467
+ }
468
+ else
469
+ {
470
+ s->eta = (float) ( 1.0 - s->progress ) *
471
+ (float) inf->totalSize / s->rateDownload / 1024.0;
472
+ if( s->eta > 99 * 3600 + 59 * 60 + 59 )
473
+ {
474
+ s->eta = -1;
475
+ }
476
+ }
477
+
478
+ s->downloaded = tor->downloaded;
479
+ s->uploaded = tor->uploaded;
480
+
481
+ tr_lockUnlock( &tor->lock );
482
+
483
+ return s;
484
+ }
485
+
486
+ void tr_torrentAvailability( tr_torrent_t * tor, int8_t * tab, int size )
487
+ {
488
+ int i, j, piece;
489
+
490
+ tr_lockLock( &tor->lock );
491
+ for( i = 0; i < size; i++ )
492
+ {
493
+ piece = i * tor->info.pieceCount / size;
494
+
495
+ if( tr_cpPieceIsComplete( tor->completion, piece ) )
496
+ {
497
+ tab[i] = -1;
498
+ continue;
499
+ }
500
+
501
+ tab[i] = 0;
502
+ for( j = 0; j < tor->peerCount; j++ )
503
+ {
504
+ if( tr_peerBitfield( tor->peers[j] ) &&
505
+ tr_bitfieldHas( tr_peerBitfield( tor->peers[j] ), piece ) )
506
+ {
507
+ (tab[i])++;
508
+ }
509
+ }
510
+ }
511
+ tr_lockUnlock( &tor->lock );
512
+ }
513
+
514
+ void tr_torrentRemoveSaved( tr_torrent_t * tor ) {
515
+ tr_metainfoRemoveSaved( tor->info.hashString );
516
+ }
517
+
518
+ /***********************************************************************
519
+ * tr_torrentClose
520
+ ***********************************************************************
521
+ * Frees memory allocated by tr_torrentInit.
522
+ **********************************************************************/
523
+ void tr_torrentClose( tr_handle_t * h, tr_torrent_t * tor )
524
+ {
525
+ tr_info_t * inf = &tor->info;
526
+
527
+ if( tor->status & ( TR_STATUS_STOPPING | TR_STATUS_STOPPED ) )
528
+ {
529
+ /* Join the thread first */
530
+ torrentReallyStop( tor );
531
+ }
532
+
533
+ tr_lockLock( &h->acceptLock );
534
+
535
+ h->torrentCount--;
536
+
537
+ tr_lockClose( &tor->lock );
538
+ tr_cpClose( tor->completion );
539
+
540
+ tr_rcClose( tor->upload );
541
+ tr_rcClose( tor->download );
542
+
543
+ if( tor->destination )
544
+ {
545
+ free( tor->destination );
546
+ }
547
+ free( inf->pieces );
548
+ free( inf->files );
549
+
550
+ if( tor->prev )
551
+ {
552
+ tor->prev->next = tor->next;
553
+ }
554
+ else
555
+ {
556
+ h->torrentList = tor->next;
557
+ }
558
+ if( tor->next )
559
+ {
560
+ tor->next->prev = tor->prev;
561
+ }
562
+ free( tor );
563
+
564
+ tr_lockUnlock( &h->acceptLock );
565
+ }
566
+
567
+ void tr_close( tr_handle_t * h )
568
+ {
569
+ acceptStop( h );
570
+ tr_chokingClose( h->choking );
571
+ tr_fdClose( h->fdlimit );
572
+ tr_rcClose( h->upload );
573
+ tr_rcClose( h->download );
574
+ free( h );
575
+
576
+ tr_netResolveThreadClose();
577
+ }
578
+
579
+ /***********************************************************************
580
+ * downloadLoop
581
+ **********************************************************************/
582
+ static void downloadLoop( void * _tor )
583
+ {
584
+ tr_torrent_t * tor = _tor;
585
+ uint64_t date1, date2;
586
+
587
+ tr_dbg( "Thread started" );
588
+
589
+ #ifdef SYS_BEOS
590
+ /* This is required because on BeOS, SIGINT is sent to each thread,
591
+ which kills them not nicely */
592
+ signal( SIGINT, SIG_IGN );
593
+ #endif
594
+
595
+ tr_lockLock( &tor->lock );
596
+
597
+ tr_cpReset( tor->completion );
598
+ tor->io = tr_ioInit( tor );
599
+ tor->status = tr_cpIsSeeding( tor->completion ) ?
600
+ TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
601
+
602
+ while( !tor->die )
603
+ {
604
+ date1 = tr_date();
605
+
606
+ /* Are we finished ? */
607
+ if( ( tor->status & TR_STATUS_DOWNLOAD ) &&
608
+ tr_cpIsSeeding( tor->completion ) )
609
+ {
610
+ /* Done */
611
+ tor->status = TR_STATUS_SEED;
612
+ tor->finished = 1;
613
+ tr_trackerCompleted( tor->tracker );
614
+ tr_ioSaveResume( tor->io );
615
+ sync(); /* KLUDGE: all files should be closed and
616
+ re-opened in read-only mode instead */
617
+ }
618
+
619
+ /* Receive/send messages */
620
+ tr_peerPulse( tor );
621
+
622
+ /* Try to get new peers or to send a message to the tracker */
623
+ tr_trackerPulse( tor->tracker );
624
+
625
+ if( tor->status & TR_STATUS_STOPPED )
626
+ {
627
+ break;
628
+ }
629
+
630
+ /* Wait up to 20 ms */
631
+ date2 = tr_date();
632
+ if( date2 < date1 + 20 )
633
+ {
634
+ tr_lockUnlock( &tor->lock );
635
+ tr_wait( date1 + 20 - date2 );
636
+ tr_lockLock( &tor->lock );
637
+ }
638
+ }
639
+
640
+ tr_lockUnlock( &tor->lock );
641
+
642
+ tr_ioClose( tor->io );
643
+
644
+ tor->status = TR_STATUS_STOPPED;
645
+
646
+ tr_dbg( "Thread exited" );
647
+ }
648
+
649
+ /***********************************************************************
650
+ * acceptLoop
651
+ **********************************************************************/
652
+ static void acceptLoop( void * _h )
653
+ {
654
+ tr_handle_t * h = _h;
655
+ uint64_t date1, date2, lastchoke = 0;
656
+ int ii;
657
+ uint8_t * hash;
658
+ tr_torrent_t * tor;
659
+
660
+ tr_dbg( "Accept thread started" );
661
+
662
+ #ifdef SYS_BEOS
663
+ /* This is required because on BeOS, SIGINT is sent to each thread,
664
+ which kills them not nicely */
665
+ signal( SIGINT, SIG_IGN );
666
+ #endif
667
+
668
+ tr_lockLock( &h->acceptLock );
669
+
670
+ while( !h->acceptDie )
671
+ {
672
+ date1 = tr_date();
673
+
674
+ /* Check for incoming connections */
675
+ if( h->bindSocket > -1 &&
676
+ h->acceptPeerCount < TR_MAX_PEER_COUNT &&
677
+ !tr_fdSocketWillCreate( h->fdlimit, 0 ) )
678
+ {
679
+ int s;
680
+ struct in_addr addr;
681
+ in_port_t port;
682
+ s = tr_netAccept( h->bindSocket, &addr, &port );
683
+ if( s > -1 )
684
+ {
685
+ h->acceptPeers[h->acceptPeerCount++] = tr_peerInit( addr, port, s );
686
+ }
687
+ else
688
+ {
689
+ tr_fdSocketClosed( h->fdlimit, 0 );
690
+ }
691
+ }
692
+
693
+ for( ii = 0; ii < h->acceptPeerCount; )
694
+ {
695
+ if( tr_peerRead( NULL, h->acceptPeers[ii] ) )
696
+ {
697
+ tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
698
+ goto removePeer;
699
+ }
700
+ if( NULL != ( hash = tr_peerHash( h->acceptPeers[ii] ) ) )
701
+ {
702
+ for( tor = h->torrentList; tor; tor = tor->next )
703
+ {
704
+ tr_lockLock( &tor->lock );
705
+ if( 0 == memcmp( tor->info.hash, hash,
706
+ SHA_DIGEST_LENGTH ) )
707
+ {
708
+ tr_peerAttach( tor, h->acceptPeers[ii] );
709
+ tr_lockUnlock( &tor->lock );
710
+ goto removePeer;
711
+ }
712
+ tr_lockUnlock( &tor->lock );
713
+ }
714
+ tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
715
+ goto removePeer;
716
+ }
717
+ if( date1 > tr_peerDate( h->acceptPeers[ii] ) + 10000 )
718
+ {
719
+ /* Give them 10 seconds to send the handshake */
720
+ tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
721
+ goto removePeer;
722
+ }
723
+ ii++;
724
+ continue;
725
+ removePeer:
726
+ h->acceptPeerCount--;
727
+ memmove( &h->acceptPeers[ii], &h->acceptPeers[ii+1],
728
+ ( h->acceptPeerCount - ii ) * sizeof( tr_peer_t * ) );
729
+ }
730
+
731
+ if( date1 > lastchoke + 2000 )
732
+ {
733
+ tr_chokingPulse( h->choking );
734
+ lastchoke = date1;
735
+ }
736
+
737
+ /* Wait up to 20 ms */
738
+ date2 = tr_date();
739
+ if( date2 < date1 + 20 )
740
+ {
741
+ tr_lockUnlock( &h->acceptLock );
742
+ tr_wait( date1 + 20 - date2 );
743
+ tr_lockLock( &h->acceptLock );
744
+ }
745
+ }
746
+
747
+ tr_lockUnlock( &h->acceptLock );
748
+
749
+ tr_dbg( "Accept thread exited" );
750
+ }
751
+
752
+ /***********************************************************************
753
+ * acceptStop
754
+ ***********************************************************************
755
+ * Joins the accept thread and frees/closes everything related to it.
756
+ **********************************************************************/
757
+ static void acceptStop( tr_handle_t * h )
758
+ {
759
+ int ii;
760
+
761
+ h->acceptDie = 1;
762
+ tr_threadJoin( &h->acceptThread );
763
+ tr_lockClose( &h->acceptLock );
764
+ tr_dbg( "Accept thread joined" );
765
+
766
+ for( ii = 0; ii < h->acceptPeerCount; ii++ )
767
+ {
768
+ tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
769
+ }
770
+
771
+ if( h->bindSocket > -1 )
772
+ {
773
+ tr_netClose( h->bindSocket );
774
+ tr_fdSocketClosed( h->fdlimit, 0 );
775
+ }
776
+ }