source: trunk/libtransmission/peerext.h @ 1579

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

Merge PEX branch, I hope this works.

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