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,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
+ }