source: trunk/libtransmission/peermessages.h @ 2

Last change on this file since 2 was 2, checked in by root, 16 years ago

Update 2005-11-01

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