source: trunk/libtransmission/peerparse.h @ 2805

Last change on this file since 2805 was 2805, checked in by charles, 15 years ago

the new tracker code seems to be working, so now it's time for me to learn yet again how much better users are at noticing bugs than I am. :)

  • Property svn:keywords set to Date Rev Author Id
File size: 22.4 KB
Line 
1/******************************************************************************
2 * $Id: peerparse.h 2805 2007-08-16 20:00:06Z charles $
3 *
4 * Copyright (c) 2005-2007 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 incoming messages
27 **********************************************************************/
28
29/***********************************************************************
30 * parseChoke
31 ***********************************************************************
32 *
33 **********************************************************************/
34
35static int parseChoke( tr_torrent_t  * tor,
36                       tr_peer_t     * peer,
37                       int             len,
38                       int             choking )
39{
40    tr_request_t * r;
41    int i;
42
43    if( len != 0 )
44    {
45        peer_dbg( "GET  %schoke, invalid", choking ? "" : "un" );
46        return TR_ERROR_ASSERT;
47    }
48
49    peer_dbg( "GET  %schoke", choking ? "" : "un" );
50
51    peer->isChokingUs = choking;
52
53    if( choking )
54    {
55        /* Discard all pending requests */
56        for( i = 0; i < peer->inRequestCount; i++ )
57        {
58            r = &peer->inRequests[i];
59            tr_cpDownloaderRem( tor->completion, tr_block(r->index,r->begin) );
60
61            /* According to the spec, all requests are dropped when you
62               are choked, however some clients seem to remember those
63               the next time they unchoke you. Also, if you get quickly
64               choked and unchoked while you are sending requests, you
65               can't know when the other peer received them and how it
66               handled it.
67               This can cause us to receive blocks multiple times and
68               overdownload, so we send 'cancel' messages to try and
69               reduce that. */
70            sendCancel( peer, r->index, r->begin, r->length );
71        }
72        peer->inRequestCount = 0;
73    }
74
75    return TR_OK;
76}
77
78/***********************************************************************
79 * parseInterested
80 ***********************************************************************
81 *
82 **********************************************************************/
83static int parseInterested( tr_peer_t * peer, int len,
84                                   int interested )
85{
86    if( len != 0 )
87    {
88        peer_dbg( "GET  %sinterested, invalid", interested ? "" : "un" );
89        return TR_ERROR_ASSERT;
90    }
91
92    peer_dbg( "GET  %sinterested", interested ? "" : "un" );
93
94    peer->isInterested = interested;
95
96    return TR_OK;
97}
98
99/***********************************************************************
100 * parseHave
101 ***********************************************************************
102 *
103 **********************************************************************/
104static int parseHave( tr_torrent_t * tor, tr_peer_t * peer,
105                             uint8_t * p, int len )
106{
107    tr_info_t * inf = &tor->info;
108    uint32_t piece;
109
110    if( len != 4 )
111    {
112        peer_dbg( "GET  have, invalid" );
113        return TR_ERROR_ASSERT;
114    }
115
116    piece = tr_ntohl( p );
117    if( ( uint32_t )inf->pieceCount <= piece )
118    {
119        peer_dbg( "GET  have, invalid piece" );
120        return TR_ERROR_ASSERT;
121    }
122
123    peer_dbg( "GET  have %d", piece );
124
125    if( !peer->bitfield )
126    {
127        peer->bitfield = tr_bitfieldNew( inf->pieceCount );
128    }
129    if( !tr_bitfieldHas( peer->bitfield, piece ) )
130    {
131        peer->pieceCount++;
132        peer->progress = (float) peer->pieceCount / inf->pieceCount;
133    }
134    tr_bitfieldAdd( peer->bitfield, piece );
135    updateInterest( tor, peer );
136
137    tr_rcTransferred( tor->swarmspeed, tor->info.pieceSize );
138
139    return TR_OK;
140}
141
142static int parseBitfield( tr_torrent_t * tor, tr_peer_t * peer,
143                                 uint8_t * p, int len )
144{
145    tr_info_t * inf = &tor->info;
146    int bitfieldSize;
147    int i;
148
149    bitfieldSize = ( inf->pieceCount + 7 ) / 8;
150   
151    if( len != bitfieldSize )
152    {
153        peer_dbg( "GET  bitfield, wrong size" );
154        return TR_ERROR_ASSERT;
155    }
156
157    /* Make sure the spare bits are unset */
158    if( ( inf->pieceCount & 0x7 ) )
159    {
160        uint8_t lastByte;
161       
162        lastByte   = p[bitfieldSize-1];
163        lastByte <<= inf->pieceCount & 0x7;
164        lastByte  &= 0xFF;
165
166        if( lastByte )
167        {
168            peer_dbg( "GET  bitfield, spare bits set" );
169            return TR_ERROR_ASSERT;
170        }
171    }
172
173    peer_dbg( "GET  bitfield, ok" );
174
175    if( !peer->bitfield )
176    {
177        peer->bitfield = tr_bitfieldNew( inf->pieceCount );
178    }
179    assert( (unsigned)bitfieldSize == peer->bitfield->len );
180    memcpy( peer->bitfield->bits, p, bitfieldSize );
181
182    peer->pieceCount = 0;
183    for( i = 0; i < inf->pieceCount; i++ )
184    {
185        if( tr_bitfieldHas( peer->bitfield, i ) )
186        {
187            peer->pieceCount++;
188        }
189    }
190    peer->progress = (float) peer->pieceCount / inf->pieceCount;
191
192    updateInterest( tor, peer );
193
194    return TR_OK;
195}
196
197static int parseRequest( tr_torrent_t * tor, tr_peer_t * peer,
198                                uint8_t * p, int len )
199{
200    tr_info_t * inf = &tor->info;
201    int index, begin, length;
202    tr_request_t * r;
203
204    if( len != 12 )
205    {
206        peer_dbg( "GET  request, invalid" );
207        return TR_ERROR_ASSERT;
208    }
209
210    if( peer->isChokedByUs )
211    {
212        /* Didn't he get it? */
213        sendChoke( peer, 1 );
214        return TR_OK;
215    }
216   
217    index = tr_ntohl( p );
218    begin = tr_ntohl( &p[4] );
219    length = tr_ntohl( &p[8] );
220
221    if( inf->pieceCount <= index )
222    {
223        peer_dbg( "GET  request, invalid index" );
224        return TR_ERROR_ASSERT;
225    }
226    if( tr_torPieceCountBytes( tor, index ) < begin + length )
227    {
228        peer_dbg( "GET  request, invalid begin/length" );
229        return TR_ERROR_ASSERT;
230    }
231
232    peer_dbg( "GET  request %d/%d (%d bytes)",
233              index, begin, length );
234
235    /* TODO sanity checks (do we have the piece, etc) */
236
237    if( length > 16384 )
238    {
239        /* Sorry mate */
240        return TR_ERROR;
241    }
242
243    r = tr_new0( tr_request_t, 1 );
244    r->index = index;
245    r->begin = begin;
246    r->length = length;
247    tr_list_append( &peer->outRequests, r );
248
249    return TR_OK;
250}
251
252static void updateRequests( tr_peer_t * peer, int index, int begin )
253{
254    tr_request_t * r;
255    int i;
256
257    /* Find this block in the requests list */
258    for( i = 0; i < peer->inRequestCount; i++ )
259    {
260        r = &peer->inRequests[i];
261        if( index == r->index && begin == r->begin )
262        {
263            break;
264        }
265    }
266
267    /* Usually 'i' would be 0, but some clients don't handle multiple
268       requests and drop previous requests, some other clients don't
269       send blocks in the same order we sent the requests */
270    if( i < peer->inRequestCount )
271    {
272        peer->inRequestCount--;
273        memmove( &peer->inRequests[i], &peer->inRequests[i+1],
274                 ( peer->inRequestCount - i ) * sizeof( tr_request_t ) );
275    }
276    else
277    {
278        /* Not in the list. Probably because of a cancel that arrived
279           too late */
280        peer_dbg( "wasn't expecting this block" );
281    }
282}
283
284static int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
285                              uint8_t * p, int len )
286{
287    tr_info_t * inf = &tor->info;
288    int index, begin, block, i, ret;
289
290    if( 8 > len )
291    {
292        peer_dbg( "GET  piece, too short (8 > %i)", len );
293        return TR_ERROR_ASSERT;
294    }
295
296    index = tr_ntohl( p );
297    begin = tr_ntohl( &p[4] );
298
299    if( inf->pieceCount <= index )
300    {
301        peer_dbg( "GET  piece, invalid index" );
302        return TR_ERROR_ASSERT;
303    }
304    if( tr_torPieceCountBytes( tor, index ) < begin + len - 8 )
305    {
306        peer_dbg( "GET  piece, invalid begin/length" );
307        return TR_ERROR_ASSERT;
308    }
309
310    block = tr_block( index, begin );
311
312    peer_dbg( "GET  piece %d/%d (%d bytes)",
313              index, begin, len - 8 );
314
315    updateRequests( peer, index, begin );
316
317    /* Sanity checks */
318    if( len - 8 != tr_torBlockCountBytes( tor, block ) )
319    {
320        peer_dbg( "wrong size (expecting %d)", tr_torBlockCountBytes( tor, block ) );
321        return TR_ERROR_ASSERT;
322    }
323    if( tr_cpBlockIsComplete( tor->completion, block ) )
324    {
325        peer_dbg( "have this block already" );
326        return TR_OK;
327    }
328
329    /* Set blame/credit for this piece */
330    if( !peer->blamefield )
331    {
332        peer->blamefield = tr_bitfieldNew( inf->pieceCount );
333    }
334    tr_bitfieldAdd( peer->blamefield, index );
335
336    /* Write to disk */
337    if( ( ret = tr_ioWrite( tor->io, index, begin, len - 8, &p[8] ) ) )
338    {
339        return ret;
340    }
341    tr_cpBlockAdd( tor->completion, block );
342    tr_peerSentBlockToUs( peer, len-8 );
343    broadcastCancel( tor, index, begin, len - 8 );
344
345    if( !tr_cpPieceHasAllBlocks( tor->completion, index ) )
346    {
347        return TR_OK;
348    }
349
350    /* Piece is complete, check it */
351    if( ( ret = tr_ioHash( tor->io, index ) ) )
352    {
353        return ret;
354    }
355    if( !tr_cpPieceIsComplete( tor->completion, index ) )
356    {
357        return TR_OK;
358    }
359
360    /* Hash OK */
361    for( i = 0; i < tor->peerCount; i++ )
362    {
363        tr_peer_t * otherPeer;
364        otherPeer = tor->peers[i];
365
366        if( otherPeer->status < PEER_STATUS_CONNECTED )
367            continue;
368
369        sendHave( otherPeer, index );
370        updateInterest( tor, otherPeer );
371    }
372
373    return TR_OK;
374}
375
376static int reqCompare( const void * va, const void * vb )
377{
378    const tr_request_t * a = (const tr_request_t *) va;
379    const tr_request_t * b = (const tr_request_t *) vb;
380    if( a->index != b->index ) return a->index - b->index;
381    if( a->begin != b->begin ) return a->begin - b->begin;
382    return a->length - b->length;
383}
384
385static int parseCancel( tr_torrent_t * tor, tr_peer_t * peer,
386                               uint8_t * p, int len )
387{
388    tr_info_t * inf = &tor->info;
389    int index, begin, length;
390    tr_request_t req;
391    tr_list_t * l;
392
393    if( len != 12 )
394    {
395        peer_dbg( "GET  cancel, invalid" );
396        return TR_ERROR_ASSERT;
397    }
398
399    index = tr_ntohl( p );
400    begin = tr_ntohl( &p[4] );
401    length = tr_ntohl( &p[8] );
402
403    if( inf->pieceCount <= index )
404    {
405        peer_dbg( "GET  cancel, invalid index" );
406        return TR_ERROR_ASSERT;
407    }
408    if( tr_torPieceCountBytes( tor, index ) < begin + length )
409    {
410        peer_dbg( "GET  cancel, invalid begin/length" );
411        return TR_ERROR_ASSERT;
412    }
413
414    peer_dbg( "GET  cancel %d/%d (%d bytes)",
415              index, begin, length );
416
417    /* remove it from the outRequests list */
418    req.index = index;
419    req.begin = begin;
420    req.length = length;
421    while(( l = tr_list_find( peer->outRequests, &req, reqCompare ) )) {
422        tr_request_t * r = (tr_request_t *) l->data;
423        tr_list_remove_data( &peer->outRequests, r );
424        tr_free( r );
425    }
426
427    return TR_OK;
428}
429
430static int parsePort( tr_peer_t * peer, uint8_t * p, int len )
431{
432    tr_port_t port;
433
434    if( len != 2 )
435    {
436        peer_dbg( "GET  port, invalid" );
437        return TR_ERROR_ASSERT;
438    }
439
440    port = *( (tr_port_t *) p );
441    peer_dbg( "GET  port %d", ntohs( port ) );
442
443    return TR_OK;
444}
445
446static int
447parseMessageHeader( tr_peer_t * peer, uint8_t * buf, int buflen,
448                    int * msgid, int * msglen )
449{
450    if( 4 > buflen )
451    {
452        return TR_NET_BLOCK;
453    }
454
455    /* Get payload size */
456    *msglen = tr_ntohl( buf );
457
458    if( 4 + *msglen > buflen )
459    {
460        /* We do not have the entire message */
461        return TR_NET_BLOCK;
462    }
463
464    if( 0 == *msglen )
465    {
466        /* keep-alive */
467        peer_dbg( "GET  keep-alive" );
468        *msgid = AZ_MSG_BT_KEEP_ALIVE;
469        return 4;
470    }
471    else
472    {
473        /* Type of the message */
474        *msgid = buf[4];
475        (*msglen)--;
476        return 5;
477    }
478}
479
480static int parseMessage( tr_torrent_t * tor, tr_peer_t * peer,
481                                int id, uint8_t * p, int len )
482{
483    int extid;
484
485    switch( id )
486    {
487        case PEER_MSG_CHOKE:
488            return parseChoke( tor, peer, len, 1 );
489        case PEER_MSG_UNCHOKE:
490            return parseChoke( tor, peer, len, 0 );
491        case PEER_MSG_INTERESTED:
492            return parseInterested( peer, len, 1 );
493        case PEER_MSG_UNINTERESTED:
494            return parseInterested( peer, len, 0 );
495        case PEER_MSG_HAVE:
496            return parseHave( tor, peer, p, len );
497        case PEER_MSG_BITFIELD:
498            return parseBitfield( tor, peer, p, len );
499        case PEER_MSG_REQUEST:
500            return parseRequest( tor, peer, p, len );
501        case PEER_MSG_PIECE:
502            return parsePiece( tor, peer, p, len );
503        case PEER_MSG_CANCEL:
504            return parseCancel( tor, peer, p, len );
505        case PEER_MSG_PORT:
506            return parsePort( peer, p, len );
507        case PEER_MSG_EXTENDED:
508            if( EXTENDED_NOT_SUPPORTED == peer->extStatus )
509            {
510                break;
511            }
512            if( 0 < len )
513            {
514                extid = p[0];
515                p++;
516                len--;
517                if( EXTENDED_HANDSHAKE_ID == extid )
518                {
519                    return parseExtendedHandshake( peer, p, len );
520                }
521                else if( 0 < peer->pexStatus && extid == peer->pexStatus )
522                {
523                    return parseUTPex( tor, peer, p, len );
524                }
525                peer_dbg( "GET  unknown extended message '%hhu'", extid );
526            }
527            /* ignore the unknown extension */
528            return 0;
529        case AZ_MSG_BT_KEEP_ALIVE:
530            return TR_OK;
531        case AZ_MSG_AZ_PEER_EXCHANGE:
532            if( peer->azproto && peer->pexStatus )
533            {
534                return parseAZPex( tor, peer, p, len );
535            }
536            break;
537        case AZ_MSG_INVALID:
538            return 0;
539    }
540
541    tr_err( "GET  unknown message '%d'", id );
542    return TR_ERROR;
543}
544
545static int parseBufHeader( tr_peer_t * peer )
546{
547    static uint8_t badproto_http[] =
548"HTTP/1.0 400 Nice try...\015\012"
549"Content-type: text/plain\015\012"
550"\015\012";
551    static uint8_t badproto_tinfoil[] =
552"This is not a rootkit or other backdoor, it's a BitTorrent\015\012"
553"client. Really. Why should you be worried, can't you read this\015\012"
554"reassuring message? Now just listen to this social engi, er, I mean,\015\012"
555"completely truthful statement, and go about your business. Your box is\015\012"
556"safe and completely impregnable, the marketing hype for your OS even\015\012"
557"says so. You can believe everything you read. Now move along, nothing\015\012"
558"to see here.";
559    uint8_t * p   = peer->buf;
560
561    if( 4 > peer->pos )
562    {
563        return TR_OK;
564    }
565
566    if( 0 != memcmp( p, HANDSHAKE_NAME, 4 ) )
567    {
568        /* Don't wait until we get 68 bytes, this is wrong
569           already */
570        peer_dbg( "GET  handshake, invalid" );
571        if( 0 == memcmp( p, "GET ", 4 ) || 0 == memcmp( p, "HEAD", 4 ) )
572        {
573            tr_netSend( peer->socket, badproto_http, sizeof badproto_http - 1 );
574        }
575        tr_netSend( peer->socket, badproto_tinfoil, sizeof badproto_tinfoil - 1 );
576        return TR_ERROR;
577    }
578    if( HANDSHAKE_SIZE > peer->pos )
579    {
580        return TR_OK;
581    }
582    if( 0 != memcmp( peer->buf, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN ) )
583    {
584        peer_dbg( "GET  handshake, invalid" );
585        return TR_ERROR;
586    }
587
588    return TR_OK;
589}
590
591static const uint8_t * parseBufHash( const tr_peer_t * peer )
592{
593    if( HANDSHAKE_HASH_OFF + SHA_DIGEST_LENGTH > peer->pos )
594    {
595        return NULL;
596    }
597    else
598    {
599        return peer->buf + HANDSHAKE_HASH_OFF;
600    }
601}
602
603static int parseHandshake( tr_torrent_t * tor, tr_peer_t * peer )
604{
605    tr_info_t * inf = &tor->info;
606    int         ii, extmsgs, azproto;
607    char      * dbgsup, * dbgwant;
608
609    if( 0 != memcmp( peer->buf + HANDSHAKE_HASH_OFF, inf->hash,
610                     SHA_DIGEST_LENGTH ) )
611    {
612        peer_dbg( "GET  handshake, wrong torrent hash" );
613        return TR_ERROR;
614    }
615
616    if( 0 == memcmp( peer->buf + HANDSHAKE_PEERID_OFF, getPeerId(),
617                     TR_ID_LEN ) )
618    {
619        /* We are connected to ourselves... */
620        peer_dbg( "GET  handshake, that is us" );
621        return TR_ERROR;
622    }
623
624    memcpy( peer->id, peer->buf + HANDSHAKE_PEERID_OFF, TR_ID_LEN );
625
626    for( ii = 0; ii < tor->peerCount; ii++ )
627    {
628        if( tor->peers[ii] == peer )
629        {
630            continue;
631        }
632        if( !peerCmp( peer, tor->peers[ii] ) )
633        {
634            peer_dbg( "GET  handshake, duplicate" );
635            return TR_ERROR;
636        }
637    }
638
639    extmsgs = 0;
640    azproto = 0;
641    dbgsup  = "";
642    dbgwant = "";
643
644    if( HANDSHAKE_HAS_EXTMSGS( peer->buf + HANDSHAKE_FLAGS_OFF ) )
645    {
646        dbgsup = " extended messaging supported";
647        extmsgs = 1;
648    }
649    if( HANDSHAKE_HAS_AZPROTO( peer->buf + HANDSHAKE_FLAGS_OFF ) )
650    {
651        dbgsup = " will use azureus protocol";
652        azproto = 1;
653    }
654    if( extmsgs && azproto )
655    {
656        dbgsup = " both extended and azureus messaging supported";
657        switch( HANDSHAKE_GET_EXTPREF( peer->buf + HANDSHAKE_FLAGS_OFF ) )
658        {
659            case HANDSHAKE_EXTPREF_FORCE_EXT:
660                dbgwant = ", peer forces extended";
661                azproto = 0;
662                break;
663            case HANDSHAKE_EXTPREF_WANT_EXT:
664                dbgwant = ", peer prefers extended";
665                azproto = 0;
666                break;
667            case HANDSHAKE_EXTPREF_WANT_AZ:
668                dbgwant = ", peer prefers azureus";
669                extmsgs = 0;
670                break;
671            case HANDSHAKE_EXTPREF_FORCE_AZ:
672                dbgwant = ", peer forces azureus";
673                extmsgs = 0;
674                break;
675        }
676    }
677    assert( !extmsgs || !azproto );
678
679    if( extmsgs )
680    {
681        peer->status = PEER_STATUS_CONNECTED;
682        peer->extStatus = EXTENDED_SUPPORTED;
683    }
684    else if( azproto )
685    {
686        peer->status  = PEER_STATUS_AZ_GIVER;
687        peer->azproto = 1;
688        peer->date    = tr_date();
689    }
690    else
691    {
692        peer->status = PEER_STATUS_CONNECTED;
693    }
694    peer_dbg( "GET  handshake, ok (%s)%s%s",
695              tr_peerClient( peer ), dbgsup, dbgwant );
696
697    return TR_OK;
698}
699
700static int sendInitial( tr_torrent_t * tor, tr_peer_t * peer )
701{
702    if( PEER_STATUS_CONNECTED != peer->status )
703    {
704        return TR_OK;
705    }
706
707    if( EXTENDED_SUPPORTED == peer->extStatus )
708    {
709        if( sendExtended( tor, peer, EXTENDED_HANDSHAKE_ID ) )
710        {
711            return TR_ERROR;
712        }
713        peer->extStatus = EXTENDED_HANDSHAKE;
714    }
715
716    sendBitfield( tor, peer );
717
718    return TR_OK;
719}
720
721static int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
722{
723    int       len, ret, msgid;
724    uint8_t * buf;
725
726    buf = peer->buf;
727
728    if( peer->banned )
729    {
730        /* Don't even parse, we only stay connected */
731        peer->pos = 0;
732        return TR_OK;
733    }
734
735    while( peer->pos >= 4 )
736    {
737        if( PEER_STATUS_HANDSHAKE == peer->status )
738        {
739            ret = parseBufHeader( peer );
740            if( ret )
741            {
742                return ret;
743            }
744
745            if( HANDSHAKE_SIZE > peer->pos )
746            {
747                break;
748            }
749
750            ret = parseHandshake( tor, peer );
751            if( 0 > ret )
752            {
753                return ret;
754            }
755            buf       += HANDSHAKE_SIZE;
756            peer->pos -= HANDSHAKE_SIZE;
757
758            ret = sendInitial( tor, peer );
759            if( ret )
760            {
761                return ret;
762            }
763
764            continue;
765        }
766
767        if( PEER_STATUS_AZ_RECEIVER == peer->status )
768        {
769            ret = parseAZMessageHeader( peer, buf, peer->pos, &msgid, &len );
770            if( TR_NET_BLOCK & ret )
771            {
772                break;
773            }
774            else if( TR_NET_CLOSE & ret )
775            {
776                return TR_ERROR;
777            }
778
779            buf       += ret;
780            peer->pos -= ret;
781            assert( len <= peer->pos );
782            if( AZ_MSG_AZ_HANDSHAKE != msgid ||
783                parseAZHandshake( peer, buf, len ) )
784            {
785                return TR_ERROR;
786            }
787            buf         += len;
788            peer->pos   -= len;
789            assert( 0 <= peer->pos );
790            peer->status = PEER_STATUS_CONNECTED;
791
792            ret = sendInitial( tor, peer );
793            if( ret )
794            {
795                return ret;
796            }
797
798            continue;
799        }
800
801        if( PEER_STATUS_CONNECTED != peer->status )
802        {
803            break;
804        }
805
806        if( peer->azproto )
807        {
808            ret = parseAZMessageHeader( peer, buf, peer->pos, &msgid, &len );
809        }
810        else
811        {
812            ret = parseMessageHeader( peer, buf, peer->pos, &msgid, &len );
813        }
814        if( TR_NET_BLOCK & ret )
815        {
816            break;
817        }
818        else if( TR_NET_CLOSE & ret )
819        {
820            return TR_ERROR;
821        }
822
823#if 0
824        if( len > 8 + tor->blockSize )
825        {
826            /* This should never happen. Drop that peer */
827            /* XXX could an extended message be longer than this? */
828            peer_dbg( "message too large (%d bytes)", len );
829            return TR_ERROR;
830        }
831#endif
832
833        buf       += ret;
834        peer->pos -= ret;
835        assert( 0 <= peer->pos );
836
837        if( ( ret = parseMessage( tor, peer, msgid, buf, len ) ) )
838        {
839            return ret;
840        }
841
842        buf       += len;
843        peer->pos -= len;
844        assert( 0 <= peer->pos );
845    }
846
847    if( 0 < peer->pos )
848    {
849        memmove( peer->buf, buf, peer->pos );
850    }
851
852    return TR_OK;
853}
Note: See TracBrowser for help on using the repository browser.