source: trunk/libtransmission/peermessages.h @ 54

Last change on this file since 54 was 54, checked in by titer, 16 years ago

Ignore requests for blocks we don't have, fixes the "readOrWrite ..." error

File size: 9.5 KB
Line 
1/******************************************************************************
2 * Copyright (c) 2005 Eric Petit
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *****************************************************************************/
22
23/***********************************************************************
24 * This file handles all outgoing messages
25 **********************************************************************/
26
27static uint8_t * messagesPending( tr_peer_t * peer, int * size )
28{
29    if( peer->outBlockSending || peer->outMessagesPos < 1 )
30    {
31        return NULL;
32    }
33
34    *size = MIN( peer->outMessagesPos, 1024 );
35
36    return peer->outMessages;
37}
38
39static void messagesSent( tr_peer_t * peer, int size )
40{
41    peer->outMessagesPos -= size;
42    memmove( peer->outMessages, &peer->outMessages[size],
43             peer->outMessagesPos );
44}
45
46static uint8_t * blockPending( tr_torrent_t * tor, tr_peer_t * peer,
47                               int * size )
48{
49    if( !peer->outBlockLoaded )
50    {
51        uint8_t * p;
52        tr_request_t * r;
53
54        if( peer->outRequestCount < 1 )
55        {
56            /* No piece to send */
57            return NULL;
58        }
59
60        /* We need to load the block for the next request */
61        r = &peer->outRequests[0];
62
63        /* Sanity check */
64        if( !tr_cpPieceIsComplete( tor->completion, r->index ) )
65        {
66            /* We have been asked for something we don't have, buggy client?
67               Let's just drop this request */
68            tr_inf( "Block %d/%d/%d was requested but we don't have it",
69                    r->index, r->begin, r->length );
70            (peer->outRequestCount)--;
71            memmove( &peer->outRequests[0], &peer->outRequests[1],
72                     peer->outRequestCount * sizeof( tr_request_t ) );
73            return NULL;
74        }
75       
76        p = (uint8_t *) peer->outBlock;
77
78        TR_HTONL( 9 + r->length, p );
79        p[4] = 7;
80        TR_HTONL( r->index, p + 5 );
81        TR_HTONL( r->begin, p + 9 );
82
83        tr_ioRead( tor->io, r->index, r->begin, r->length, &p[13] );
84
85        peer_dbg( "SEND piece %d/%d (%d bytes)",
86                  r->index, r->begin, r->length );
87
88        peer->outBlockSize   = 13 + r->length;
89        peer->outBlockLoaded = 1;
90
91        (peer->outRequestCount)--;
92        memmove( &peer->outRequests[0], &peer->outRequests[1],
93                 peer->outRequestCount * sizeof( tr_request_t ) );
94    }
95
96    *size = MIN( 1024, peer->outBlockSize );
97
98    return (uint8_t *) peer->outBlock;
99}
100
101static void blockSent( tr_peer_t * peer, int size )
102{
103    peer->outBlockSize -= size;
104    memmove( peer->outBlock, &peer->outBlock[size], peer->outBlockSize );
105
106    if( peer->outBlockSize > 0 )
107    {
108        /* We can't send messages until we are done sending the block */
109        peer->outBlockSending = 1;
110    }
111    else
112    {
113        /* Block fully sent */
114        peer->outBlockSending = 0;
115        peer->outBlockLoaded  = 0;
116    }
117}
118
119static uint8_t * getPointerForSize( tr_peer_t * peer, int size )
120{
121    uint8_t * p;
122
123    if( peer->outMessagesPos + size > peer->outMessagesSize )
124    {
125        peer->outMessagesSize = peer->outMessagesPos + size;
126        peer->outMessages     = realloc( peer->outMessages,
127                                         peer->outMessagesSize );
128    }
129
130    p                     = &peer->outMessages[peer->outMessagesPos];
131    peer->outMessagesPos += size;
132
133    return p;
134}
135
136/***********************************************************************
137 * sendKeepAlive
138 ***********************************************************************
139 *
140 **********************************************************************/
141static void sendKeepAlive( tr_peer_t * peer )
142{
143    uint8_t * p;
144
145    p = getPointerForSize( peer, 4 );
146
147    TR_HTONL( 0, p );
148
149    peer_dbg( "SEND keep-alive" );
150}
151
152
153/***********************************************************************
154 * sendChoke
155 ***********************************************************************
156 *
157 **********************************************************************/
158static void sendChoke( tr_peer_t * peer, int yes )
159{
160    uint8_t * p;
161
162    p = getPointerForSize( peer, 5 );
163
164    TR_HTONL( 1, p );
165    p[4] = yes ? 0 : 1;
166
167    peer->amChoking = yes;
168
169    if( yes )
170    {
171        /* Drop all pending requests */
172        peer->outRequestCount = 0;
173    }
174
175    peer_dbg( "SEND %schoke", yes ? "" : "un" );
176}
177
178/***********************************************************************
179 * sendInterest
180 ***********************************************************************
181 *
182 **********************************************************************/
183static void sendInterest( tr_peer_t * peer, int yes )
184{
185    uint8_t * p;
186
187    p = getPointerForSize( peer, 5 );
188   
189    TR_HTONL( 1, p );
190    p[4] = yes ? 2 : 3;
191
192    peer->amInterested = yes;
193
194    peer_dbg( "SEND %sinterested", yes ? "" : "un" );
195}
196
197/***********************************************************************
198 * sendHave
199 ***********************************************************************
200 *
201 **********************************************************************/
202static void sendHave( tr_peer_t * peer, int piece )
203{
204    uint8_t * p;
205
206    p = getPointerForSize( peer, 9 );
207
208    TR_HTONL( 5, &p[0] );
209    p[4] = 4;
210    TR_HTONL( piece, &p[5] );
211
212    peer_dbg( "SEND have %d", piece );
213}
214
215/***********************************************************************
216 * sendBitfield
217 ***********************************************************************
218 * Builds a 'bitfield' message:
219 *  - size = 5 + X (4 bytes)
220 *  - id   = 5     (1 byte)
221 *  - bitfield     (X bytes)
222 **********************************************************************/
223static void sendBitfield( tr_torrent_t * tor, tr_peer_t * peer )
224{
225    uint8_t * p;
226    int       bitfieldSize = ( tor->info.pieceCount + 7 ) / 8;
227
228    p = getPointerForSize( peer, 5 + bitfieldSize );
229
230    TR_HTONL( 1 + bitfieldSize, p );
231    p[4] = 5;
232    memcpy( &p[5], tr_cpPieceBitfield( tor->completion ), bitfieldSize );
233
234    peer_dbg( "SEND bitfield" );
235}
236
237/***********************************************************************
238 * sendRequest
239 ***********************************************************************
240 *
241 **********************************************************************/
242static void sendRequest( tr_torrent_t * tor, tr_peer_t * peer, int block )
243{
244    tr_info_t * inf = &tor->info;
245    tr_request_t * r;
246    uint8_t * p;
247
248    /* Get the piece the block is a part of, its position in the piece
249       and its size */
250    r         = &peer->inRequests[peer->inRequestCount];
251    r->index  = block / ( inf->pieceSize / tor->blockSize );
252    r->begin  = ( block % ( inf->pieceSize / tor->blockSize ) ) *
253                    tor->blockSize;
254    r->length = tor->blockSize;
255    if( block == tor->blockCount - 1 )
256    {
257        int lastSize = inf->totalSize % tor->blockSize;
258        if( lastSize )
259        {
260            r->length = lastSize;
261        }
262    }
263    (peer->inRequestCount)++;
264
265    /* Build the "ask" message */
266    p = getPointerForSize( peer, 17 );
267
268    TR_HTONL( 13, p );
269    p[4] = 6;
270    TR_HTONL( r->index, p + 5 );
271    TR_HTONL( r->begin, p + 9 );
272    TR_HTONL( r->length, p + 13 );
273
274    tr_cpDownloaderAdd( tor->completion, block );
275
276    peer_dbg( "SEND request %d/%d (%d bytes)",
277              r->index, r->begin, r->length );
278}
279
280/***********************************************************************
281 * sendCancel
282 ***********************************************************************
283 *
284 **********************************************************************/
285static void sendCancel( tr_torrent_t * tor, int block )
286{
287    int i, j;
288    uint8_t * p;
289    tr_peer_t * peer;
290    tr_request_t * r;
291
292    for( i = 0; i < tor->peerCount; i++ )
293    {
294        peer = tor->peers[i];
295
296        for( j = 1; j < peer->inRequestCount; j++ )
297        {
298            r = &peer->inRequests[j];
299
300            if( block != tr_block( r->index, r->begin ) )
301            {
302                continue;
303            }
304
305            p = getPointerForSize( peer, 17 );
306       
307            /* Build the "cancel" message */
308            TR_HTONL( 13, p );
309            p[4] = 8;
310            TR_HTONL( r->index,  p + 5  );
311            TR_HTONL( r->begin,  p + 9  );
312            TR_HTONL( r->length, p + 13 );
313
314            peer_dbg( "SEND cancel %d/%d (%d bytes)",
315                      r->index, r->begin, r->length );
316
317            (peer->inRequestCount)--;
318            memmove( &peer->inRequests[j], &peer->inRequests[j+1],
319                     ( peer->inRequestCount - j ) * sizeof( tr_request_t ) );
320            break;
321        }
322    }
323}
Note: See TracBrowser for help on using the repository browser.