source: trunk/libtransmission/peerext.h @ 1594

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

Don't save or load cached peers for private torrents.

  • Property svn:keywords set to Date Rev Author Id
File size: 7.8 KB
Line 
1/******************************************************************************
2 * $Id: peerext.h 1594 2007-03-26 19:19:33Z 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    /* get human-readable version string */
108    vers = NULL;
109    asprintf( &vers, "%s %s", TR_NAME, VERSION_STRING );
110    if( NULL == vers )
111    {
112        return NULL;
113    }
114
115    tr_bencInit( &val, TYPE_DICT );
116
117    /* append v str and m dict to toplevel dictionary */
118    if( tr_bencDictAppendNofree( &val, "v", &versval, "m", &msgsval, NULL ) )
119    {
120        free( vers );
121        tr_bencFree( &val );
122        return NULL;
123    }
124
125    /* human readable version string */
126    tr_bencInitStr( versval, vers, 0, 0 );
127
128    /* create dict of supported extended messages */
129    tr_bencInit( msgsval, TYPE_DICT );
130    if( tr_bencDictAppendNofree( msgsval, "ut_pex", &pexval, NULL ) )
131    {
132        tr_bencFree( &val );
133        return NULL;
134    }
135    /* for public torrents advertise utorrent pex message */
136    tr_bencInitInt( pexval, ( peer->private ? 0 : EXTENDED_PEX_ID ) );
137
138    /* our listening port */
139    if( 0 < tor->publicPort )
140    {
141        if( tr_bencDictAppendNofree( &val, "p", &portval, NULL ) )
142        {
143            tr_bencFree( &val );
144            return NULL;
145        }
146        tr_bencInitInt( portval, tor->publicPort );
147    }
148
149    /* bencode it */
150    buf = tr_bencSaveMalloc( &val, len );
151    tr_bencFree( &val );
152
153    if( NULL != buf )
154    {
155        peer->advertisedPort = tor->publicPort;
156    }
157
158    return buf;
159}
160
161static int
162peertreeToBencUT( tr_peertree_t * tree, benc_val_t * val )
163{
164    char                * buf;
165    tr_peertree_entry_t * ii;
166    int                   count;
167
168    count = peertreeCount( tree );
169    if( 0 == count )
170    {
171        tr_bencInitStr( val, NULL, 0, 1 );
172        return 0;
173    }
174
175    buf = malloc( 6 * count );
176    if( NULL == buf )
177    {
178        return 1;
179    }
180    tr_bencInitStr( val, buf, 6 * count, 0 );
181
182    for( ii = peertreeFirst( tree ); NULL != ii;
183         ii = peertreeNext( tree, ii ) )
184    {
185        assert( 0 < count );
186        count--;
187        memcpy( buf + 6 * count, ii->peer, 6 );
188    }
189    assert( 0 == count );
190
191    return 0;
192}
193
194static char *
195makeUTPex( tr_torrent_t * tor, tr_peer_t * peer, int * len )
196{
197    benc_val_t val;
198    char     * ret;
199
200    assert( !peer->private );
201    tr_bencInitStr( &val, NULL, 0, 1 );
202    ret = makeCommonPex( tor, peer, len, peertreeToBencUT, "added.f", &val );
203
204    return ret;
205}
206
207static inline int
208parseExtendedHandshake( tr_peer_t * peer, uint8_t * buf, int len )
209{
210    benc_val_t     val, * sub;
211
212    if( tr_bencLoad( buf, len, &val, NULL ) )
213    {
214        peer_dbg( "invalid bencoding in extended handshake" );
215        return TR_ERROR;
216    }
217    if( TYPE_DICT != val.type )
218    {
219        peer_dbg( "extended handshake is not a dictionary" );
220        tr_bencFree( &val );
221        return TR_ERROR;
222    }
223
224    /* check supported messages for utorrent pex */
225    sub = tr_bencDictFind( &val, "m" );
226    if( NULL != sub && TYPE_DICT == sub->type )
227    {
228        sub = tr_bencDictFind( sub, "ut_pex" );
229        if( NULL != sub && TYPE_INT == sub->type )
230        {
231            peer->pexStatus = 0;
232            if( 0x0 < sub->val.i && 0xff >= sub->val.i )
233            {
234                peer->pexStatus = sub->val.i;
235            }
236        }
237    }
238
239    /* get peer's listening port */
240    sub = tr_bencDictFind( &val, "p" );
241    if( NULL != sub && TYPE_INT == sub->type &&
242        0x0 < sub->val.i && 0xffff >= sub->val.i )
243    {
244        peer->port = htons( (uint16_t) sub->val.i );
245        peer_dbg( "got listening port %i", ntohs( peer->port ) );
246    }
247
248    tr_bencFree( &val );
249    return TR_OK;
250}
251
252static inline int
253parseUTPex( tr_torrent_t * tor, tr_peer_t * peer, uint8_t * buf, int len )
254{
255    benc_val_t val, * sub;
256
257    if( peer->private || PEX_PEER_CUTOFF <= tor->peerCount )
258    {
259        return TR_OK;
260    }
261
262    if( tr_bencLoad( buf, len, &val, NULL ) )
263    {
264        peer_dbg( "invalid bencoding in extended peer exchange" );
265        return TR_ERROR;
266    }
267    if( TYPE_DICT != val.type )
268    {
269        tr_bencFree( &val );
270        peer_dbg( "extended peer exchange is not a dictionary" );
271        return TR_ERROR;
272    }
273
274    sub = tr_bencDictFind( &val, "added" );
275    if( NULL != sub && TYPE_STR == sub->type && 0 == sub->val.s.i % 6 )
276    {
277        tr_torrentAddCompact( tor, TR_PEER_FROM_PEX,
278                              ( uint8_t * )sub->val.s.s, sub->val.s.i / 6 );
279    }
280
281    return TR_OK;
282}
Note: See TracBrowser for help on using the repository browser.