transmission 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+