source: trunk/libtransmission/peerparse.h @ 61

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

Removed now unused tables and some now unused code

File size: 13.6 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    tor->downloaded += r->length;
272
273    block = tr_block( r->index, r->begin );
274    if( tr_cpBlockIsComplete( tor->completion, block ) )
275    {
276        peer_dbg( "have this block already" );
277        (peer->inRequestCount)--;
278        memmove( &peer->inRequests[0], &peer->inRequests[1],
279                 peer->inRequestCount * sizeof( tr_request_t ) );
280        return 0;
281    }
282
283    tr_cpBlockAdd( tor->completion, block );
284    tr_ioWrite( tor->io, index, begin, len - 9, &p[8] );
285    tr_cpDownloaderRem( tor->completion, block );
286
287    sendCancel( tor, block );
288
289    if( tr_cpPieceIsComplete( tor->completion, index ) )
290    {
291        tr_peer_t * otherPeer;
292
293        for( i = 0; i < tor->peerCount; i++ )
294        {
295            otherPeer = tor->peers[i];
296
297            if( otherPeer->status < PEER_STATUS_CONNECTED )
298            {
299                continue;
300            }
301
302            sendHave( otherPeer, index );
303            updateInterest( tor, otherPeer );
304        }
305    }
306
307    (peer->inRequestCount)--;
308    memmove( &peer->inRequests[0], &peer->inRequests[1],
309             peer->inRequestCount * sizeof( tr_request_t ) );
310
311    return 0;
312}
313
314static inline int parseCancel( tr_peer_t * peer, uint8_t * p, int len )
315{
316    int index, begin, length;
317    int i;
318    tr_request_t * r;
319
320    if( len != 13 )
321    {
322        peer_dbg( "GET  cancel, invalid" );
323        return 1;
324    }
325
326    TR_NTOHL( p,     index );
327    TR_NTOHL( &p[4], begin );
328    TR_NTOHL( &p[8], length );
329
330    peer_dbg( "GET  cancel %d/%d (%d bytes)",
331              index, begin, length );
332
333    for( i = 0; i < peer->outRequestCount; i++ )
334    {
335        r = &peer->outRequests[i];
336        if( r->index == index && r->begin == begin &&
337            r->length == length )
338        {
339            (peer->outRequestCount)--;
340            memmove( &r[0], &r[1], sizeof( tr_request_t ) *
341                    ( peer->outRequestCount - i ) );
342            break;
343        }
344    }
345
346    return 0;
347}
348
349static inline int parsePort( tr_peer_t * peer, uint8_t * p, int len )
350{
351    in_port_t port;
352
353    if( len != 3 )
354    {
355        peer_dbg( "GET  port, invalid" );
356        return 1;
357    }
358
359    port = *( (in_port_t *) p );
360    peer_dbg( "GET  port %d", ntohs( port ) );
361
362    return 0;
363}
364
365static inline int parseMessage( tr_torrent_t * tor, tr_peer_t * peer,
366                                uint8_t * p, int len )
367{
368    char id;
369
370    /* Type of the message */
371    id = *(p++);
372
373    switch( id )
374    {
375        case 0:
376            return parseChoke( tor, peer, len, 1 );
377        case 1:
378            return parseChoke( tor, peer, len, 0 );
379        case 2:
380            return parseInterested( peer, len, 1 );
381        case 3:
382            return parseInterested( peer, len, 0 );
383        case 4:
384            return parseHave( tor, peer, p, len );
385        case 5:
386            return parseBitfield( tor, peer, p, len );
387        case 6:
388            return parseRequest( peer, p, len );
389        case 7:
390            return parsePiece( tor, peer, p, len );
391        case 8:
392            return parseCancel( peer, p, len );
393        case 9:
394            return parsePort( peer, p, len );
395    }
396
397    peer_dbg( "Unknown message '%d'", id );
398    return 1;
399}
400
401static inline int parseBufHeader( tr_peer_t * peer )
402{
403    uint8_t * p   = peer->buf;
404
405    if( 4 > peer->pos )
406    {
407        return 0;
408    }
409
410    if( p[0] != 19 || memcmp( &p[1], "Bit", 3 ) )
411    {
412        /* Don't wait until we get 68 bytes, this is wrong
413           already */
414        peer_dbg( "GET  handshake, invalid" );
415        tr_netSend( peer->socket, (uint8_t *) "Nice try...\r\n", 13 );
416        return 1;
417    }
418    if( peer->pos < 68 )
419    {
420        return 0;
421    }
422    if( memcmp( &p[4], "Torrent protocol", 16 ) )
423    {
424        peer_dbg( "GET  handshake, invalid" );
425        return 1;
426    }
427
428    return 0;
429}
430
431static uint8_t * parseBufHash( tr_peer_t * peer )
432{
433    if( 48 > peer->pos )
434    {
435        return NULL;
436    }
437    else
438    {
439        return peer->buf + 28;
440    }
441}
442
443static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
444{
445    tr_info_t * inf = &tor->info;
446
447    int       i;
448    int       len;
449    uint8_t * p   = peer->buf;
450    uint8_t * end = &p[peer->pos];
451
452    while( peer->pos >= 4 )
453    {
454        if( peer->status & PEER_STATUS_HANDSHAKE )
455        {
456            char * client;
457
458            if( parseBufHeader( peer ) )
459            {
460                return 1;
461            }
462
463            if( peer->pos < 68 )
464            {
465                break;
466            }
467
468            if( memcmp( &p[28], inf->hash, 20 ) )
469            {
470                peer_dbg( "GET  handshake, wrong torrent hash" );
471                return 1;
472            }
473
474            if( !memcmp( &p[48], tor->id, 20 ) )
475            {
476                /* We are connected to ourselves... */
477                peer_dbg( "GET  handshake, that is us" );
478                return 1;
479            }
480
481            peer->status  = PEER_STATUS_CONNECTED;
482            memcpy( peer->id, &p[48], 20 );
483            p            += 68;
484            peer->pos    -= 68;
485
486            for( i = 0; i < tor->peerCount; i++ )
487            {
488                if( tor->peers[i] == peer )
489                {
490                    continue;
491                }
492                if( !peerCmp( peer, tor->peers[i] ) )
493                {
494                    peer_dbg( "GET  handshake, duplicate" );
495                    return 1;
496                }
497            }
498
499            client = tr_clientForId( (uint8_t *) peer->id );
500            peer_dbg( "GET  handshake, ok (%s)", client );
501            free( client );
502
503            sendBitfield( tor, peer );
504
505            continue;
506        }
507       
508        /* Get payload size */
509        TR_NTOHL( p, len );
510        p += 4;
511
512        if( len > 9 + tor->blockSize )
513        {
514            /* This should never happen. Drop that peer */
515            peer_dbg( "message too large (%d bytes)", len );
516            return 1;
517        }
518
519        if( !len )
520        {
521            /* keep-alive */
522            peer_dbg( "GET  keep-alive" );
523            peer->pos -= 4;
524            continue;
525        }
526
527        if( &p[len] > end )
528        {
529            /* We do not have the entire message */
530            p -= 4;
531            break;
532        }
533
534        /* Remaining data after this message */
535        peer->pos -= 4 + len;
536
537        if( parseMessage( tor, peer, p, len ) )
538        {
539            return 1;
540        }
541
542        p += len;
543    }
544
545    memmove( peer->buf, p, peer->pos );
546
547    return 0;
548}
Note: See TracBrowser for help on using the repository browser.