remove the "peer is asking for too many blocks!" warning reported by Gimp_ by changing from a fixed-size array to a linked lists of incoming requests
This commit is contained in:
parent
b1ab3968e7
commit
08f787291a
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* This file is licensed by the GPL version 2. Works owned by the
|
||||
* Transmission project are granted a special exemption to clause 2(b)
|
||||
* so that the bulk of its code can remain under the MIT license.
|
||||
* This exemption does not extend to derived works not owned by
|
||||
* the Transmission project.
|
||||
*/
|
||||
|
||||
#include "transmission.h"
|
||||
#include "list.h"
|
||||
#include "utils.h"
|
||||
|
||||
int
|
||||
tr_list_length( const tr_list_t * list )
|
||||
{
|
||||
int i = 0;
|
||||
while( list ) {
|
||||
++i;
|
||||
list = list->next;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
tr_list_t*
|
||||
tr_list_alloc( void )
|
||||
{
|
||||
return tr_new0( tr_list_t, 1 );
|
||||
}
|
||||
|
||||
void
|
||||
tr_list_free1( tr_list_t* node )
|
||||
{
|
||||
tr_free( node );
|
||||
}
|
||||
|
||||
void
|
||||
tr_list_free( tr_list_t* list )
|
||||
{
|
||||
while( list )
|
||||
{
|
||||
tr_list_t * node = list;
|
||||
list = list->next;
|
||||
tr_list_free1( node );
|
||||
}
|
||||
}
|
||||
|
||||
tr_list_t*
|
||||
tr_list_prepend( tr_list_t * list, void * data )
|
||||
{
|
||||
tr_list_t * node = tr_list_alloc ();
|
||||
node->data = data;
|
||||
node->next = list;
|
||||
if( list )
|
||||
list->prev = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
tr_list_t*
|
||||
tr_list_append( tr_list_t * list, void * data )
|
||||
{
|
||||
tr_list_t * node = list;
|
||||
tr_list_t * l = tr_list_alloc( );
|
||||
l->data = data;
|
||||
if( !list )
|
||||
return l;
|
||||
while( node->next )
|
||||
node = node->next;
|
||||
node->next = l;
|
||||
l->prev = node;
|
||||
return list;
|
||||
}
|
||||
|
||||
tr_list_t*
|
||||
tr_list_find_data ( tr_list_t * list, const void * data )
|
||||
{
|
||||
for(; list; list=list->next )
|
||||
if( list->data == data )
|
||||
return list;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tr_list_t*
|
||||
tr_list_remove( tr_list_t * list, const void * data )
|
||||
{
|
||||
tr_list_t * node = tr_list_find_data( list, data );
|
||||
tr_list_t * prev = node ? node->prev : NULL;
|
||||
tr_list_t * next = node ? node->next : NULL;
|
||||
if( prev ) prev->next = next;
|
||||
if( next ) next->prev = prev;
|
||||
if( list == node ) list = next;
|
||||
tr_list_free1( node );
|
||||
return list;
|
||||
}
|
||||
|
||||
tr_list_t*
|
||||
tr_list_find ( tr_list_t * list , TrListCompareFunc func, const void * b )
|
||||
{
|
||||
for( ; list; list=list->next )
|
||||
if( !func( list->data, b ) )
|
||||
return list;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
tr_list_foreach( tr_list_t * list, TrListForeachFunc func )
|
||||
{
|
||||
while( list )
|
||||
{
|
||||
func( list->data );
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* This file is licensed by the GPL version 2. Works owned by the
|
||||
* Transmission project are granted a special exemption to clause 2(b)
|
||||
* so that the bulk of its code can remain under the MIT license.
|
||||
* This exemption does not extend to derived works not owned by
|
||||
* the Transmission project.
|
||||
*/
|
||||
|
||||
#ifndef TR_LIST_H
|
||||
#define TR_LIST_H
|
||||
|
||||
typedef struct tr_list_s
|
||||
{
|
||||
void * data;
|
||||
struct tr_list_s * next;
|
||||
struct tr_list_s * prev;
|
||||
}
|
||||
tr_list_t;
|
||||
|
||||
void tr_list_free_1 ( void );
|
||||
void tr_list_free ( tr_list_t* );
|
||||
int tr_list_length ( const tr_list_t* );
|
||||
tr_list_t* tr_list_append ( tr_list_t*, void * data );
|
||||
tr_list_t* tr_list_prepend ( tr_list_t*, void * data );
|
||||
tr_list_t* tr_list_remove ( tr_list_t*, const void * data );
|
||||
tr_list_t* tr_list_pop ( tr_list_t*, void ** setme );
|
||||
|
||||
typedef int (*TrListCompareFunc)(const void * a, const void * b);
|
||||
tr_list_t* tr_list_find ( tr_list_t*, TrListCompareFunc func, const void * b );
|
||||
tr_list_t* tr_list_find_data ( tr_list_t*, const void * data );
|
||||
|
||||
typedef void (*TrListForeachFunc)(void *);
|
||||
void tr_list_foreach( tr_list_t*, TrListForeachFunc func );
|
||||
|
||||
#endif /* TR_LIST_H */
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "transmission.h"
|
||||
#include "peertree.h"
|
||||
#include "list.h"
|
||||
|
||||
/*****
|
||||
******
|
||||
|
@ -189,10 +190,7 @@ struct tr_peer_s
|
|||
int inLength;
|
||||
uint64_t inTotal;
|
||||
|
||||
int outRequestCount;
|
||||
int outRequestMax;
|
||||
int outRequestAlloc;
|
||||
tr_request_t * outRequests;
|
||||
tr_list_t * outRequests;
|
||||
uint64_t outTotal;
|
||||
uint64_t outDate;
|
||||
|
||||
|
@ -247,9 +245,6 @@ tr_peer_t * tr_peerInit( struct in_addr addr, in_port_t port, int s, int from )
|
|||
peer->download = tr_rcInit();
|
||||
peer->upload = tr_rcInit();
|
||||
|
||||
peer->outRequestMax = peer->outRequestAlloc = 2;
|
||||
peer->outRequests = tr_new0( tr_request_t, peer->outRequestAlloc );
|
||||
|
||||
peer->inRequestMax = peer->inRequestAlloc = 2;
|
||||
peer->inRequests = tr_new0( tr_request_t, peer->inRequestAlloc );
|
||||
|
||||
|
@ -288,8 +283,9 @@ void tr_peerDestroy( tr_peer_t * peer )
|
|||
tr_bitfieldFree( peer->blamefield );
|
||||
tr_bitfieldFree( peer->banfield );
|
||||
tr_bitfieldFree( peer->reqfield );
|
||||
tr_list_foreach( peer->outRequests, tr_free );
|
||||
tr_list_free( peer->outRequests );
|
||||
tr_free( peer->inRequests );
|
||||
tr_free( peer->outRequests );
|
||||
tr_free( peer->buf );
|
||||
tr_free( peer->outMessages );
|
||||
if( peer->status > PEER_STATUS_IDLE )
|
||||
|
@ -870,7 +866,6 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor )
|
|||
for( i=0; i<tor->peerCount; ++i )
|
||||
{
|
||||
double outboundSpeedKiBs;
|
||||
double inboundSpeedKiBs;
|
||||
int size;
|
||||
tr_peer_t * peer = tor->peers[ i ];
|
||||
|
||||
|
@ -888,18 +883,6 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor )
|
|||
peer->inRequestAlloc = peer->inRequestMax;
|
||||
peer->inRequests = tr_renew( tr_request_t, peer->inRequests, peer->inRequestAlloc );
|
||||
}
|
||||
|
||||
/* decide how many blocks we'll concurrently let the peer ask us for */
|
||||
inboundSpeedKiBs = tr_rcRate(peer->download);
|
||||
size = queueTimeSec * inboundSpeedKiBs / blockSizeKiB;
|
||||
if( size < 4 ) /* don't let it get TOO small */
|
||||
size = 4;
|
||||
size += 4; /* and always leave room to grow */
|
||||
peer->outRequestMax = size;
|
||||
if( peer->outRequestAlloc < peer->outRequestMax ) {
|
||||
peer->outRequestAlloc = peer->outRequestMax;
|
||||
peer->outRequests = tr_renew( tr_request_t, peer->outRequests, peer->outRequestAlloc );
|
||||
}
|
||||
}
|
||||
|
||||
deadbeats = tr_new( tr_peer_t*, tor->peerCount );
|
||||
|
|
|
@ -104,34 +104,33 @@ fillHeader( tr_peer_t * peer, int size, int id, uint8_t * buf )
|
|||
return buf;
|
||||
}
|
||||
|
||||
static uint8_t * blockPending( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
int * size )
|
||||
static uint8_t *
|
||||
blockPending( tr_torrent_t * tor,
|
||||
tr_peer_t * peer,
|
||||
int * size )
|
||||
{
|
||||
if( !peer->outBlockLoaded )
|
||||
if( !peer->outBlockLoaded ) /* we need to load the block for the next request */
|
||||
{
|
||||
uint8_t * buf;
|
||||
tr_request_t * r;
|
||||
int hdrlen;
|
||||
|
||||
if( peer->amChoking || peer->outRequestCount < 1 )
|
||||
{
|
||||
/* No piece to send */
|
||||
if( peer->amChoking )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We need to load the block for the next request */
|
||||
r = &peer->outRequests[0];
|
||||
if( !peer->outRequests ) /* nothing to send */
|
||||
return NULL;
|
||||
|
||||
/* Sanity check */
|
||||
if( !tr_cpPieceIsComplete( tor->completion, r->index ) )
|
||||
r = (tr_request_t*) peer->outRequests->data;
|
||||
assert( r != NULL );
|
||||
peer->outRequests = tr_list_remove( peer->outRequests, r );
|
||||
|
||||
if( !tr_cpPieceIsComplete( tor->completion, r->index ) ) /* sanity clause */
|
||||
{
|
||||
/* We have been asked for something we don't have, buggy client?
|
||||
Let's just drop this request */
|
||||
/* We've been asked for something we don't have. buggy client? */
|
||||
tr_inf( "Block %d/%d/%d was requested but we don't have it",
|
||||
r->index, r->begin, r->length );
|
||||
(peer->outRequestCount)--;
|
||||
memmove( &peer->outRequests[0], &peer->outRequests[1],
|
||||
peer->outRequestCount * sizeof( tr_request_t ) );
|
||||
tr_free( r );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -146,21 +145,12 @@ static uint8_t * blockPending( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
|
||||
tr_ioRead( tor->io, r->index, r->begin, r->length, buf );
|
||||
|
||||
if( peer->outRequestCount < 1 )
|
||||
{
|
||||
/* We were choked during the read */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
peer_dbg( "SEND piece %d/%d (%d bytes)",
|
||||
r->index, r->begin, r->length );
|
||||
|
||||
peer->outBlockSize = hdrlen;
|
||||
peer->outBlockLoaded = 1;
|
||||
|
||||
(peer->outRequestCount)--;
|
||||
memmove( &peer->outRequests[0], &peer->outRequests[1],
|
||||
peer->outRequestCount * sizeof( tr_request_t ) );
|
||||
tr_free( r );
|
||||
}
|
||||
|
||||
*size = MIN( 1024, peer->outBlockSize );
|
||||
|
@ -234,9 +224,10 @@ static void sendChoke( tr_peer_t * peer, int yes )
|
|||
|
||||
if( !yes )
|
||||
{
|
||||
/* Drop older requests from the last time it was unchoked,
|
||||
if any */
|
||||
peer->outRequestCount = 0;
|
||||
/* Drop older requests from the last time it was unchoked, if any */
|
||||
tr_list_foreach( peer->outRequests, tr_free );
|
||||
tr_list_free( peer->outRequests );
|
||||
peer->outRequests = NULL;
|
||||
}
|
||||
|
||||
peer_dbg( "SEND %schoke", yes ? "" : "un" );
|
||||
|
|
|
@ -237,18 +237,11 @@ static inline int parseRequest( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
return TR_ERROR;
|
||||
}
|
||||
|
||||
if( peer->outRequestCount >= peer->outRequestMax )
|
||||
{
|
||||
tr_dbg( "Peer is asking for too many blocks!");
|
||||
return TR_ERROR;
|
||||
}
|
||||
|
||||
r = &peer->outRequests[peer->outRequestCount];
|
||||
r->index = index;
|
||||
r->begin = begin;
|
||||
r = tr_new0( tr_request_t, 1 );
|
||||
r->index = index;
|
||||
r->begin = begin;
|
||||
r->length = length;
|
||||
|
||||
(peer->outRequestCount)++;
|
||||
peer->outRequests = tr_list_append( peer->outRequests, r );
|
||||
|
||||
return TR_OK;
|
||||
}
|
||||
|
@ -378,13 +371,22 @@ static inline int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
return TR_OK;
|
||||
}
|
||||
|
||||
static int reqCompare( const void * va, const void * vb )
|
||||
{
|
||||
const tr_request_t * a = (const tr_request_t *) va;
|
||||
const tr_request_t * b = (const tr_request_t *) vb;
|
||||
if( a->index != b->index ) return a->index - b->index;
|
||||
if( a->begin != b->begin ) return a->begin - b->begin;
|
||||
return a->length - b->length;
|
||||
}
|
||||
|
||||
static inline int parseCancel( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
{
|
||||
tr_info_t * inf = &tor->info;
|
||||
int index, begin, length;
|
||||
int i;
|
||||
tr_request_t * r;
|
||||
tr_request_t req;
|
||||
tr_list_t * l;
|
||||
|
||||
if( len != 12 )
|
||||
{
|
||||
|
@ -410,17 +412,13 @@ static inline int parseCancel( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
peer_dbg( "GET cancel %d/%d (%d bytes)",
|
||||
index, begin, length );
|
||||
|
||||
for( i = 0; i < peer->outRequestCount; i++ )
|
||||
{
|
||||
r = &peer->outRequests[i];
|
||||
if( r->index == index && r->begin == begin &&
|
||||
r->length == length )
|
||||
{
|
||||
(peer->outRequestCount)--;
|
||||
memmove( &r[0], &r[1], sizeof( tr_request_t ) *
|
||||
( peer->outRequestCount - i ) );
|
||||
break;
|
||||
}
|
||||
/* remove it from the outRequests list */
|
||||
req.index = index;
|
||||
req.begin = begin;
|
||||
req.length = length;
|
||||
while(( l = tr_list_find( peer->outRequests, reqCompare, &req ) )) {
|
||||
tr_free( l->data );
|
||||
peer->outRequests = tr_list_remove( peer->outRequests, l );
|
||||
}
|
||||
|
||||
return TR_OK;
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
static void updateInterest( tr_torrent_t * tor, tr_peer_t * peer );
|
||||
|
||||
|
||||
static int peerCmp( tr_peer_t * peer1, tr_peer_t * peer2 )
|
||||
{
|
||||
/* Wait until we got the peers' ids */
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#define GRANULARITY_MSEC 200
|
||||
#define SHORT_INTERVAL_MSEC 1000
|
||||
#define LONG_INTERVAL_MSEC 10000
|
||||
#define LONG_INTERVAL_MSEC 20000
|
||||
#define HISTORY_SIZE (LONG_INTERVAL_MSEC / GRANULARITY_MSEC)
|
||||
|
||||
typedef struct
|
||||
|
@ -52,22 +52,18 @@ rateForInterval( const tr_ratecontrol_t * r, int interval_msec )
|
|||
uint64_t bytes = 0;
|
||||
const uint64_t now = tr_date ();
|
||||
int i = r->newest;
|
||||
int real_interval_msec = 0;
|
||||
for( ;; )
|
||||
{
|
||||
if( r->transfers[i].date + interval_msec < now )
|
||||
break;
|
||||
|
||||
bytes += r->transfers[i].size;
|
||||
real_interval_msec = now - r->transfers[i].date;
|
||||
|
||||
if( --i == -1 ) i = HISTORY_SIZE - 1; /* circular history */
|
||||
if( i == r->newest ) break; /* we've come all the way around */
|
||||
}
|
||||
|
||||
return !bytes || !real_interval_msec
|
||||
? 0.0
|
||||
: (bytes/1024.0) * (1000.0/real_interval_msec);
|
||||
return (bytes/1024.0) * (1000.0/interval_msec);
|
||||
}
|
||||
|
||||
/***
|
||||
|
|
|
@ -4,8 +4,8 @@ include ../mk/config.mk
|
|||
include ../mk/common.mk
|
||||
|
||||
SRCS = bencode.c choking.c clients.c completion.c fastresume.c fdlimit.c \
|
||||
http.c inout.c ipcparse.c makemeta.c metainfo.c natpmp.c net.c \
|
||||
peer.c platform.c ratecontrol.c sha1.c shared.c strlcat.c \
|
||||
http.c inout.c ipcparse.c list.c makemeta.c metainfo.c natpmp.c \
|
||||
net.c peer.c platform.c ratecontrol.c sha1.c shared.c strlcat.c \
|
||||
strlcpy.c torrent.c tracker.c transmission.c upnp.c utils.c xml.c
|
||||
|
||||
OBJS = $(SRCS:%.c=%.o)
|
||||
|
|
Loading…
Reference in New Issue