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,394 @@
1
+ /******************************************************************************
2
+ * $Id: peerutils.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
+ static void updateInterest( tr_torrent_t * tor, tr_peer_t * peer );
26
+
27
+ /***********************************************************************
28
+ * peerInit
29
+ ***********************************************************************
30
+ * Allocates a new tr_peer_t and returns a pointer to it.
31
+ **********************************************************************/
32
+ static tr_peer_t * peerInit()
33
+ {
34
+ tr_peer_t * peer;
35
+
36
+ peer = calloc( sizeof( tr_peer_t ), 1 );
37
+ peer->amChoking = 1;
38
+ peer->peerChoking = 1;
39
+ peer->date = tr_date();
40
+ peer->keepAlive = peer->date;
41
+ peer->download = tr_rcInit();
42
+
43
+ return peer;
44
+ }
45
+
46
+ /***********************************************************************
47
+ * peerAttach
48
+ ***********************************************************************
49
+ * Deallocates the tr_peer_t and returns 0 if we reached the maximum
50
+ * authorized number of peers. Otherwise, adds the tr_peer_t to the
51
+ * peers list.
52
+ **********************************************************************/
53
+ static int peerAttach( tr_torrent_t * tor, tr_peer_t * peer )
54
+ {
55
+ if( tor->peerCount >= TR_MAX_PEER_COUNT )
56
+ {
57
+ tr_peerDestroy( tor->fdlimit, peer );
58
+ return 0;
59
+ }
60
+
61
+ tor->peers[tor->peerCount++] = peer;
62
+ return 1;
63
+ }
64
+
65
+ static int peerCmp( tr_peer_t * peer1, tr_peer_t * peer2 )
66
+ {
67
+ /* Wait until we got the peers' ids */
68
+ if( peer1->status < PEER_STATUS_CONNECTED ||
69
+ peer2->status < PEER_STATUS_CONNECTED )
70
+ {
71
+ return 1;
72
+ }
73
+
74
+ return memcmp( peer1->id, peer2->id, 20 );
75
+ }
76
+
77
+ /***********************************************************************
78
+ * addWithAddr
79
+ ***********************************************************************
80
+ * Does nothing if we already have a peer matching 'addr' and 'port'.
81
+ * Otherwise adds such a new peer.
82
+ **********************************************************************/
83
+ static void addWithAddr( tr_torrent_t * tor, struct in_addr addr,
84
+ in_port_t port )
85
+ {
86
+ int i;
87
+ tr_peer_t * peer;
88
+
89
+ for( i = 0; i < tor->peerCount; i++ )
90
+ {
91
+ peer = tor->peers[i];
92
+ if( peer->addr.s_addr == addr.s_addr &&
93
+ peer->port == port )
94
+ {
95
+ /* We are already connected to this peer */
96
+ return;
97
+ }
98
+ }
99
+
100
+ peer = peerInit();
101
+ if( !peerAttach( tor, peer ) )
102
+ {
103
+ return;
104
+ }
105
+
106
+ peer->addr = addr;
107
+ peer->port = port;
108
+ peer->status = PEER_STATUS_IDLE;
109
+ }
110
+
111
+ static int checkPeer( tr_torrent_t * tor, int i )
112
+ {
113
+ tr_peer_t * peer = tor->peers[i];
114
+
115
+ if( peer->status < PEER_STATUS_CONNECTED &&
116
+ tr_date() > peer->date + 8000 )
117
+ {
118
+ /* If it has been too long, don't wait for the socket
119
+ to timeout - forget about it now */
120
+ peer_dbg( "connection timeout" );
121
+ return 1;
122
+ }
123
+
124
+ /* Drop peers who haven't even sent a keep-alive within the
125
+ last 3 minutes */
126
+ if( tr_date() > peer->date + 180000 )
127
+ {
128
+ peer_dbg( "read timeout" );
129
+ return 1;
130
+ }
131
+
132
+ /* Drop peers which are supposed to upload but actually
133
+ haven't sent anything within the last minute */
134
+ if( peer->inRequestCount && tr_date() > peer->date + 60000 )
135
+ {
136
+ peer_dbg( "bad uploader" );
137
+ return 1;
138
+ }
139
+
140
+ if( peer->status & PEER_STATUS_CONNECTED )
141
+ {
142
+ /* Send keep-alive every 2 minutes */
143
+ if( tr_date() > peer->keepAlive + 120000 )
144
+ {
145
+ sendKeepAlive( peer );
146
+ peer->keepAlive = tr_date();
147
+ }
148
+ }
149
+
150
+ /* Connect */
151
+ if( ( peer->status & PEER_STATUS_IDLE ) &&
152
+ !tr_fdSocketWillCreate( tor->fdlimit, 0 ) )
153
+ {
154
+ peer->socket = tr_netOpen( peer->addr, peer->port );
155
+ if( peer->socket < 0 )
156
+ {
157
+ peer_dbg( "connection failed" );
158
+ tr_fdSocketClosed( tor->fdlimit, 0 );
159
+ return 1;
160
+ }
161
+ peer->status = PEER_STATUS_CONNECTING;
162
+ }
163
+
164
+ /* Try to send handshake */
165
+ if( peer->status & PEER_STATUS_CONNECTING )
166
+ {
167
+ uint8_t buf[68];
168
+ tr_info_t * inf = &tor->info;
169
+ int ret;
170
+
171
+ buf[0] = 19;
172
+ memcpy( &buf[1], "BitTorrent protocol", 19 );
173
+ memset( &buf[20], 0, 8 );
174
+ memcpy( &buf[28], inf->hash, 20 );
175
+ memcpy( &buf[48], tor->id, 20 );
176
+
177
+ ret = tr_netSend( peer->socket, buf, 68 );
178
+ if( ret & TR_NET_CLOSE )
179
+ {
180
+ peer_dbg( "connection closed" );
181
+ return 1;
182
+ }
183
+ else if( !( ret & TR_NET_BLOCK ) )
184
+ {
185
+ peer_dbg( "SEND handshake" );
186
+ peer->status = PEER_STATUS_HANDSHAKE;
187
+ }
188
+ }
189
+
190
+ return 0;
191
+ }
192
+
193
+ /***********************************************************************
194
+ * isInteresting
195
+ ***********************************************************************
196
+ * Returns 1 if 'peer' has at least one piece that we haven't completed,
197
+ * or 0 otherwise.
198
+ **********************************************************************/
199
+ static int isInteresting( tr_torrent_t * tor, tr_peer_t * peer )
200
+ {
201
+ tr_info_t * inf = &tor->info;
202
+
203
+ int i;
204
+ int bitfieldSize = ( inf->pieceCount + 7 ) / 8;
205
+ uint8_t * bitfield = tr_cpPieceBitfield( tor->completion );
206
+
207
+ if( !peer->bitfield )
208
+ {
209
+ /* We don't know what this peer has */
210
+ return 0;
211
+ }
212
+
213
+ for( i = 0; i < bitfieldSize; i++ )
214
+ {
215
+ if( ( peer->bitfield[i] & ~(bitfield[i]) ) & 0xFF )
216
+ {
217
+ return 1;
218
+ }
219
+ }
220
+
221
+ return 0;
222
+ }
223
+ static void updateInterest( tr_torrent_t * tor, tr_peer_t * peer )
224
+ {
225
+ int interested = isInteresting( tor, peer );
226
+
227
+ if( interested && !peer->amInterested )
228
+ {
229
+ sendInterest( peer, 1 );
230
+ }
231
+ if( !interested && peer->amInterested )
232
+ {
233
+ sendInterest( peer, 0 );
234
+ }
235
+ }
236
+
237
+ /***********************************************************************
238
+ * chooseBlock
239
+ ***********************************************************************
240
+ * At this point, we know the peer has at least one block we have an
241
+ * interest in. If he has more than one, we choose which one we are
242
+ * going to ask first.
243
+ * Our main goal is to complete pieces, so we look the pieces which are
244
+ * missing less blocks.
245
+ **********************************************************************/
246
+ static inline int chooseBlock( tr_torrent_t * tor, tr_peer_t * peer )
247
+ {
248
+ tr_info_t * inf = &tor->info;
249
+
250
+ int i;
251
+ int missingBlocks, minMissing;
252
+ int poolSize, * pool;
253
+ int block, minDownloading;
254
+
255
+ /* Choose a piece */
256
+ pool = malloc( inf->pieceCount * sizeof( int ) );
257
+ poolSize = 0;
258
+ minMissing = tor->blockCount + 1;
259
+ for( i = 0; i < inf->pieceCount; i++ )
260
+ {
261
+ missingBlocks = tr_cpMissingBlocksForPiece( tor->completion, i );
262
+ if( missingBlocks < 1 )
263
+ {
264
+ /* We already have or are downloading all blocks */
265
+ continue;
266
+ }
267
+ if( !tr_bitfieldHas( peer->bitfield, i ) )
268
+ {
269
+ /* The peer doesn't have this piece */
270
+ continue;
271
+ }
272
+ if( peer->banfield && tr_bitfieldHas( peer->banfield, i ) )
273
+ {
274
+ /* The peer is banned for this piece */
275
+ continue;
276
+ }
277
+
278
+ /* We are interested in this piece, remember it */
279
+ if( missingBlocks < minMissing )
280
+ {
281
+ minMissing = missingBlocks;
282
+ poolSize = 0;
283
+ }
284
+ if( missingBlocks <= minMissing )
285
+ {
286
+ pool[poolSize++] = i;
287
+ }
288
+ }
289
+
290
+ if( poolSize )
291
+ {
292
+ /* All pieces in 'pool' have 'minMissing' missing blocks. Find
293
+ the rarest ones. */
294
+ uint8_t * bitfield;
295
+ int piece;
296
+ int min, foo, j;
297
+ int * pool2;
298
+ int pool2Size;
299
+
300
+ pool2 = malloc( poolSize * sizeof( int ) );
301
+ pool2Size = 0;
302
+ min = TR_MAX_PEER_COUNT + 1;
303
+ for( i = 0; i < poolSize; i++ )
304
+ {
305
+ foo = 0;
306
+ for( j = 0; j < tor->peerCount; j++ )
307
+ {
308
+ bitfield = tor->peers[j]->bitfield;
309
+ if( bitfield && tr_bitfieldHas( bitfield, pool[i] ) )
310
+ {
311
+ foo++;
312
+ }
313
+ }
314
+ if( foo < min )
315
+ {
316
+ min = foo;
317
+ pool2Size = 0;
318
+ }
319
+ if( foo <= min )
320
+ {
321
+ pool2[pool2Size++] = pool[i];
322
+ }
323
+ }
324
+ free( pool );
325
+
326
+ if( pool2Size < 1 )
327
+ {
328
+ /* Shouldn't happen */
329
+ free( pool2 );
330
+ return -1;
331
+ }
332
+
333
+ /* All pieces in pool2 have the same number of missing blocks,
334
+ and are availabme from the same number of peers. Pick a
335
+ random one */
336
+ piece = pool2[tr_rand(pool2Size)];
337
+ free( pool2 );
338
+
339
+ /* Pick a block in this piece */
340
+ block = tr_cpMissingBlockInPiece( tor->completion, piece );
341
+ goto check;
342
+ }
343
+
344
+ free( pool );
345
+
346
+ /* "End game" mode */
347
+ minDownloading = 255;
348
+ block = -1;
349
+ for( i = 0; i < inf->pieceCount; i++ )
350
+ {
351
+ int downloaders, block2;
352
+ if( !tr_bitfieldHas( peer->bitfield, i ) )
353
+ {
354
+ /* The peer doesn't have this piece */
355
+ continue;
356
+ }
357
+ if( peer->banfield && tr_bitfieldHas( peer->banfield, i ) )
358
+ {
359
+ /* The peer is banned for this piece */
360
+ continue;
361
+ }
362
+ if( tr_cpPieceIsComplete( tor->completion, i ) )
363
+ {
364
+ /* We already have it */
365
+ continue;
366
+ }
367
+ block2 = tr_cpMostMissingBlockInPiece( tor->completion, i, &downloaders );
368
+ if( block2 > -1 && downloaders < minDownloading )
369
+ {
370
+ block = block2;
371
+ minDownloading = downloaders;
372
+ }
373
+ }
374
+
375
+ check:
376
+ if( block < 0 )
377
+ {
378
+ /* Shouldn't happen */
379
+ return -1;
380
+ }
381
+
382
+ for( i = 0; i < peer->inRequestCount; i++ )
383
+ {
384
+ tr_request_t * r;
385
+ r = &peer->inRequests[i];
386
+ if( tr_block( r->index, r->begin ) == block )
387
+ {
388
+ /* We are already asking this peer for this block */
389
+ return -1;
390
+ }
391
+ }
392
+
393
+ return block;
394
+ }
@@ -0,0 +1,196 @@
1
+ /******************************************************************************
2
+ * $Id: platform.c 310 2006-06-09 19:53:35Z joshe $
3
+ *
4
+ * Copyright (c) 2005 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
+ #ifdef SYS_BEOS
26
+ #include <fs_info.h>
27
+ #include <FindDirectory.h>
28
+ #endif
29
+ #include <sys/types.h>
30
+ #include <dirent.h>
31
+
32
+ #include "transmission.h"
33
+
34
+ static void
35
+ tr_migrateResume( const char *oldDirectory, const char *newDirectory )
36
+ {
37
+ DIR * dirh;
38
+ struct dirent * dirp;
39
+ char oldFile[MAX_PATH_LENGTH];
40
+ char newFile[MAX_PATH_LENGTH];
41
+
42
+ if( ( dirh = opendir( oldDirectory ) ) )
43
+ {
44
+ while( ( dirp = readdir( dirh ) ) )
45
+ {
46
+ if( strncmp( "resume.", dirp->d_name, 7 ) )
47
+ {
48
+ continue;
49
+ }
50
+ snprintf( oldFile, MAX_PATH_LENGTH, "%s/%s",
51
+ oldDirectory, dirp->d_name );
52
+ snprintf( newFile, MAX_PATH_LENGTH, "%s/%s",
53
+ newDirectory, dirp->d_name );
54
+ rename( oldFile, newFile );
55
+ }
56
+
57
+ closedir( dirh );
58
+ }
59
+ }
60
+
61
+ char * tr_getPrefsDirectory()
62
+ {
63
+ static char prefsDirectory[MAX_PATH_LENGTH];
64
+ static int init = 0;
65
+
66
+ if( init )
67
+ {
68
+ return prefsDirectory;
69
+ }
70
+
71
+ #ifdef SYS_BEOS
72
+ find_directory( B_USER_SETTINGS_DIRECTORY, dev_for_path("/boot"),
73
+ true, prefsDirectory, MAX_PATH_LENGTH );
74
+ strcat( prefsDirectory, "/Transmission" );
75
+ #elif defined( SYS_DARWIN )
76
+ snprintf( prefsDirectory, MAX_PATH_LENGTH,
77
+ "%s/Library/Caches/Transmission", getenv( "HOME" ) );
78
+ #else
79
+ snprintf( prefsDirectory, MAX_PATH_LENGTH, "%s/.transmission",
80
+ getenv( "HOME" ) );
81
+ #endif
82
+
83
+ tr_mkdir( prefsDirectory );
84
+ init = 1;
85
+
86
+ #ifdef SYS_DARWIN
87
+ char oldDirectory[MAX_PATH_LENGTH];
88
+ snprintf( oldDirectory, MAX_PATH_LENGTH, "%s/.transmission",
89
+ getenv( "HOME" ) );
90
+ tr_migrateResume( oldDirectory, prefsDirectory );
91
+ rmdir( oldDirectory );
92
+ #endif
93
+
94
+ return prefsDirectory;
95
+ }
96
+
97
+ char * tr_getCacheDirectory()
98
+ {
99
+ static char cacheDirectory[MAX_PATH_LENGTH];
100
+ static int init = 0;
101
+
102
+ if( init )
103
+ {
104
+ return cacheDirectory;
105
+ }
106
+
107
+ #ifdef SYS_BEOS
108
+ /* XXX hey Bryan, is this fine with you? */
109
+ snprintf( cacheDirectory, MAX_PATH_LENGTH, "%s/Cache",
110
+ tr_getPrefsDirectory() );
111
+ #elif defined( SYS_DARWIN )
112
+ snprintf( cacheDirectory, MAX_PATH_LENGTH, "%s",
113
+ tr_getPrefsDirectory() );
114
+ #else
115
+ snprintf( cacheDirectory, MAX_PATH_LENGTH, "%s/cache",
116
+ tr_getPrefsDirectory() );
117
+ #endif
118
+
119
+ tr_mkdir( cacheDirectory );
120
+ init = 1;
121
+
122
+ if( strcmp( tr_getPrefsDirectory(), cacheDirectory ) )
123
+ {
124
+ tr_migrateResume( tr_getPrefsDirectory(), cacheDirectory );
125
+ }
126
+
127
+ return cacheDirectory;
128
+ }
129
+
130
+ char * tr_getTorrentsDirectory()
131
+ {
132
+ static char torrentsDirectory[MAX_PATH_LENGTH];
133
+ static int init = 0;
134
+
135
+ if( init )
136
+ {
137
+ return torrentsDirectory;
138
+ }
139
+
140
+ #ifdef SYS_BEOS
141
+ /* XXX hey Bryan, is this fine with you? */
142
+ snprintf( torrentsDirectory, MAX_PATH_LENGTH, "%s/Torrents",
143
+ tr_getPrefsDirectory() );
144
+ #elif defined( SYS_DARWIN )
145
+ snprintf( torrentsDirectory, MAX_PATH_LENGTH,
146
+ "%s/Library/Application Support/Transmission/Torrents",
147
+ getenv( "HOME" ) );
148
+ #else
149
+ snprintf( torrentsDirectory, MAX_PATH_LENGTH, "%s/torrents",
150
+ tr_getPrefsDirectory() );
151
+ #endif
152
+
153
+ tr_mkdir( torrentsDirectory );
154
+ init = 1;
155
+
156
+ return torrentsDirectory;
157
+ }
158
+
159
+ void tr_threadCreate( tr_thread_t * t, void (*func)(void *), void * arg )
160
+ {
161
+ #ifdef SYS_BEOS
162
+ *t = spawn_thread( (void *) func, "torrent-tx", B_NORMAL_PRIORITY, arg );
163
+ resume_thread( *t );
164
+ #else
165
+ pthread_create( t, NULL, (void *) func, arg );
166
+ #endif
167
+ }
168
+
169
+ void tr_threadJoin( tr_thread_t * t )
170
+ {
171
+ #ifdef SYS_BEOS
172
+ long exit;
173
+ wait_for_thread( *t, &exit );
174
+ #else
175
+ pthread_join( *t, NULL );
176
+ #endif
177
+ }
178
+
179
+ void tr_lockInit( tr_lock_t * l )
180
+ {
181
+ #ifdef SYS_BEOS
182
+ *l = create_sem( 1, "" );
183
+ #else
184
+ pthread_mutex_init( l, NULL );
185
+ #endif
186
+ }
187
+
188
+ void tr_lockClose( tr_lock_t * l )
189
+ {
190
+ #ifdef SYS_BEOS
191
+ delete_sem( *l );
192
+ #else
193
+ pthread_mutex_destroy( l );
194
+ #endif
195
+ }
196
+