source: trunk/libtransmission/completion.c @ 1534

Last change on this file since 1534 was 1534, checked in by joshe, 15 years ago

Do bounds checking on bitfields.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.4 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 1534 2007-03-05 23:03:38Z 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#include "transmission.h"
26
27tr_completion_t * tr_cpInit( tr_torrent_t * tor )
28{
29    tr_completion_t * cp;
30
31    cp                   = malloc( sizeof( tr_completion_t ) );
32    cp->tor              = tor;
33    cp->blockBitfield    = tr_bitfieldNew( tor->blockCount );
34    cp->blockDownloaders = malloc( tor->blockCount );
35    cp->pieceBitfield    = tr_bitfieldNew( tor->info.pieceCount );
36    cp->missingBlocks    = malloc( tor->info.pieceCount * sizeof( int ) );
37
38    tr_cpReset( cp );
39
40    return cp;
41}
42
43void tr_cpClose( tr_completion_t * cp )
44{
45    tr_bitfieldFree( cp->blockBitfield );
46    free(            cp->blockDownloaders );
47    tr_bitfieldFree( cp->pieceBitfield );
48    free(            cp->missingBlocks );
49    free(            cp );
50}
51
52void tr_cpReset( tr_completion_t * cp )
53{
54    tr_torrent_t * tor = cp->tor;
55    int i;
56
57    cp->blockCount = 0;
58    tr_bitfieldClear( cp->blockBitfield );
59    memset( cp->blockDownloaders, 0, tor->blockCount );
60    tr_bitfieldClear( cp->pieceBitfield );
61    for( i = 0; i < tor->info.pieceCount; i++ )
62    {
63        cp->missingBlocks[i] = tr_pieceCountBlocks( i );
64    }
65}
66
67float tr_cpCompletionAsFloat( tr_completion_t * cp )
68{
69    return (float) cp->blockCount / (float) cp->tor->blockCount;
70}
71
72uint64_t tr_cpLeftBytes( tr_completion_t * cp )
73{
74    tr_torrent_t * tor = cp->tor;
75    uint64_t left;
76    left = (uint64_t) ( cp->tor->blockCount - cp->blockCount ) *
77           (uint64_t) tor->blockSize;
78    if( !tr_bitfieldHas( cp->blockBitfield, cp->tor->blockCount - 1 ) &&
79        tor->info.totalSize % tor->blockSize )
80    {
81        left += tor->info.totalSize % tor->blockSize;
82        left -= tor->blockSize;
83    }
84    return left;
85}
86
87/* Pieces */
88int tr_cpPieceHasAllBlocks( tr_completion_t * cp, int piece )
89{
90    tr_torrent_t * tor = cp->tor;
91    int startBlock  = tr_pieceStartBlock( piece );
92    int endBlock    = startBlock + tr_pieceCountBlocks( piece );
93    int i;
94
95    for( i = startBlock; i < endBlock; i++ )
96    {
97        if( !tr_bitfieldHas( cp->blockBitfield, i ) )
98        {
99            return 0;
100        }
101    }   
102    return 1;
103}
104int tr_cpPieceIsComplete( tr_completion_t * cp, int piece )
105{
106    return tr_bitfieldHas( cp->pieceBitfield, piece );
107}
108
109tr_bitfield_t * tr_cpPieceBitfield( tr_completion_t * cp )
110{
111    return cp->pieceBitfield;
112}
113
114void tr_cpPieceAdd( tr_completion_t * cp, int piece )
115{
116    tr_torrent_t * tor = cp->tor;
117    int startBlock, endBlock, i;
118
119    startBlock = tr_pieceStartBlock( piece );
120    endBlock   = startBlock + tr_pieceCountBlocks( piece );
121    for( i = startBlock; i < endBlock; i++ )
122    {
123        tr_cpBlockAdd( cp, i );
124    }
125
126    tr_bitfieldAdd( cp->pieceBitfield, piece );
127}
128
129void tr_cpPieceRem( tr_completion_t * cp, int piece )
130{
131    tr_torrent_t * tor = cp->tor;
132    int startBlock, endBlock, i;
133
134    startBlock = tr_pieceStartBlock( piece );
135    endBlock   = startBlock + tr_pieceCountBlocks( piece );
136    for( i = startBlock; i < endBlock; i++ )
137    {
138        tr_cpBlockRem( cp, i );
139    }
140
141    tr_bitfieldRem( cp->pieceBitfield, piece );
142}
143
144/* Blocks */
145void tr_cpDownloaderAdd( tr_completion_t * cp, int block )
146{
147    tr_torrent_t * tor = cp->tor;
148    if( !cp->blockDownloaders[block] && !tr_cpBlockIsComplete( cp, block ) )
149    {
150        cp->missingBlocks[tr_blockPiece(block)]--;
151    }
152    (cp->blockDownloaders[block])++;
153}
154
155void tr_cpDownloaderRem( tr_completion_t * cp, int block )
156{
157    tr_torrent_t * tor = cp->tor;
158    (cp->blockDownloaders[block])--;
159    if( !cp->blockDownloaders[block] && !tr_cpBlockIsComplete( cp, block ) )
160    {
161        cp->missingBlocks[tr_blockPiece(block)]++;
162    }
163}
164
165int tr_cpBlockIsComplete( tr_completion_t * cp, int block )
166{
167    return tr_bitfieldHas( cp->blockBitfield, block );
168}
169
170void tr_cpBlockAdd( tr_completion_t * cp, int block )
171{
172    tr_torrent_t * tor = cp->tor;
173    if( !tr_cpBlockIsComplete( cp, block ) )
174    {
175        (cp->blockCount)++;
176        if( !cp->blockDownloaders[block] )
177        {
178            (cp->missingBlocks[tr_blockPiece(block)])--;
179        }
180    }
181    tr_bitfieldAdd( cp->blockBitfield, block );
182}
183
184void tr_cpBlockRem( tr_completion_t * cp, int block )
185{
186    tr_torrent_t * tor = cp->tor;
187    if( tr_cpBlockIsComplete( cp, block ) )
188    {
189        (cp->blockCount)--;
190        if( !cp->blockDownloaders[block] )
191        {
192            (cp->missingBlocks[tr_blockPiece(block)])++;
193        }
194    }
195    tr_bitfieldRem( cp->blockBitfield, block );
196}
197
198tr_bitfield_t * tr_cpBlockBitfield( tr_completion_t * cp )
199{
200    return cp->blockBitfield;
201}
202
203void tr_cpBlockBitfieldSet( tr_completion_t * cp, tr_bitfield_t * bitfield )
204{
205    tr_torrent_t * tor = cp->tor;
206    int i, j;
207    int startBlock, endBlock;
208    int pieceComplete;
209
210    for( i = 0; i < cp->tor->info.pieceCount; i++ )
211    {
212        startBlock    = tr_pieceStartBlock( i );
213        endBlock      = startBlock + tr_pieceCountBlocks( i );
214        pieceComplete = 1;
215
216        for( j = startBlock; j < endBlock; j++ )
217        {
218            if( tr_bitfieldHas( bitfield, j ) )
219            {
220                tr_cpBlockAdd( cp, j );
221            }
222            else
223            {
224                pieceComplete = 0;
225            }
226        }
227        if( pieceComplete )
228        {
229            tr_cpPieceAdd( cp, i );
230        }
231    }
232}
233
234float tr_cpPercentBlocksInPiece( tr_completion_t * cp, int piece )
235{
236    tr_torrent_t * tor = cp->tor;
237    int i;
238    int blockCount, startBlock, endBlock;
239    int complete;
240    tr_bitfield_t * bitfield;
241   
242    blockCount  = tr_pieceCountBlocks( piece );
243    startBlock  = tr_pieceStartBlock( piece );
244    endBlock    = startBlock + blockCount;
245    complete    = 0;
246   
247    bitfield = cp->blockBitfield;
248
249    for( i = startBlock; i < endBlock; i++ )
250    {
251        if( tr_bitfieldHas( bitfield, i ) )
252        {
253            complete++;
254        }
255    }   
256
257    return (float)complete / (float)blockCount;
258}
259
260int tr_cpMissingBlockInPiece( tr_completion_t * cp, int piece )
261{
262    tr_torrent_t * tor = cp->tor;
263    int start, count, end, i;
264
265    start = tr_pieceStartBlock( piece );
266    count = tr_pieceCountBlocks( piece );
267    end   = start + count;
268
269    for( i = start; i < end; i++ )
270    {
271        if( tr_cpBlockIsComplete( cp, i ) || cp->blockDownloaders[i] )
272        {
273            continue;
274        }
275        return i;
276    }
277
278    return -1;
279}
280
281int tr_cpMostMissingBlockInPiece( tr_completion_t * cp, int piece,
282                                  int * downloaders )
283{
284    tr_torrent_t * tor = cp->tor;
285    int start, count, end, i;
286    int * pool, poolSize, min, ret;
287
288    start = tr_pieceStartBlock( piece );
289    count = tr_pieceCountBlocks( piece );
290    end   = start + count;
291
292    pool     = malloc( count * sizeof( int ) );
293    poolSize = 0;
294    min      = 255;
295
296    for( i = start; i < end; i++ )
297    {
298        if( tr_cpBlockIsComplete( cp, i ) || cp->blockDownloaders[i] > min )
299        {
300            continue;
301        }
302        if( cp->blockDownloaders[i] < min )
303        {
304            min      = cp->blockDownloaders[i];
305            poolSize = 0;
306        }
307        if( cp->blockDownloaders[i] <= min )
308        {
309            pool[poolSize++] = i;
310        }
311    }
312
313    if( poolSize > 0 )
314    {
315        ret = pool[0];
316        *downloaders = min;
317    }
318    else
319    {
320        ret = -1;
321    }
322
323    free( pool );
324    return ret;
325}
326
Note: See TracBrowser for help on using the repository browser.