transmission 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +0 -0
- data/LICENSE +23 -0
- data/README +50 -0
- data/Rakefile +41 -0
- data/ext/bencode.c +335 -0
- data/ext/bencode.h +64 -0
- data/ext/choking.c +335 -0
- data/ext/choking.h +30 -0
- data/ext/clients.c +90 -0
- data/ext/clients.h +25 -0
- data/ext/completion.c +266 -0
- data/ext/completion.h +67 -0
- data/ext/extconf.rb +3 -0
- data/ext/fastresume.h +375 -0
- data/ext/fdlimit.c +297 -0
- data/ext/fdlimit.h +36 -0
- data/ext/inout.c +620 -0
- data/ext/inout.h +38 -0
- data/ext/internal.h +202 -0
- data/ext/metainfo.c +339 -0
- data/ext/metainfo.h +44 -0
- data/ext/net.c +405 -0
- data/ext/net.h +54 -0
- data/ext/peer.c +584 -0
- data/ext/peer.h +55 -0
- data/ext/peermessages.h +326 -0
- data/ext/peerparse.h +564 -0
- data/ext/peerutils.h +394 -0
- data/ext/platform.c +196 -0
- data/ext/platform.h +63 -0
- data/ext/r_transmission.c +1135 -0
- data/ext/ratecontrol.c +170 -0
- data/ext/ratecontrol.h +33 -0
- data/ext/sha1.c +235 -0
- data/ext/sha1.h +68 -0
- data/ext/tracker.c +767 -0
- data/ext/tracker.h +53 -0
- data/ext/transmission.c +776 -0
- data/ext/transmission.h +317 -0
- data/ext/utils.c +142 -0
- data/ext/utils.h +164 -0
- data/lib/transmission.rb +75 -0
- metadata +98 -0
data/ext/peerutils.h
ADDED
@@ -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
|
+
}
|
data/ext/platform.c
ADDED
@@ -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
|
+
|