diff --git a/libtransmission/bencode.c b/libtransmission/bencode.c index 991e15f6d..4e3303cd8 100644 --- a/libtransmission/bencode.c +++ b/libtransmission/bencode.c @@ -318,40 +318,7 @@ void tr_bencInitInt( benc_val_t * val, int64_t num ) val->val.i = num; } -int tr_bencListAppend( benc_val_t * val, ... ) -{ - va_list ap; - int len; - benc_val_t ** ptr; - - assert( TYPE_LIST == val->type ); - - len = 0; - va_start( ap, val ); - while( NULL != va_arg( ap, benc_val_t ** ) ) - { - len++; - } - va_end( ap ); - - if( makeroom( val, len ) ) - { - return 1; - } - - va_start( ap, val ); - while( NULL != ( ptr = va_arg( ap, benc_val_t ** ) ) ) - { - *ptr = &val->val.l.vals[val->val.l.count]; - tr_bencInit( *ptr, TYPE_INT ); - val->val.l.count++; - } - va_end( ap ); - - return 0; -} - -int tr_bencListExtend( benc_val_t * val, int count ) +int tr_bencListReserve( benc_val_t * val, int count ) { assert( TYPE_LIST == val->type ); @@ -363,75 +330,48 @@ int tr_bencListExtend( benc_val_t * val, int count ) return 0; } -static inline int _tr_bencDictAppend( benc_val_t * val, va_list ap, - va_list ap2, int nofree ) +int tr_bencDictReserve( benc_val_t * val, int count ) { - int len; - char * key; - benc_val_t ** ptr; - assert( TYPE_DICT == val->type ); - len = 0; - while( NULL != va_arg( ap, char * ) ) - { - ptr = va_arg( ap, benc_val_t ** ); - assert( NULL != ptr ); - len += 2; - } - - if( makeroom( val, len ) ) + if( makeroom( val, count * 2 ) ) { return 1; } - while( NULL != ( key = va_arg( ap2, char * ) ) ) - { - if( !nofree ) - { - key = strdup( key ); - if( NULL == key ) - { - return 1; - } - } - ptr = va_arg( ap2, benc_val_t ** ); - tr_bencInitStr( &val->val.l.vals[val->val.l.count], key, 0, nofree ); - val->val.l.count++; - *ptr = &val->val.l.vals[val->val.l.count]; - tr_bencInit( *ptr, TYPE_INT ); - val->val.l.count++; - } - return 0; } -int tr_bencDictAppend( benc_val_t * val, ... ) +benc_val_t * tr_bencListAdd( benc_val_t * list ) { - va_list ap, ap2; - int ret; + benc_val_t * item; - va_start( ap, val ); - va_start( ap2, val ); - ret = _tr_bencDictAppend( val, ap, ap2, 0 ); - va_end( ap2 ); - va_end( ap ); + assert( TYPE_LIST == list->type ); + assert( list->val.l.count < list->val.l.alloc ); - return ret; + item = &list->val.l.vals[list->val.l.count]; + list->val.l.count++; + tr_bencInit( item, TYPE_INT ); + + return item; } -int tr_bencDictAppendNofree( benc_val_t * val, ... ) +benc_val_t * tr_bencDictAdd( benc_val_t * dict, const char * key ) { - va_list ap, ap2; - int ret; + benc_val_t * keyval, * itemval; - va_start( ap, val ); - va_start( ap2, val ); - ret = _tr_bencDictAppend( val, ap, ap2, 1 ); - va_end( ap2 ); - va_end( ap ); + assert( TYPE_DICT == dict->type ); + assert( dict->val.l.count + 2 <= dict->val.l.alloc ); - return ret; + keyval = &dict->val.l.vals[dict->val.l.count]; + dict->val.l.count++; + itemval = &dict->val.l.vals[dict->val.l.count]; + dict->val.l.count++; + + tr_bencInitStr( keyval, key, -1, 1 ); + tr_bencInit( itemval, TYPE_INT ); + + return itemval; } char * tr_bencSaveMalloc( benc_val_t * val, int * len ) diff --git a/libtransmission/bencode.h b/libtransmission/bencode.h index f480f63b1..e1034f9dc 100644 --- a/libtransmission/bencode.h +++ b/libtransmission/bencode.h @@ -76,15 +76,12 @@ static inline void tr_bencInit( benc_val_t * val, int type ) void _tr_bencInitStr( benc_val_t * val, char * str, int len, int nofree ); int tr_bencInitStrDup( benc_val_t * val, const char * str ); void tr_bencInitInt( benc_val_t * val, int64_t num ); -/* args are a NULL terminated list of benc_val_t** */ -int tr_bencListAppend( benc_val_t * val, ... ); -/* args are a NULL terminated list of pairs of char * key, benc_val_t ** val */ -int tr_bencDictAppend( benc_val_t * val, ... ); -/* like tr_bencDictAppend but char * key args are marked nofree */ -int tr_bencDictAppendNofree( benc_val_t * val, ... ); - -/* insure val has room for at least count more items */ -int tr_bencListExtend( benc_val_t * val, int count ); +int tr_bencListReserve( benc_val_t * list, int count ); +/* note that for one key-value pair, count should be 1, not 2 */ +int tr_bencDictReserve( benc_val_t * dict, int count ); +benc_val_t * tr_bencListAdd( benc_val_t * list ); +/* note: key must not be freed or modified while val is in use */ +benc_val_t * tr_bencDictAdd( benc_val_t * dict, const char * key ); char * tr_bencSaveMalloc( benc_val_t * val, int * len ); int tr_bencSave( benc_val_t * val, char ** buf, diff --git a/libtransmission/peeraz.h b/libtransmission/peeraz.h index 1129e6d2d..d97ad5d4c 100644 --- a/libtransmission/peeraz.h +++ b/libtransmission/peeraz.h @@ -100,8 +100,7 @@ static uint8_t * makeAZHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * buflen ) { char * buf; - benc_val_t val, * idval, * clientval, * versval; - benc_val_t * tcpval, * msgsval, * msgdictval, * msgidval, * msgversval; + benc_val_t val, * msgsval, * msgdictval; int len, max, idx; uint8_t vers; @@ -123,13 +122,7 @@ makeAZHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * buflen ) /* start building a dictionary for handshake data */ tr_bencInit( &val, TYPE_DICT ); - if( tr_bencDictAppendNofree( &val, - "identity", &idval, - "client", &clientval, - "version", &versval, - "tcp_port", &tcpval, - "messages", &msgsval, - NULL ) ) + if( tr_bencDictReserve( &val, 5 ) ) { free( buf ); tr_bencFree( &val ); @@ -137,13 +130,23 @@ makeAZHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * buflen ) } /* fill in the dictionary values */ - tr_bencInitStr( idval, tor->azId, TR_AZ_ID_LEN, 1 ); - tr_bencInitStr( clientval, TR_NAME, 0, 1 ); - tr_bencInitStr( versval, VERSION_STRING, 0, 1 ); - tr_bencInitInt( tcpval, tor->publicPort ); - tr_bencInit( msgsval, TYPE_LIST ); + tr_bencInitStr( tr_bencDictAdd( &val, "identity" ), + tor->azId, TR_AZ_ID_LEN, 1 ); + tr_bencInitStr( tr_bencDictAdd( &val, "client" ), TR_NAME, 0, 1 ); + tr_bencInitStr( tr_bencDictAdd( &val, "version" ), VERSION_STRING, 0, 1 ); + tr_bencInitInt( tr_bencDictAdd( &val, "tcp_port" ), tor->publicPort ); - /* fill in the supported message list */ + /* initialize supported message list */ + msgsval = tr_bencDictAdd( &val, "messages" ); + tr_bencInit( msgsval, TYPE_LIST ); + if( tr_bencListReserve( msgsval, azmsgCount() ) ) + { + tr_bencFree( &val ); + free( buf ); + return NULL; + } + + /* fill in the message list */ vers = AZ_EXT_VERSION; for( idx = 0; azmsgCount() > idx; idx++ ) { @@ -156,25 +159,18 @@ makeAZHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * buflen ) /* no point in saying we can do pex if the torrent is private */ continue; } - if( tr_bencListAppend( msgsval, &msgdictval, NULL ) ) - { - tr_bencFree( &val ); - free( buf ); - return NULL; - } /* each item in the list is a dict with id and ver keys */ + msgdictval = tr_bencListAdd( msgsval ); tr_bencInit( msgdictval, TYPE_DICT ); - if( tr_bencDictAppendNofree( msgdictval, - "id", &msgidval, - "ver", &msgversval, - NULL ) ) + if( tr_bencDictReserve( msgdictval, 2 ) ) { tr_bencFree( &val ); free( buf ); return NULL; } - tr_bencInitStr( msgidval, azmsgStr( idx ), azmsgLen( idx ), 1 ); - tr_bencInitStr( msgversval, &vers, 1, 1 ); + tr_bencInitStr( tr_bencDictAdd( msgdictval, "id" ), + azmsgStr( idx ), azmsgLen( idx ), 1 ); + tr_bencInitStr( tr_bencDictAdd( msgdictval, "ver" ), &vers, 1, 1 ); } /* bencode the dictionary and append it to the buffer */ @@ -200,7 +196,7 @@ makeAZHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * buflen ) static int peertreeToBencAZ( tr_peertree_t * tree, benc_val_t * val ) { - int count, jj; + int count; tr_peertree_entry_t * ii; tr_bencInit( val, TYPE_LIST ); @@ -209,20 +205,16 @@ peertreeToBencAZ( tr_peertree_t * tree, benc_val_t * val ) { return 0; } - if( tr_bencListExtend( val, count ) ) + if( tr_bencListReserve( val, count ) ) { return 1; } ii = peertreeFirst( tree ); - jj = val->val.l.count; while( NULL != ii ) { - assert( jj < val->val.l.alloc ); - tr_bencInitStr( &val->val.l.vals[jj], ii->peer, 6, 1 ); - val->val.l.count++; + tr_bencInitStr( tr_bencListAdd( val ), ii->peer, 6, 1 ); ii = peertreeNext( tree, ii ); - jj++; } return 0; diff --git a/libtransmission/peerext.h b/libtransmission/peerext.h index 6a4bf7b2c..ae57652f6 100644 --- a/libtransmission/peerext.h +++ b/libtransmission/peerext.h @@ -67,10 +67,19 @@ makeCommonPex( tr_torrent_t * tor, tr_peer_t * peer, int * len, /* build the dictionaries */ tr_bencInit( &val, TYPE_DICT ); if( ( peertreeEmpty( &added ) && peertreeEmpty( sent ) ) || - tr_bencDictAppendNofree( &val, extrakey, &extra, "added", &addval, - "dropped", &delval, NULL ) || - (*peerfunc)( &added, addval ) || - (*peerfunc)( sent, delval ) ) + tr_bencDictReserve( &val, 3 ) ) + { + tr_bencFree( &val ); + peertreeMerge( sent, &common ); + peertreeFree( &added ); + tr_bencFree( extraval ); + return NULL; + } + extra = tr_bencDictAdd( &val, extrakey ); + addval = tr_bencDictAdd( &val, "added" ); + delval = tr_bencDictAdd( &val, "dropped" ); + assert( NULL != extra && NULL != addval && NULL != delval ); + if( (*peerfunc)( &added, addval ) || (*peerfunc)( sent, delval ) ) { tr_bencFree( &val ); peertreeMerge( sent, &common ); @@ -101,12 +110,9 @@ makeCommonPex( tr_torrent_t * tor, tr_peer_t * peer, int * len, static char * makeExtendedHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * len ) { - benc_val_t val, * msgsval, * portval, * versval, * pexval; + benc_val_t val, * msgsval; char * buf, * vers; - peer_dbg( "SEND extended-handshake, %s pex", - ( peer->private ? "without" : "with" ) ); - /* get human-readable version string */ vers = NULL; asprintf( &vers, "%s %s", TR_NAME, VERSION_STRING ); @@ -115,10 +121,9 @@ makeExtendedHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * len ) return NULL; } + /* reserve space in toplevel dictionary for v, m, and possibly p */ tr_bencInit( &val, TYPE_DICT ); - - /* append v str and m dict to toplevel dictionary */ - if( tr_bencDictAppendNofree( &val, "v", &versval, "m", &msgsval, NULL ) ) + if( tr_bencDictReserve( &val, ( 0 < tor->publicPort ? 3 : 2 ) ) ) { free( vers ); tr_bencFree( &val ); @@ -126,41 +131,41 @@ makeExtendedHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * len ) } /* human readable version string */ - tr_bencInitStr( versval, vers, 0, 0 ); + tr_bencInitStr( tr_bencDictAdd( &val, "v" ), vers, 0, 0 ); /* create dict of supported extended messages */ + msgsval = tr_bencDictAdd( &val, "m" ); tr_bencInit( msgsval, TYPE_DICT ); if( !peer->private ) { - /* for public torrents advertise utorrent pex message */ - if( tr_bencDictAppendNofree( msgsval, "ut_pex", &pexval, NULL ) ) + /* for public torrents, advertise utorrent pex message */ + if( tr_bencDictReserve( msgsval, 1 ) ) { tr_bencFree( &val ); return NULL; } - tr_bencInitInt( pexval, EXTENDED_PEX_ID ); + tr_bencInitInt( tr_bencDictAdd( msgsval, "ut_pex" ), EXTENDED_PEX_ID ); } /* our listening port */ if( 0 < tor->publicPort ) { - if( tr_bencDictAppendNofree( &val, "p", &portval, NULL ) ) - { - tr_bencFree( &val ); - return NULL; - } - tr_bencInitInt( portval, tor->publicPort ); + tr_bencInitInt( tr_bencDictAdd( &val, "p" ), tor->publicPort ); } /* bencode it */ buf = tr_bencSaveMalloc( &val, len ); tr_bencFree( &val ); - - if( NULL != buf ) + if( NULL == buf ) { - peer->advertisedPort = tor->publicPort; + return NULL; } + peer->advertisedPort = tor->publicPort; + + peer_dbg( "SEND extended-handshake, %s pex", + ( peer->private ? "without" : "with" ) ); + return buf; }