source: trunk/libtransmission/peermessages.h @ 346

Last change on this file since 346 was 261, checked in by titer, 15 years ago

Updated svn:keywords

  • Property svn:keywords set to Date Rev Author Id
File size: 9.6 KB
Line 
1/******************************************************************************
2 * $Id: peermessages.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/***********************************************************************
26 * This file handles all outgoing messages
27 **********************************************************************/
28
29static uint8_t * messagesPending( tr_peer_t * peer, int * size )
30{
31    if( peer->outBlockSending || peer->outMessagesPos < 1 )
32    {
33        return NULL;
34    }
35
36    *size = MIN( peer->outMessagesPos, 1024 );
37
38    return peer->outMessages;
39}
40
41static void messagesSent( tr_peer_t * peer, int size )
42{
43    peer->outMessagesPos -= size;
44    memmove( peer->outMessages, &peer->outMessages[size],
45             peer->outMessagesPos );
46}
47
48static uint8_t * blockPending( tr_torrent_t * tor, tr_peer_t * peer,
49                               int * size )
50{
51    if( !peer->outBlockLoaded )
52    {
53        uint8_t * p;
54        tr_request_t * r;
55
56        if( peer->amChoking || peer->outRequestCount < 1 )
57        {
58            /* No piece to send */
59            return NULL;
60        }
61
62        /* We need to load the block for the next request */
63        r = &peer->outRequests[0];
64
65        /* Sanity check */
66        if( !tr_cpPieceIsComplete( tor->completion, r->index ) )
67        {
68            /* We have been asked for something we don't have, buggy client?
69               Let's just drop this request */
70            tr_inf( "Block %d/%d/%d was requested but we don't have it",
71                    r->index, r->begin, r->length );
72            (peer->outRequestCount)--;
73            memmove( &peer->outRequests[0], &peer->outRequests[1],
74                     peer->outRequestCount * sizeof( tr_request_t ) );
75            return NULL;
76        }
77       
78        p = (uint8_t *) peer->outBlock;
79
80        TR_HTONL( 9 + r->length, p );
81        p[4] = 7;
82        TR_HTONL( r->index, p + 5 );
83        TR_HTONL( r->begin, p + 9 );
84
85        tr_ioRead( tor->io, r->index, r->begin, r->length, &p[13] );
86
87        peer_dbg( "SEND piece %d/%d (%d bytes)",
88                  r->index, r->begin, r->length );
89
90        peer->outBlockSize   = 13 + r->length;
91        peer->outBlockLoaded = 1;
92
93        (peer->outRequestCount)--;
94        memmove( &peer->outRequests[0], &peer->outRequests[1],
95                 peer->outRequestCount * sizeof( tr_request_t ) );
96    }
97
98    *size = MIN( 1024, peer->outBlockSize );
99
100    return (uint8_t *) peer->outBlock;
101}
102
103static void blockSent( tr_peer_t * peer, int size )
104{
105    peer->outBlockSize -= size;
106    memmove( peer->outBlock, &peer->outBlock[size], peer->outBlockSize );
107
108    if( peer->outBlockSize > 0 )
109    {
110        /* We can't send messages until we are done sending the block */
111        peer->outBlockSending = 1;
112    }
113    else
114    {
115        /* Block fully sent */
116        peer->outBlockSending = 0;
117        peer->outBlockLoaded  = 0;
118    }
119}
120
121static uint8_t * getPointerForSize( tr_peer_t * peer, int size )
122{
123    uint8_t * p;
124
125    if( peer->outMessagesPos + size > peer->outMessagesSize )
126    {
127        peer->outMessagesSize = peer->outMessagesPos + size;
128        peer->outMessages     = realloc( peer->outMessages,
129                                         peer->outMessagesSize );
130    }
131
132    p                     = &peer->outMessages[peer->outMessagesPos];
133    peer->outMessagesPos += size;
134
135    return p;
136}
137
138/***********************************************************************
139 * sendKeepAlive
140 ***********************************************************************
141 *
142 **********************************************************************/
143static void sendKeepAlive( tr_peer_t * peer )
144{
145    uint8_t * p;
146
147    p = getPointerForSize( peer, 4 );
148
149    TR_HTONL( 0, p );
150
151    peer_dbg( "SEND keep-alive" );
152}
153
154
155/***********************************************************************
156 * sendChoke
157 ***********************************************************************
158 *
159 **********************************************************************/
160static void sendChoke( tr_peer_t * peer, int yes )
161{
162    uint8_t * p;
163
164    p = getPointerForSize( peer, 5 );
165
166    TR_HTONL( 1, p );
167    p[4] = yes ? 0 : 1;
168
169    peer->amChoking = yes;
170
171    if( !yes )
172    {
173        /* Drop older requests from the last time it was unchoked,
174           if any */
175        peer->outRequestCount = 0;
176    }
177
178    peer_dbg( "SEND %schoke", yes ? "" : "un" );
179}
180
181/***********************************************************************
182 * sendInterest
183 ***********************************************************************
184 *
185 **********************************************************************/
186static void sendInterest( tr_peer_t * peer, int yes )
187{
188    uint8_t * p;
189
190    p = getPointerForSize( peer, 5 );
191   
192    TR_HTONL( 1, p );
193    p[4] = yes ? 2 : 3;
194
195    peer->amInterested = yes;
196
197    peer_dbg( "SEND %sinterested", yes ? "" : "un" );
198}
199
200/***********************************************************************
201 * sendHave
202 ***********************************************************************
203 *
204 **********************************************************************/
205static void sendHave( tr_peer_t * peer, int piece )
206{
207    uint8_t * p;
208
209    p = getPointerForSize( peer, 9 );
210
211    TR_HTONL( 5, &p[0] );
212    p[4] = 4;
213    TR_HTONL( piece, &p[5] );
214
215    peer_dbg( "SEND have %d", piece );
216}
217
218/***********************************************************************
219 * sendBitfield
220 ***********************************************************************
221 * Builds a 'bitfield' message:
222 *  - size = 5 + X (4 bytes)
223 *  - id   = 5     (1 byte)
224 *  - bitfield     (X bytes)
225 **********************************************************************/
226static void sendBitfield( tr_torrent_t * tor, tr_peer_t * peer )
227{
228    uint8_t * p;
229    int       bitfieldSize = ( tor->info.pieceCount + 7 ) / 8;
230
231    p = getPointerForSize( peer, 5 + bitfieldSize );
232
233    TR_HTONL( 1 + bitfieldSize, p );
234    p[4] = 5;
235    memcpy( &p[5], tr_cpPieceBitfield( tor->completion ), bitfieldSize );
236
237    peer_dbg( "SEND bitfield" );
238}
239
240/***********************************************************************
241 * sendRequest
242 ***********************************************************************
243 *
244 **********************************************************************/
245static void sendRequest( tr_torrent_t * tor, tr_peer_t * peer, int block )
246{
247    tr_info_t * inf = &tor->info;
248    tr_request_t * r;
249    uint8_t * p;
250
251    /* Get the piece the block is a part of, its position in the piece
252       and its size */
253    r         = &peer->inRequests[peer->inRequestCount];
254    r->index  = block / ( inf->pieceSize / tor->blockSize );
255    r->begin  = ( block % ( inf->pieceSize / tor->blockSize ) ) *
256                    tor->blockSize;
257    r->length = tor->blockSize;
258    if( block == tor->blockCount - 1 )
259    {
260        int lastSize = inf->totalSize % tor->blockSize;
261        if( lastSize )
262        {
263            r->length = lastSize;
264        }
265    }
266    (peer->inRequestCount)++;
267
268    /* Build the "ask" message */
269    p = getPointerForSize( peer, 17 );
270
271    TR_HTONL( 13, p );
272    p[4] = 6;
273    TR_HTONL( r->index, p + 5 );
274    TR_HTONL( r->begin, p + 9 );
275    TR_HTONL( r->length, p + 13 );
276
277    tr_cpDownloaderAdd( tor->completion, block );
278
279    peer_dbg( "SEND request %d/%d (%d bytes)",
280              r->index, r->begin, r->length );
281}
282
283/***********************************************************************
284 * sendCancel
285 ***********************************************************************
286 *
287 **********************************************************************/
288static void sendCancel( tr_torrent_t * tor, int block )
289{
290    int i, j;
291    uint8_t * p;
292    tr_peer_t * peer;
293    tr_request_t * r;
294
295    for( i = 0; i < tor->peerCount; i++ )
296    {
297        peer = tor->peers[i];
298
299        for( j = 1; j < peer->inRequestCount; j++ )
300        {
301            r = &peer->inRequests[j];
302
303            if( block != tr_block( r->index, r->begin ) )
304            {
305                continue;
306            }
307
308            p = getPointerForSize( peer, 17 );
309       
310            /* Build the "cancel" message */
311            TR_HTONL( 13, p );
312            p[4] = 8;
313            TR_HTONL( r->index,  p + 5  );
314            TR_HTONL( r->begin,  p + 9  );
315            TR_HTONL( r->length, p + 13 );
316
317            peer_dbg( "SEND cancel %d/%d (%d bytes)",
318                      r->index, r->begin, r->length );
319
320            (peer->inRequestCount)--;
321            memmove( &peer->inRequests[j], &peer->inRequests[j+1],
322                     ( peer->inRequestCount - j ) * sizeof( tr_request_t ) );
323            break;
324        }
325    }
326}
Note: See TracBrowser for help on using the repository browser.