source: trunk/libtransmission/peermessages.h @ 1

Last change on this file since 1 was 1, checked in by root, 15 years ago

Import from 2005-10-26

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