source: trunk/libtransmission/peerext.h @ 1600

Last change on this file since 1600 was 1600, checked in by joshe, 15 years ago

Unbreak azureus peer protocol.
Add more peer debug messages.
Fix pex interval.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.4 KB
Line 
1/******************************************************************************
2 * $Id: peerext.h 1600 2007-03-28 06:28:34Z joshe $
3 *
4 * Copyright (c) 2006-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#define EXTENDED_HANDSHAKE_ID   0
26#define EXTENDED_PEX_ID         1
27
28static char *
29makeCommonPex( tr_torrent_t * tor, tr_peer_t * peer, int * len,
30               int ( *peerfunc )( tr_peertree_t *, benc_val_t * ),
31               const char * extrakey, benc_val_t * extraval )
32{
33    tr_peertree_t       * sent, added, common;
34    int                   ii;
35    tr_peer_t           * pp;
36    tr_peertree_entry_t * found;
37    benc_val_t            val, * addval, * delval, * extra;
38    char                * buf;
39
40    *len = 0;
41    sent = &peer->sentPeers;
42    peertreeInit( &added );
43    peertreeInit( &common );
44
45    /* build trees of peers added and deleted since the last pex */
46    for( ii = 0; ii < tor->peerCount; ii++ )
47    {
48        pp = tor->peers[ii];
49        if( 0 == pp->port || 0 == tr_addrcmp( &peer->addr, &pp->addr ) )
50        {
51            continue;
52        }
53        found = peertreeGet( sent, &pp->addr, pp->port );
54        if( NULL != found )
55        {
56            peertreeMove( &common, sent, found );
57        }
58        else if( NULL == peertreeAdd( &added, &pp->addr, pp->port ) )
59        {
60            peertreeMerge( sent, &common );
61            peertreeFree( &added );
62            tr_bencFree( extraval );
63            return NULL;
64        }
65    }
66
67    /* build the dictionaries */
68    tr_bencInit( &val, TYPE_DICT );
69    if( ( peertreeEmpty( &added ) && peertreeEmpty( sent ) ) ||
70        tr_bencDictAppendNofree( &val, extrakey, &extra, "added", &addval,
71                                 "dropped", &delval, NULL ) ||
72        (*peerfunc)( &added, addval ) ||
73        (*peerfunc)( sent, delval ) )
74    {
75        tr_bencFree( &val );
76        peertreeMerge( sent, &common );
77        peertreeFree( &added );
78        tr_bencFree( extraval );
79        return NULL;
80    }
81    *extra = *extraval;
82    memset( extraval, 0, sizeof( extraval ) );
83
84    /* bencode it */
85    buf = tr_bencSaveMalloc( &val, len );
86    tr_bencFree( &val );
87    if( NULL == buf )
88    {
89        peertreeMerge( sent, &common );
90        peertreeFree( &added );
91        return NULL;
92    }
93
94    peertreeSwap( sent, &common );
95    peertreeMerge( sent, &added );
96    peertreeFree( &common );
97
98    return buf;
99}
100
101static char *
102makeExtendedHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * len )
103{
104    benc_val_t val, * msgsval, * portval, * versval, * pexval;
105    char * buf, * vers;
106
107    peer_dbg( "SEND extended-handshake, %s pex",
108              ( peer->private ? "without" : "with" ) );
109
110    /* get human-readable version string */
111    vers = NULL;
112    asprintf( &vers, "%s %s", TR_NAME, VERSION_STRING );
113    if( NULL == vers )
114    {
115        return NULL;
116    }
117
118    tr_bencInit( &val, TYPE_DICT );
119
120    /* append v str and m dict to toplevel dictionary */
121    if( tr_bencDictAppendNofree( &val, "v", &versval, "m", &msgsval, NULL ) )
122    {
123        free( vers );
124        tr_bencFree( &val );
125        return NULL;
126    }
127
128    /* human readable version string */
129    tr_bencInitStr( versval, vers, 0, 0 );
130
131    /* create dict of supported extended messages */
132    tr_bencInit( msgsval, TYPE_DICT );
133    if( !peer->private )
134    {
135        /* for public torrents advertise utorrent pex message */
136        if( tr_bencDictAppendNofree( msgsval, "ut_pex", &pexval, NULL ) )
137        {
138            tr_bencFree( &val );
139            return NULL;
140        }
141        tr_bencInitInt( pexval, EXTENDED_PEX_ID );
142    }
143
144    /* our listening port */
145    if( 0 < tor->publicPort )
146    {
147        if( tr_bencDictAppendNofree( &val, "p", &portval, NULL ) )
148        {
149            tr_bencFree( &val );
150            return NULL;
151        }
152        tr_bencInitInt( portval, tor->publicPort );
153    }
154
155    /* bencode it */
156    buf = tr_bencSaveMalloc( &val, len );
157    tr_bencFree( &val );
158
159    if( NULL != buf )
160    {
161        peer->advertisedPort = tor->publicPort;
162    }
163
164    return buf;
165}
166
167static int
168peertreeToBencUT( tr_peertree_t * tree, benc_val_t * val )
169{
170    char                * buf;
171    tr_peertree_entry_t * ii;
172    int                   count;
173
174    count = peertreeCount( tree );
175    if( 0 == count )
176    {
177        tr_bencInitStr( val, NULL, 0, 1 );
178        return 0;
179    }
180
181    buf = malloc( 6 * count );
182    if( NULL == buf )
183    {
184        return 1;
185    }
186    tr_bencInitStr( val, buf, 6 * count, 0 );
187
188    for( ii = peertreeFirst( tree ); NULL != ii;
189         ii = peertreeNext( tree, ii ) )
190    {
191        assert( 0 < count );
192        count--;
193        memcpy( buf + 6 * count, ii->peer, 6 );
194    }
195    assert( 0 == count );
196
197    return 0;
198}
199
200static char *
201makeUTPex( tr_torrent_t * tor, tr_peer_t * peer, int * len )
202{
203    benc_val_t val;
204    char     * ret;
205
206    peer_dbg( "SEND extended-pex" );
207
208    assert( !peer->private );
209    tr_bencInitStr( &val, NULL, 0, 1 );
210    ret = makeCommonPex( tor, peer, len, peertreeToBencUT, "added.f", &val );
211
212    return ret;
213}
214
215static inline int
216parseExtendedHandshake( tr_peer_t * peer, uint8_t * buf, int len )
217{
218    benc_val_t val, * sub;
219    int dbgport, dbgpex;
220
221    if( tr_bencLoad( buf, len, &val, NULL ) )
222    {
223        peer_dbg( "GET  extended-handshake, invalid bencoding" );
224        return TR_ERROR;
225    }
226    if( TYPE_DICT != val.type )
227    {
228        peer_dbg( "GET  extended-handshake, not a dictionary" );
229        tr_bencFree( &val );
230        return TR_ERROR;
231    }
232
233    /* check supported messages for utorrent pex */
234    sub = tr_bencDictFind( &val, "m" );
235    dbgpex = -1;
236    if( NULL != sub && TYPE_DICT == sub->type )
237    {
238        sub = tr_bencDictFind( sub, "ut_pex" );
239        if( NULL != sub && TYPE_INT == sub->type )
240        {
241            peer->pexStatus = 0;
242            if( !peer->private && 0x0 < sub->val.i && 0xff >= sub->val.i )
243            {
244                peer->pexStatus = sub->val.i;
245                dbgpex = sub->val.i;
246            }
247        }
248    }
249
250    /* get peer's listening port */
251    sub = tr_bencDictFind( &val, "p" );
252    dbgport = -1;
253    if( NULL != sub && TYPE_INT == sub->type &&
254        0x0 < sub->val.i && 0xffff >= sub->val.i )
255    {
256        peer->port = htons( (uint16_t) sub->val.i );
257        dbgport = sub->val.i;
258    }
259
260    peer_dbg( "GET  extended-handshake, ok port=%i pex=%i", dbgport, dbgpex );
261
262    tr_bencFree( &val );
263    return TR_OK;
264}
265
266static inline int
267parseUTPex( tr_torrent_t * tor, tr_peer_t * peer, uint8_t * buf, int len )
268{
269    benc_val_t val, * sub;
270
271    if( peer->private || PEX_PEER_CUTOFF <= tor->peerCount )
272    {
273        peer_dbg( "GET  extended-pex, ignoring p=%i c=(%i<=%i)",
274                  peer->private, PEX_PEER_CUTOFF, tor->peerCount );
275        return TR_OK;
276    }
277
278    if( tr_bencLoad( buf, len, &val, NULL ) )
279    {
280        peer_dbg( "GET  extended-pex, invalid bencoding" );
281        return TR_ERROR;
282    }
283    if( TYPE_DICT != val.type )
284    {
285        tr_bencFree( &val );
286        peer_dbg( "GET  extended-pex, not a dictionary" );
287        return TR_ERROR;
288    }
289
290    sub = tr_bencDictFind( &val, "added" );
291    if( NULL != sub && TYPE_STR == sub->type && 0 == sub->val.s.i % 6 )
292    {
293        peer_dbg( "GET  extended-pex, %i peers", sub->val.s.i / 6 );
294        tr_torrentAddCompact( tor, TR_PEER_FROM_PEX,
295                              ( uint8_t * )sub->val.s.s, sub->val.s.i / 6 );
296    }
297    else
298    {
299        peer_dbg( "GET  extended-pex, no peers" );
300    }
301
302    return TR_OK;
303}
Note: See TracBrowser for help on using the repository browser.