source: trunk/libtransmission/peerparse.h @ 3

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

Update 2005-11-17

File size: 13.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 incoming messages
25 **********************************************************************/
26
27/***********************************************************************
28 * parseChoke
29 ***********************************************************************
30 *
31 **********************************************************************/
32static inline int parseChoke( tr_torrent_t * tor, tr_peer_t * peer,
33                              int len, int choking )
34{
35    tr_request_t * r;
36    int i;
37
38    if( len != 1 )
39    {
40        peer_dbg( "GET  %schoke, invalid", choking ? "" : "un" );
41        return 1;
42    }
43
44    peer_dbg( "GET  %schoke", choking ? "" : "un" );
45
46    peer->peerChoking = choking;
47
48    if( choking )
49    {
50        /* Discard all pending requests */
51        for( i = 0; i < peer->inRequestCount; i++ )
52        {
53            r = &peer->inRequests[i];
54            tr_cpDownloaderRem( tor->completion, tr_block(r->index,r->begin) );
55        }
56        peer->inRequestCount = 0;
57    }
58
59    return 0;
60}
61
62/***********************************************************************
63 * parseInterested
64 ***********************************************************************
65 *
66 **********************************************************************/
67static inline int parseInterested( tr_peer_t * peer, int len,
68                                   int interested )
69{
70    if( len != 1 )
71    {
72        peer_dbg( "GET  %sinterested, invalid", interested ? "" : "un" );
73        return 1;
74    }
75
76    peer_dbg( "GET  %sinterested", interested ? "" : "un" );
77
78    peer->peerInterested = interested;
79
80    return 0;
81}
82
83/***********************************************************************
84 * parseHave
85 ***********************************************************************
86 *
87 **********************************************************************/
88static inline int parseHave( tr_torrent_t * tor, tr_peer_t * peer,
89                             uint8_t * p, int len )
90{
91    uint32_t piece;
92
93    if( len != 5 )
94    {
95        peer_dbg( "GET  have, invalid" );
96        return 1;
97    }
98
99    TR_NTOHL( p, piece );
100
101    peer_dbg( "GET  have %d", piece );
102
103    if( !peer->bitfield )
104    {
105        peer->bitfield = calloc( ( tor->info.pieceCount + 7 ) / 8, 1 );
106    }
107    tr_bitfieldAdd( peer->bitfield, piece );
108    updateInterest( tor, peer );
109
110    return 0;
111}
112
113static inline int parseBitfield( tr_torrent_t * tor, tr_peer_t * peer,
114                                 uint8_t * p, int len )
115{
116    tr_info_t * inf = &tor->info;
117    int bitfieldSize;
118
119    bitfieldSize = ( inf->pieceCount + 7 ) / 8;
120   
121    if( len != 1 + bitfieldSize )
122    {
123        peer_dbg( "GET  bitfield, wrong size" );
124        return 1;
125    }
126
127    /* Make sure the spare bits are unset */
128    if( ( inf->pieceCount & 0x7 ) )
129    {
130        uint8_t lastByte;
131       
132        lastByte   = p[bitfieldSize-1];
133        lastByte <<= inf->pieceCount & 0x7;
134        lastByte  &= 0xFF;
135
136        if( lastByte )
137        {
138            peer_dbg( "GET  bitfield, spare bits set" );
139            return 1;
140        }
141    }
142
143    peer_dbg( "GET  bitfield, ok" );
144
145    if( !peer->bitfield )
146    {
147        peer->bitfield = malloc( bitfieldSize );
148    }
149    memcpy( peer->bitfield, p, bitfieldSize );
150    updateInterest( tor, peer );
151
152    return 0;
153}
154
155static inline int parseRequest( tr_peer_t * peer, uint8_t * p, int len )
156{
157    int index, begin, length;
158    tr_request_t * r;
159
160    if( len != 13 )
161    {
162        peer_dbg( "GET  request, invalid" );
163        return 1;
164    }
165
166    if( peer->amChoking )
167    {
168        /* Didn't he get it? */
169        sendChoke( peer, 1 );
170        return 0;
171    }
172   
173    TR_NTOHL( p,     index );
174    TR_NTOHL( &p[4], begin );
175    TR_NTOHL( &p[8], length );
176
177    peer_dbg( "GET  request %d/%d (%d bytes)",
178              index, begin, length );
179
180    /* TODO sanity checks (do we have the piece, etc) */
181
182    if( length > 16384 )
183    {
184        /* Sorry mate */
185        return 1;
186    }
187
188    if( peer->outRequestCount >= MAX_REQUEST_COUNT )
189    {
190        tr_err( "Too many requests" );
191        return 1;
192    }
193
194    r         = &peer->outRequests[peer->outRequestCount];
195    r->index  = index;
196    r->begin  = begin;
197    r->length = length;
198
199    (peer->outRequestCount)++;
200
201    return 0;
202}
203
204static inline int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
205                              uint8_t * p, int len )
206{
207    int index, begin, block, i, j;
208    tr_request_t * r;
209
210    TR_NTOHL( p,     index );
211    TR_NTOHL( &p[4], begin );
212
213    peer_dbg( "GET  piece %d/%d (%d bytes)",
214              index, begin, len - 9 );
215
216    if( peer->inRequestCount < 1 )
217    {
218        /* Our "cancel" was probably late */
219        peer_dbg( "not expecting a block" );
220        return 0;
221    }
222   
223    r = &peer->inRequests[0];
224    if( index != r->index || begin != r->begin )
225    {
226        int suckyClient;
227
228        /* Either our "cancel" was late, or this is a sucky
229           client that cannot deal with multiple requests */
230        suckyClient = 0;
231        for( i = 0; i < peer->inRequestCount; i++ )
232        {
233            r = &peer->inRequests[i];
234
235            if( index != r->index || begin != r->begin )
236            {
237                continue;
238            }
239
240            /* Sucky client, he dropped the previous requests */
241            peer_dbg( "block was expected later" );
242            for( j = 0; j < i; j++ )
243            {
244                r = &peer->inRequests[j];
245                tr_cpDownloaderRem( tor->completion,
246                                    tr_block(r->index,r->begin) );
247            }
248            suckyClient = 1;
249            peer->inRequestCount -= i;
250            memmove( &peer->inRequests[0], &peer->inRequests[i],
251                     peer->inRequestCount * sizeof( tr_request_t ) );
252            r = &peer->inRequests[0];
253            break;
254        }
255
256        if( !suckyClient )
257        {
258            r = &peer->inRequests[0];
259            peer_dbg( "wrong block (expecting %d/%d)",
260                      r->index, r->begin );
261            return 0;
262        }
263    }
264
265    if( len - 9 != r->length )
266    {
267        peer_dbg( "wrong size (expecting %d)", r->length );
268        return 1;
269    }
270
271    block = tr_block( r->index, r->begin );
272    if( tr_cpBlockIsComplete( tor->completion, block ) )
273    {
274        peer_dbg( "have this block already" );
275        (peer->inRequestCount)--;
276        memmove( &peer->inRequests[0], &peer->inRequests[1],
277                 peer->inRequestCount * sizeof( tr_request_t ) );
278        return 0;
279    }
280
281    tr_cpBlockAdd( tor->completion, block );
282    tr_ioWrite( tor->io, index, begin, len - 9, &p[8] );
283    tr_cpDownloaderRem( tor->completion, block );
284
285    sendCancel( tor, block );
286
287    if( tr_cpPieceIsComplete( tor->completion, index ) )
288    {
289        tr_peer_t * otherPeer;
290
291        for( i = 0; i < tor->peerCount; i++ )
292        {
293            otherPeer = tor->peers[i];
294
295            if( otherPeer->status < PEER_STATUS_CONNECTED )
296            {
297                continue;
298            }
299
300            sendHave( otherPeer, index );
301            updateInterest( tor, otherPeer );
302        }
303    }
304
305    (peer->inRequestCount)--;
306    memmove( &peer->inRequests[0], &peer->inRequests[1],
307             peer->inRequestCount * sizeof( tr_request_t ) );
308
309    return 0;
310}
311
312static inline int parseCancel( tr_peer_t * peer, uint8_t * p, int len )
313{
314    int index, begin, length;
315    int i;
316    tr_request_t * r;
317
318    if( len != 13 )
319    {
320        peer_dbg( "GET  cancel, invalid" );
321        return 1;
322    }
323
324    TR_NTOHL( p,     index );
325    TR_NTOHL( &p[4], begin );
326    TR_NTOHL( &p[8], length );
327
328    peer_dbg( "GET  cancel %d/%d (%d bytes)",
329              index, begin, length );
330
331    for( i = 0; i < peer->outRequestCount; i++ )
332    {
333        r = &peer->outRequests[i];
334        if( r->index == index && r->begin == begin &&
335            r->length == length )
336        {
337            (peer->outRequestCount)--;
338            memmove( &r[0], &r[1], sizeof( tr_request_t ) *
339                    ( peer->outRequestCount - i ) );
340            break;
341        }
342    }
343
344    return 0;
345}
346
347static inline int parsePort( tr_peer_t * peer, uint8_t * p, int len )
348{
349    in_port_t port;
350
351    if( len != 3 )
352    {
353        peer_dbg( "GET  port, invalid" );
354        return 1;
355    }
356
357    port = *( (in_port_t *) p );
358    peer_dbg( "GET  port %d", ntohs( port ) );
359
360    return 0;
361}
362
363static inline int parseMessage( tr_torrent_t * tor, tr_peer_t * peer,
364                                uint8_t * p, int len )
365{
366    char id;
367
368    /* Type of the message */
369    id = *(p++);
370
371    switch( id )
372    {
373        case 0:
374            return parseChoke( tor, peer, len, 1 );
375        case 1:
376            return parseChoke( tor, peer, len, 0 );
377        case 2:
378            return parseInterested( peer, len, 1 );
379        case 3:
380            return parseInterested( peer, len, 0 );
381        case 4:
382            return parseHave( tor, peer, p, len );
383        case 5:
384            return parseBitfield( tor, peer, p, len );
385        case 6:
386            return parseRequest( peer, p, len );
387        case 7:
388            return parsePiece( tor, peer, p, len );
389        case 8:
390            return parseCancel( peer, p, len );
391        case 9:
392            return parsePort( peer, p, len );
393    }
394
395    peer_dbg( "Unknown message '%d'", id );
396    return 1;
397}
398
399static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer,
400                            int newBytes )
401{
402    tr_info_t * inf = &tor->info;
403
404    int       i;
405    int       len;
406    uint8_t * p   = peer->buf;
407    uint8_t * end = &p[peer->pos];
408
409    while( peer->pos >= 4 )
410    {
411        if( peer->status & PEER_STATUS_HANDSHAKE )
412        {
413            char * client;
414
415            if( p[0] != 19 || memcmp( &p[1], "Bit", 3 ) )
416            {
417                /* Don't wait until we get 68 bytes, this is wrong
418                   already */
419                peer_dbg( "GET  handshake, invalid" );
420                tr_netSend( peer->socket, (uint8_t *) "Nice try...\r\n", 13 );
421                return 1;
422            }
423
424            if( peer->pos < 68 )
425            {
426                break;
427            }
428
429            if( memcmp( &p[4], "Torrent protocol", 16 ) )
430            {
431                peer_dbg( "GET  handshake, invalid" );
432                return 1;
433            }
434
435            if( memcmp( &p[28], inf->hash, 20 ) )
436            {
437                peer_dbg( "GET  handshake, wrong torrent hash" );
438                return 1;
439            }
440
441            if( !memcmp( &p[48], tor->id, 20 ) )
442            {
443                /* We are connected to ourselves... */
444                peer_dbg( "GET  handshake, that is us" );
445                return 1;
446            }
447
448            peer->status  = PEER_STATUS_CONNECTED;
449            memcpy( peer->id, &p[48], 20 );
450            p            += 68;
451            peer->pos    -= 68;
452
453            for( i = 0; i < tor->peerCount; i++ )
454            {
455                if( tor->peers[i] == peer )
456                {
457                    continue;
458                }
459                if( !peerCmp( peer, tor->peers[i] ) )
460                {
461                    peer_dbg( "GET  handshake, duplicate" );
462                    return 1;
463                }
464            }
465
466            client = tr_clientForId( (uint8_t *) peer->id );
467            peer_dbg( "GET  handshake, ok (%s)", client );
468            free( client );
469
470            sendBitfield( tor, peer );
471
472            continue;
473        }
474       
475        /* Get payload size */
476        TR_NTOHL( p, len );
477        p += 4;
478
479        if( len > 9 + tor->blockSize )
480        {
481            /* This should never happen. Drop that peer */
482            peer_dbg( "message too large (%d bytes)", len );
483            return 1;
484        }
485
486        if( !len )
487        {
488            /* keep-alive */
489            peer_dbg( "GET  keep-alive" );
490            peer->pos -= 4;
491            continue;
492        }
493
494        /* That's a piece coming */
495        if( p < end && *p == 7 )
496        {
497            /* XXX */
498            tor->downloaded[9] += newBytes;
499            peer->inTotal      += newBytes;
500            newBytes            = 0;
501        }
502
503        if( &p[len] > end )
504        {
505            /* We do not have the entire message */
506            p -= 4;
507            break;
508        }
509
510        /* Remaining data after this message */
511        peer->pos -= 4 + len;
512
513        if( parseMessage( tor, peer, p, len ) )
514        {
515            return 1;
516        }
517
518        p += len;
519    }
520
521    memmove( peer->buf, p, peer->pos );
522
523    return 0;
524}
Note: See TracBrowser for help on using the repository browser.