source: branches/daemon/libtransmission/peerext.h @ 1712

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

Merge libT revs 1616:1711 from trunk to daemon branch.

  • Property svn:keywords set to Date Rev Author Id
File size: 9.1 KB
Line 
1/******************************************************************************
2 * $Id: peerext.h 1712 2007-04-14 06:34:52Z 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_bencDictReserve( &val, 3 ) )
71    {
72        tr_bencFree( &val );
73        peertreeMerge( sent, &common );
74        peertreeFree( &added );
75        tr_bencFree( extraval );
76        return NULL;
77    }
78    extra  = tr_bencDictAdd( &val, extrakey );
79    addval = tr_bencDictAdd( &val, "added" );
80    delval = tr_bencDictAdd( &val, "dropped" );
81    assert( NULL != extra && NULL != addval && NULL != delval );
82    if( (*peerfunc)( &added, addval ) || (*peerfunc)( sent, delval ) )
83    {
84        tr_bencFree( &val );
85        peertreeMerge( sent, &common );
86        peertreeFree( &added );
87        tr_bencFree( extraval );
88        return NULL;
89    }
90    *extra = *extraval;
91    memset( extraval, 0, sizeof( extraval ) );
92
93    /* bencode it */
94    buf = tr_bencSaveMalloc( &val, len );
95    tr_bencFree( &val );
96    if( NULL == buf )
97    {
98        peertreeMerge( sent, &common );
99        peertreeFree( &added );
100        return NULL;
101    }
102
103    peertreeSwap( sent, &common );
104    peertreeMerge( sent, &added );
105    peertreeFree( &common );
106
107    return buf;
108}
109
110static char *
111makeExtendedHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * len )
112{
113    benc_val_t val, * msgsval;
114    char * buf, * vers;
115
116    /* get human-readable version string */
117    vers = NULL;
118    asprintf( &vers, "%s %s", TR_NAME, VERSION_STRING );
119    if( NULL == vers )
120    {
121        return NULL;
122    }
123
124    /* reserve space in toplevel dictionary for v, m, and possibly p */
125    tr_bencInit( &val, TYPE_DICT );
126    if( tr_bencDictReserve( &val, ( 0 < tor->publicPort ? 3 : 2 ) ) )
127    {
128        free( vers );
129        tr_bencFree( &val );
130        return NULL;
131    }
132
133    /* human readable version string */
134    tr_bencInitStr( tr_bencDictAdd( &val, "v" ), vers, 0, 0 );
135
136    /* create dict of supported extended messages */
137    msgsval  = tr_bencDictAdd( &val, "m" );
138    tr_bencInit( msgsval, TYPE_DICT );
139    if( tr_bencDictReserve( msgsval, 1 ) )
140    {
141        tr_bencFree( &val );
142        return NULL;
143    }
144    /* for public torrents advertise utorrent pex message */
145    tr_bencInitInt( tr_bencDictAdd( msgsval, "ut_pex" ),
146                    ( peer->private ? 0 : EXTENDED_PEX_ID ) );
147
148    /* our listening port */
149    if( 0 < tor->publicPort )
150    {
151        tr_bencInitInt( tr_bencDictAdd( &val, "p" ), tor->publicPort );
152    }
153
154    /* bencode it */
155    buf = tr_bencSaveMalloc( &val, len );
156    tr_bencFree( &val );
157    if( NULL == buf )
158    {
159        return NULL;
160    }
161
162    peer->advertisedPort = tor->publicPort;
163
164    peer_dbg( "SEND extended-handshake, %s pex",
165              ( peer->private ? "without" : "with" ) );
166
167    return buf;
168}
169
170static int
171peertreeToBencUT( tr_peertree_t * tree, benc_val_t * val )
172{
173    char                * buf;
174    tr_peertree_entry_t * ii;
175    int                   count;
176
177    count = peertreeCount( tree );
178    if( 0 == count )
179    {
180        tr_bencInitStr( val, NULL, 0, 1 );
181        return 0;
182    }
183
184    buf = malloc( 6 * count );
185    if( NULL == buf )
186    {
187        return 1;
188    }
189    tr_bencInitStr( val, buf, 6 * count, 0 );
190
191    for( ii = peertreeFirst( tree ); NULL != ii;
192         ii = peertreeNext( tree, ii ) )
193    {
194        assert( 0 < count );
195        count--;
196        memcpy( buf + 6 * count, ii->peer, 6 );
197    }
198    assert( 0 == count );
199
200    return 0;
201}
202
203static char *
204makeUTPex( tr_torrent_t * tor, tr_peer_t * peer, int * len )
205{
206    benc_val_t val;
207    char     * ret;
208
209    peer_dbg( "SEND extended-pex" );
210
211    assert( !peer->private );
212    tr_bencInitStr( &val, NULL, 0, 1 );
213    ret = makeCommonPex( tor, peer, len, peertreeToBencUT, "added.f", &val );
214
215    return ret;
216}
217
218static inline int
219parseExtendedHandshake( tr_peer_t * peer, uint8_t * buf, int len )
220{
221    benc_val_t val, * sub;
222    int        dbgport, dbgpex;
223
224    if( tr_bencLoad( buf, len, &val, NULL ) )
225    {
226        peer_dbg( "GET  extended-handshake, invalid bencoding" );
227        return TR_ERROR;
228    }
229    if( TYPE_DICT != val.type )
230    {
231        peer_dbg( "GET  extended-handshake, not a dictionary" );
232        tr_bencFree( &val );
233        return TR_ERROR;
234    }
235
236    /* check supported messages for utorrent pex */
237    sub = tr_bencDictFind( &val, "m" );
238    dbgpex = -1;
239    if( NULL != sub && TYPE_DICT == sub->type )
240    {
241        sub = tr_bencDictFind( sub, "ut_pex" );
242        if( NULL != sub && TYPE_INT == sub->type )
243        {
244            peer->pexStatus = 0;
245            if( 0x0 < sub->val.i && 0xff >= sub->val.i )
246            {
247                peer->pexStatus = sub->val.i;
248                dbgpex = sub->val.i;
249            }
250        }
251    }
252
253#if 0 /* ugh, we have to deal with encoding if we do this */
254    /* get peer's client name */
255    sub = tr_bencDictFind( &val, "v" );
256    if( NULL != sub && TYPE_STR == sub->type &&
257        ( NULL == peer->client || 0 != strcmp( sub->val.s.s, peer->client ) ) )
258    {
259        client = tr_bencStealStr( sub );
260        if( NULL != client )
261        {
262            free( peer->client );
263            peer->client = client;
264        }
265    }
266#endif
267
268    /* get peer's listening port */
269    sub = tr_bencDictFind( &val, "p" );
270    dbgport = -1;
271    if( NULL != sub && TYPE_INT == sub->type &&
272        0x0 < sub->val.i && 0xffff >= sub->val.i )
273    {
274        peer->port = htons( (uint16_t) sub->val.i );
275        dbgport = sub->val.i;
276    }
277
278    peer_dbg( "GET  extended-handshake, ok port=%i pex=%i", dbgport, dbgpex );
279
280    tr_bencFree( &val );
281    return TR_OK;
282}
283
284static inline int
285parseUTPex( tr_torrent_t * tor, tr_peer_t * peer, uint8_t * buf, int len )
286{
287    benc_val_t val, * sub;
288    int used;
289
290    if( peer->private || PEX_PEER_CUTOFF <= tor->peerCount )
291    {
292        peer_dbg( "GET  extended-pex, ignoring p=%i c=(%i<=%i)",
293                  peer->private, PEX_PEER_CUTOFF, tor->peerCount );
294        return TR_OK;
295    }
296
297    if( tr_bencLoad( buf, len, &val, NULL ) )
298    {
299        peer_dbg( "GET  extended-pex, invalid bencoding" );
300        return TR_ERROR;
301    }
302    if( TYPE_DICT != val.type )
303    {
304        tr_bencFree( &val );
305        peer_dbg( "GET  extended-pex, not a dictionary" );
306        return TR_ERROR;
307    }
308
309    sub = tr_bencDictFind( &val, "added" );
310    if( NULL != sub && TYPE_STR == sub->type && 0 == sub->val.s.i % 6 )
311    {
312        used = tr_torrentAddCompact( tor, TR_PEER_FROM_PEX,
313                                     ( uint8_t * )sub->val.s.s,
314                                     sub->val.s.i / 6 );
315        peer_dbg( "GET  extended-pex, got %i peers, used %i",
316                  sub->val.s.i / 6, used );
317    }
318    else
319    {
320        peer_dbg( "GET  extended-pex, no peers" );
321    }
322
323    return TR_OK;
324}
Note: See TracBrowser for help on using the repository browser.