diff options
author | Oyvind Repvik <nail@nslu2-linux.org> | 2005-08-11 21:58:16 +0000 |
---|---|---|
committer | OpenEmbedded Project <openembedded-devel@lists.openembedded.org> | 2005-08-11 21:58:16 +0000 |
commit | de51ba6b4bffb51bda3ae87f49506d3f42793889 (patch) | |
tree | 5aedb713c53d3eb2b41cc93a2c4b265f61339b0c /packages/ctorrent | |
parent | 2c071abeee8f883ee38e4de0e0370a8816486894 (diff) |
Updated ctorrent to use the complete extended ctorrent patch set
Diffstat (limited to 'packages/ctorrent')
-rw-r--r-- | packages/ctorrent/ctorrent_1.3.4.bb | 11 | ||||
-rw-r--r-- | packages/ctorrent/files/align.patch | 189 | ||||
-rw-r--r-- | packages/ctorrent/files/configure.patch | 29 | ||||
-rw-r--r-- | packages/ctorrent/files/crash.patch | 24 | ||||
-rw-r--r-- | packages/ctorrent/files/extended_ctorrent.diff | 2169 | ||||
-rw-r--r-- | packages/ctorrent/files/fmt.patch | 42 | ||||
-rw-r--r-- | packages/ctorrent/files/nogetwd.patch | 34 | ||||
-rw-r--r-- | packages/ctorrent/files/passkey.patch | 16 | ||||
-rw-r--r-- | packages/ctorrent/files/stall.patch | 27 | ||||
-rw-r--r-- | packages/ctorrent/files/tracker.patch | 175 |
10 files changed, 2171 insertions, 545 deletions
diff --git a/packages/ctorrent/ctorrent_1.3.4.bb b/packages/ctorrent/ctorrent_1.3.4.bb index 087823cdb4..d2b02e8748 100644 --- a/packages/ctorrent/ctorrent_1.3.4.bb +++ b/packages/ctorrent/ctorrent_1.3.4.bb @@ -1,11 +1,4 @@ include ctorrent.inc -PR = "r4" +PR = "r5" -SRC_URI += "file://configure.patch;patch=1 \ - file://align.patch;patch=1 \ - file://nogetwd.patch;patch=1 \ - file://crash.patch;patch=1 \ - file://fmt.patch;patch=1 \ - file://stall.patch;patch=1 \ - file://tracker.patch;patch=1 \ - file://passkey.patch;patch=1" +SRC_URI += "file://extended_ctorrent.diff;patch=1" diff --git a/packages/ctorrent/files/align.patch b/packages/ctorrent/files/align.patch deleted file mode 100644 index 71dd7058cb..0000000000 --- a/packages/ctorrent/files/align.patch +++ /dev/null @@ -1,189 +0,0 @@ -diff -ur ctorrent-1.3.4/btstream.cpp new/btstream.cpp ---- ctorrent-1.3.4/btstream.cpp 2004-09-09 00:10:51.000000000 +0100 -+++ new/btstream.cpp 2005-01-25 01:25:31.000000000 +0000 -@@ -1,5 +1,6 @@ - #include <arpa/inet.h> - #include "btstream.h" -+#include "peer.h" - #include "msgencode.h" - #include "btconfig.h" - -@@ -11,7 +12,7 @@ - ssize_t btStream::Send_State(unsigned char state) - { - char msg[H_BASE_LEN + 4]; -- *(size_t*)msg = htonl(H_BASE_LEN); -+ set_nl(msg, H_BASE_LEN); - msg[4] = (char)state; - return out_buffer.PutFlush(sock,msg,H_BASE_LEN + 4); - } -@@ -19,12 +20,9 @@ - ssize_t btStream::Send_Have(size_t idx) - { - char msg[H_HAVE_LEN + 4]; -- size_t *p = (size_t*)msg; -- -- *p = htonl(H_HAVE_LEN); -+ set_nl(msg, H_HAVE_LEN); - msg[4] = (char)M_HAVE; -- p = (size_t*)(msg + 5); -- *p = htonl(idx); -+ set_nl(msg + 5, idx); - - return out_buffer.PutFlush(sock,msg,H_HAVE_LEN + 4); - } -@@ -43,14 +41,12 @@ - ssize_t btStream::Send_Cancel(size_t idx,size_t off,size_t len) - { - char msg[H_CANCEL_LEN + 4]; -- size_t *p = (size_t*)msg; - -- *p = htonl(H_CANCEL_LEN); -+ set_nl(msg, H_CANCEL_LEN); - msg[4] = M_CANCEL; -- p = (size_t*)(msg + 5); -- *p = htonl(idx); p++; -- *p = htonl(off); p++; -- *p = htonl(len); -+ set_nl(msg + 5, idx); -+ set_nl(msg + 9, off); -+ set_nl(msg + 13, len); - return out_buffer.Put(sock,msg,H_CANCEL_LEN + 4); - } - -@@ -72,14 +68,12 @@ - ssize_t btStream::Send_Request(size_t idx, size_t off,size_t len) - { - char msg[H_REQUEST_LEN + 4]; -- size_t *p = (size_t*) msg; - -- *p = htonl(H_REQUEST_LEN); -+ set_nl(msg, H_REQUEST_LEN); - msg[4] = (char)M_REQUEST; -- p = (size_t*)(msg + 5); -- *p = htonl(idx); p++; -- *p = htonl(off); p++; -- *p = htonl(len); -+ set_nl(msg + 5, idx); -+ set_nl(msg + 9, off); -+ set_nl(msg + 13, len); - return out_buffer.Put(sock,msg,H_REQUEST_LEN + 4); - } - -@@ -94,7 +88,7 @@ - // if message arrived. - size_t r; - if( 4 <= in_buffer.Count() ){ -- r = ntohl(*(size_t*)in_buffer.BasePointer()); -+ r = get_nl(in_buffer.BasePointer()); - if( (cfg_max_slice_size + H_PIECE_LEN + 4) < r) return -1; //message too long - if( (r + 4) <= in_buffer.Count() ) return 1; - } -diff -ur ctorrent-1.3.4/peer.cpp new/peer.cpp ---- ctorrent-1.3.4/peer.cpp 2004-09-09 00:10:51.000000000 +0100 -+++ new/peer.cpp 2005-01-25 01:23:51.000000000 +0000 -@@ -3,11 +3,32 @@ - #include <stdlib.h> - #include <string.h> - -+#include "btstream.h" - #include "./btcontent.h" - #include "./msgencode.h" - #include "./peerlist.h" - #include "./btconfig.h" - -+size_t get_nl(char *sfrom) -+{ -+ unsigned char *from = (unsigned char *)sfrom; -+ size_t t; -+ t = (*from++) << 24; -+ t |= (*from++) << 16; -+ t |= (*from++) << 8; -+ t |= *from; -+ return t; -+} -+ -+void set_nl(char *sto, size_t from) -+{ -+ unsigned char *to = (unsigned char *)sto; -+ *to++ = (from >> 24) & 0xff; -+ *to++ = (from >> 16) & 0xff; -+ *to++ = (from >> 8) & 0xff; -+ *to = from & 0xff; -+} -+ - btBasic Self; - - void btBasic::SetIp(struct sockaddr_in addr) -@@ -152,7 +173,8 @@ - - char *msgbuf = stream.in_buffer.BasePointer(); - -- r = ntohl(*(size_t*) msgbuf); -+ r = get_nl(msgbuf); -+ - - if( 0 == r ){ - time(&m_last_timestamp); -@@ -193,7 +215,7 @@ - case M_HAVE: - if(H_HAVE_LEN != r){return -1;} - -- idx = ntohl(*(size_t*) (msgbuf + 5)); -+ idx = get_nl(msgbuf + 5); - - if( idx >= BTCONTENT.GetNPieces() || bitfield.IsSet(idx)) return -1; - -@@ -208,12 +230,12 @@ - case M_REQUEST: - if(H_REQUEST_LEN != r || !m_state.remote_interested){ return -1; } - -- idx = ntohl(*(size_t*)(msgbuf + 5)); -+ idx = get_nl(msgbuf + 5); - - if( !BTCONTENT.pBF->IsSet(idx) ) return -1; - -- off = ntohl(*(size_t*)(msgbuf + 9)); -- len = ntohl(*(size_t*)(msgbuf + 13)); -+ off = get_nl(msgbuf + 9); -+ len = get_nl(msgbuf + 13); - - if( !reponse_q.IsValidRequest(idx, off, len) ) return -1; - -@@ -235,9 +257,9 @@ - case M_CANCEL: - if(r != H_CANCEL_LEN || !m_state.remote_interested) return -1; - -- idx = ntohl(*(size_t*)(msgbuf + 5)); -- off = ntohl(*(size_t*)(msgbuf + 9)); -- len = ntohl(*(size_t*)(msgbuf + 13)); -+ idx = get_nl(msgbuf + 5); -+ off = get_nl(msgbuf + 9); -+ len = get_nl(msgbuf + 13); - if( reponse_q.Remove(idx,off,len) < 0 ){ - m_err_count++; - return 0; -@@ -312,8 +334,8 @@ - size_t idx,off,len; - char *msgbuf = stream.in_buffer.BasePointer(); - -- idx = ntohl(*(size_t*) (msgbuf + 5)); -- off = ntohl(*(size_t*) (msgbuf + 9)); -+ idx = get_nl(msgbuf + 5); -+ off = get_nl(msgbuf + 9); - len = mlen - 9; - - if( request_q.Remove(idx,off,len) < 0 ){ -diff -ur ctorrent-1.3.4/peer.h new/peer.h ---- ctorrent-1.3.4/peer.h 2004-09-09 00:10:51.000000000 +0100 -+++ new/peer.h 2005-01-25 01:23:01.000000000 +0000 -@@ -34,6 +34,9 @@ - unsigned char reserved:4; /* unused */ - }BTSTATUS; - -+size_t get_nl(char *from); -+void set_nl(char *to, size_t from); -+ - class btBasic - { - private: diff --git a/packages/ctorrent/files/configure.patch b/packages/ctorrent/files/configure.patch deleted file mode 100644 index 95fe5cc2be..0000000000 --- a/packages/ctorrent/files/configure.patch +++ /dev/null @@ -1,29 +0,0 @@ -diff -ur ctorrent/configure ctorrent.new/configure ---- ctorrent/configure 2004-09-09 00:10:51.000000000 +0100 -+++ ctorrent.new/configure 2005-01-23 18:29:34.000000000 +0000 -@@ -3216,13 +3216,13 @@ - - else - --echo "$as_me:$LINENO: checking for SHA1_Init in -lcrypt" >&5 --echo $ECHO_N "checking for SHA1_Init in -lcrypt... $ECHO_C" >&6 -+echo "$as_me:$LINENO: checking for SHA1_Init in -lcrypto" >&5 -+echo $ECHO_N "checking for SHA1_Init in -lcrypto... $ECHO_C" >&6 - if test "${ac_cv_lib_crypt_SHA1_Init+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 - else - ac_check_lib_save_LIBS=$LIBS --LIBS="-lcrypt $LIBS" -+LIBS="-lcrypto $LIBS" - cat >conftest.$ac_ext <<_ACEOF - #line $LINENO "configure" - /* confdefs.h. */ -@@ -3275,7 +3275,7 @@ - #define HAVE_LIBCRYPT 1 - _ACEOF - -- LIBS="-lcrypt $LIBS" -+ LIBS="-lcrypto $LIBS" - - else - diff --git a/packages/ctorrent/files/crash.patch b/packages/ctorrent/files/crash.patch deleted file mode 100644 index 70ef72e6cd..0000000000 --- a/packages/ctorrent/files/crash.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff -ur ctorrent/btcontent.cpp ctorrent.new/btcontent.cpp ---- ctorrent/btcontent.cpp 2004-09-09 00:10:51.000000000 +0100 -+++ ctorrent.new/btcontent.cpp 2005-02-03 01:32:24.000000000 +0000 -@@ -226,6 +226,7 @@ - if( m_btfiles.BuildFromMI(b, flen, saveas) < 0) ERR_RETURN(); - - delete []b; -+ b = (char *)0; - PrintOut(); - - if( arg_flg_exam_only ) return 0; -diff -ur ctorrent/iplist.cpp ctorrent.new/iplist.cpp ---- ctorrent/iplist.cpp 2004-09-09 00:10:51.000000000 +0100 -+++ ctorrent.new/iplist.cpp 2005-02-08 13:02:45.000000000 +0000 -@@ -8,8 +8,8 @@ - IPLIST *node = ipl_head; - for(; ipl_head;){ - node = ipl_head; -- delete ipl_head; - ipl_head = node->next; -+ delete node; - } - count = 0; - } diff --git a/packages/ctorrent/files/extended_ctorrent.diff b/packages/ctorrent/files/extended_ctorrent.diff new file mode 100644 index 0000000000..d35c434d07 --- /dev/null +++ b/packages/ctorrent/files/extended_ctorrent.diff @@ -0,0 +1,2169 @@ +Only in ctorrent-1.3.4: README-DNH.TXT +diff -u ctorrent-1.3.4.orig/btconfig.cpp ctorrent-1.3.4/btconfig.cpp +--- ctorrent-1.3.4.orig/btconfig.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/btconfig.cpp 2005-08-11 23:45:29.424694440 +0200 +@@ -1,6 +1,7 @@ + #include <sys/types.h> + +-size_t cfg_req_slice_size = 32768; ++//size_t cfg_req_slice_size = 32768; ++size_t cfg_req_slice_size = 16384; + + size_t cfg_cache_size = 16; + +@@ -11,7 +12,8 @@ + int cfg_max_listen_port = 2706; + int cfg_min_listen_port = 2106; + +-int cfg_max_bandwidth = -1; ++int cfg_max_bandwidth_down = -1; ++int cfg_max_bandwidth_up = -1; + + time_t cfg_seed_hours = 72; + +@@ -25,6 +27,8 @@ + unsigned char arg_flg_check_only = 0; + unsigned char arg_flg_exam_only = 0; + unsigned char arg_flg_make_torrent = 0; ++unsigned char arg_file_to_download = 0; ++unsigned char arg_verbose = 0; + + size_t arg_piece_length = 262144; + char *arg_announce = (char*) 0; +diff -u ctorrent-1.3.4.orig/btconfig.h ctorrent-1.3.4/btconfig.h +--- ctorrent-1.3.4.orig/btconfig.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/btconfig.h 2005-08-11 23:45:29.425694288 +0200 +@@ -22,6 +22,8 @@ + extern time_t cfg_seed_hours; + + extern int cfg_max_bandwidth; ++extern int cfg_max_bandwidth_down; ++extern int cfg_max_bandwidth_up; + + // arguments global value + extern char *arg_metainfo_file; +@@ -33,6 +35,8 @@ + extern unsigned char arg_flg_check_only; + extern unsigned char arg_flg_exam_only; + extern unsigned char arg_flg_make_torrent; ++extern unsigned char arg_file_to_download; ++extern unsigned char arg_verbose; + + extern size_t arg_piece_length; + extern char *arg_announce; +diff -u ctorrent-1.3.4.orig/btcontent.cpp ctorrent-1.3.4/btcontent.cpp +--- ctorrent-1.3.4.orig/btcontent.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/btcontent.cpp 2005-08-11 23:45:29.425694288 +0200 +@@ -23,6 +23,7 @@ + #include "bencode.h" + #include "peer.h" + #include "httpencode.h" ++#include "tracker.h" + + #define meta_str(keylist,pstr,pint) decode_query(b,flen,(keylist),(pstr),(pint),QUERY_STR) + #define meta_int(keylist,pint) decode_query(b,flen,(keylist),(const char**) 0,(pint),QUERY_INT) +@@ -53,6 +54,7 @@ + m_announce = global_piece_buffer = (char*) 0; + m_hash_table = (unsigned char *) 0; + pBF = (BitField*) 0; ++ pBFilter = (BitField*) 0; + m_create_date = m_seed_timestamp = (time_t) 0; + time(&m_start_timestamp); + m_cache = (BTCACHE*) 0; +@@ -226,6 +228,7 @@ + if( m_btfiles.BuildFromMI(b, flen, saveas) < 0) ERR_RETURN(); + + delete []b; ++ b = (char *)0; + PrintOut(); + + if( arg_flg_exam_only ) return 0; +@@ -242,6 +245,17 @@ + if( !pBF ) ERR_RETURN(); + #endif + ++ //create the file filter ++ pBFilter = new BitField(m_npieces); ++#ifndef WINDOWS ++ if( !pBFilter ) ERR_RETURN(); ++#endif ++ if(arg_file_to_download>0){ ++ m_btfiles.SetFilter(arg_file_to_download,pBFilter,m_piece_length); ++ } ++ ++ ++ + m_left_bytes = m_btfiles.GetTotalLength() / m_piece_length; + if( m_btfiles.GetTotalLength() % m_piece_length ) m_left_bytes++; + if( m_left_bytes != m_npieces ) ERR_RETURN(); +@@ -309,7 +323,8 @@ + + ssize_t btContent::ReadSlice(char *buf,size_t idx,size_t off,size_t len) + { +- u_int64_t offset = idx * m_piece_length + off; ++ //changed ++ u_int64_t offset = (u_int64_t)idx * (u_int64_t)m_piece_length + (u_int64_t)off; + + if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 0); + else{ +@@ -405,7 +420,11 @@ + + ssize_t btContent::WriteSlice(char *buf,size_t idx,size_t off,size_t len) + { +- u_int64_t offset = (u_int64_t)(idx * m_piece_length + off); ++ //u_int64_t offset = (u_int64_t)(idx * m_piece_length + off); ++ //changed ++ u_int64_t offset = (u_int64_t)idx * (u_int64_t)m_piece_length + (u_int64_t)off; ++ ++ // printf("\nOffset-write: %lu - Piece:%lu\n",offset,(unsigned long)idx); + + if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 1); + else{ +@@ -514,9 +533,9 @@ + if( !percent ) percent = 1; + + for( ; idx < m_npieces; idx++){ +- if( GetHashValue(idx, md) == 0 && memcmp(md, m_hash_table + idx * 20, 20) == 0){ +- m_left_bytes -= GetPieceLength(idx); +- pBF->Set(idx); ++ if( GetHashValue(idx, md) == 0 && memcmp(md, m_hash_table + idx * 20, 20) == 0){ ++ m_left_bytes -= GetPieceLength(idx); ++ pBF->Set(idx); + } + if(idx % percent == 0){ + printf("\rCheck exist: %d/%d",idx,pBF->NBits()); +@@ -575,7 +594,6 @@ + fprintf(stderr,"warn,piece %d hash check failed.\n",idx); + return 0; + } +- + pBF->Set(idx); + m_left_bytes -= GetPieceLength(idx); + return 1; +@@ -592,6 +610,7 @@ + { + if( pBF->IsFull() ){ + if( !m_seed_timestamp ){ ++ Tracker.Reset(15); + Self.ResetDLTimer(); + Self.ResetULTimer(); + ReleaseHashTable(); +@@ -605,3 +624,13 @@ + } + return 0; + } ++ ++ ++size_t btContent::getFilePieces(unsigned char nfile){ ++ return m_btfiles.getFilePieces(nfile); ++} ++ ++ ++void btContent::SetFilter(){ ++ m_btfiles.SetFilter(arg_file_to_download,pBFilter,m_piece_length); ++} +diff -u ctorrent-1.3.4.orig/btcontent.h ctorrent-1.3.4/btcontent.h +--- ctorrent-1.3.4.orig/btcontent.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/btcontent.h 2005-08-11 23:45:29.426694136 +0200 +@@ -60,6 +60,7 @@ + + public: + BitField *pBF; ++ BitField *pBFilter; + char *global_piece_buffer; + + btContent(); +@@ -93,6 +94,11 @@ + + int PrintOut(); + int SeedTimeout(const time_t *pnow); ++ ++ ++ void SetFilter(); ++ size_t getFilePieces(unsigned char nfile); ++ + }; + + extern btContent BTCONTENT; +diff -u ctorrent-1.3.4.orig/btfiles.cpp ctorrent-1.3.4/btfiles.cpp +--- ctorrent-1.3.4.orig/btfiles.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/btfiles.cpp 2005-08-11 23:45:29.426694136 +0200 +@@ -105,6 +105,7 @@ + pos = (size_t) (off - (n - pbf->bf_length)); + + for(; len ;){ ++ + if( !pbf->bf_flag_opened ){ + if( _btf_open(pbf) < 0 ) return -1; + } +@@ -119,6 +120,7 @@ + if( 1 != fread(buf,nio,1,pbf->bf_fp) ) return -1; + }else{ + if( 1 != fwrite(buf,nio,1,pbf->bf_fp) ) return -1; ++ fflush(pbf->bf_fp); + } + + len -= nio; +@@ -169,7 +171,7 @@ + DIR *dp; + BTFILE *pbf; + +- if( !getwd(full_cur) ) return -1; ++ if( !getcwd(full_cur,MAXPATHLEN) ) return -1; + + if( cur_path ){ + strcpy(fn, full_cur); +@@ -293,7 +295,7 @@ + m_btfhead = pbf; + }else if( S_IFDIR & sb.st_mode ){ + char wd[MAXPATHLEN]; +- if( !getwd(wd) ) return -1; ++ if( !getcwd(wd,MAXPATHLEN) ) return -1; + m_directory = new char[strlen(pathname) + 1]; + #ifndef WINDOWS + if( !m_directory ) return -1; +@@ -488,3 +490,54 @@ + } + return 1; + } ++ ++ ++void btFiles::SetFilter(int nfile, BitField *pFilter, size_t pieceLength) ++{ ++ //set the filter ++ ++ BTFILE *p = m_btfhead; ++ size_t id = 1; ++ u_int64_t sizeBuffer=0; ++ size_t index; ++ ++ ++ pFilter->SetAll(); ++ for( ; p ; p = p->bf_next ){ ++ if(id++ == nfile){ ++ size_t start,stop; ++ start = sizeBuffer/pieceLength; ++ stop = (sizeBuffer+p->bf_length)/pieceLength; ++ printf ("\rDownloading file: <%d> %s \nPieces: %d - %d (%d)\n",nfile,p->bf_filename,start,stop,stop-start+1); ++ p->bf_npieces = stop-start+1; ++ for(index=sizeBuffer/pieceLength;index<=(sizeBuffer+p->bf_length)/pieceLength;index++){ ++ pFilter->UnSet(index); ++ } ++ } ++ sizeBuffer+=(u_int64_t) p->bf_length; ++ } ++ if(nfile>=id){ ++ printf("\nEnd of files list. Resuming normal behaviour\n"); ++ pFilter->Invert(); ++ arg_file_to_download = 0; ++ } ++} ++ ++size_t btFiles::getFilePieces(unsigned char nfile) ++{ ++ //returns the pieces of the file already gotten ++ ++ BTFILE *p = m_btfhead; ++ size_t id = 1; ++ ++ for( ; p ; p = p->bf_next ){ ++ if(id++ == nfile){ ++ return p->bf_npieces; ++ } ++ } ++return 0; ++} ++ ++ ++ ++ +diff -u ctorrent-1.3.4.orig/btfiles.h ctorrent-1.3.4/btfiles.h +--- ctorrent-1.3.4.orig/btfiles.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/btfiles.h 2005-08-11 23:45:29.427693984 +0200 +@@ -3,6 +3,10 @@ + + #include <sys/types.h> + #include <stdio.h> ++ ++#include "bitfield.h" ++extern unsigned char arg_file_to_download; ++ + #include "./def.h" + + typedef struct _btfile{ +@@ -14,6 +18,8 @@ + + size_t bf_completed; // already downloaded length + ++ size_t bf_npieces; //number of pieces ++ + unsigned char bf_flag_opened:1; + unsigned char bf_flag_need:1; + unsigned char bf_reserved:6; +@@ -53,6 +59,10 @@ + u_int64_t GetTotalLength() const { return m_total_files_length; } + ssize_t IO(char *buf, u_int64_t off, size_t len, const int iotype); + size_t FillMetaInfo(FILE* fp); ++ ++ void SetFilter(int nfile, BitField *pFilter,size_t pieceLength); ++ size_t getFilePieces(unsigned char nfile); ++ + #ifndef WINDOWS + void PrintOut(); + #endif +diff -u ctorrent-1.3.4.orig/btrequest.cpp ctorrent-1.3.4/btrequest.cpp +--- ctorrent-1.3.4.orig/btrequest.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/btrequest.cpp 2005-08-11 23:45:29.427693984 +0200 +@@ -44,6 +44,58 @@ + rq.rq_head = (PSLICE) 0; + } + ++int RequestQueue::CopyShuffle(RequestQueue &rq) ++{ ++ PSLICE ps; ++ ++ if( rq_head ) _empty_slice_list(&rq_head); ++ ++ if( rq.IsEmpty() ) return 0; ++ for (ps = rq.GetHead(); ps; ps = ps->next) { ++ if (random()&01) { ++ if (Add(ps->index, ps->offset, ps->length) < 0) return -1; ++ } ++ else if (Insert(ps->index, ps->offset, ps->length) < 0) return -1; ++ } ++ return 0; ++} ++ ++size_t RequestQueue::Qsize() ++{ ++ size_t cnt = 0; ++ PSLICE n = rq_head; ++ PSLICE u = (PSLICE) 0; ++ ++ for( ; n ; u = n,n = u->next) cnt++; // move to end ++ return cnt; ++} ++ ++int RequestQueue::Insert(size_t idx,size_t off,size_t len) ++{ ++ size_t cnt = 0; ++ PSLICE n = rq_head; ++ PSLICE u = (PSLICE) 0; ++ ++ for( ; n ; u = n,n = u->next) cnt++; // move to end (count) ++ ++ if( cnt >= cfg_req_queue_length ) return -1; // already full ++ ++ n = new SLICE; ++ ++#ifndef WINDOWS ++ if( !n ) return -1; ++#endif ++ ++ n->next = rq_head; ++ n->index = idx; ++ n->offset = off; ++ n->length = len; ++ ++ rq_head = n; ++ ++ return 0; ++} ++ + int RequestQueue::Add(size_t idx,size_t off,size_t len) + { + size_t cnt = 0; +@@ -231,3 +283,33 @@ + } + return 0; + } ++ ++int PendingQueue::Delete(size_t idx) ++{ ++ int i = 0; ++ for ( ; i < PENDING_QUEUE_SIZE && pq_count; i++){ ++ if( (PSLICE) 0 != pending_array[i] && idx == pending_array[i]->index){ ++ delete pending_array[i]; ++ pending_array[i] = (PSLICE) 0; ++ } ++ } ++ return 0; ++} ++ ++int PendingQueue::DeleteSlice(size_t idx, size_t off, size_t len) ++{ ++ int i = 0; ++ RequestQueue rq; ++ for ( ; i < PENDING_QUEUE_SIZE && pq_count; i++){ ++ if( (PSLICE) 0 != pending_array[i] && idx == pending_array[i]->index){ ++ //check if off & len match any slice ++ //remove the slice if so ++ rq.SetHead(pending_array[i]); ++ if( rq.Remove(idx, off, len) == 0 ) ++ pending_array[i] = rq.GetHead(); ++ rq.Release(); ++ } ++ } ++ return 0; ++} ++ +diff -u ctorrent-1.3.4.orig/btrequest.h ctorrent-1.3.4/btrequest.h +--- ctorrent-1.3.4.orig/btrequest.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/btrequest.h 2005-08-11 23:45:29.427693984 +0200 +@@ -31,9 +31,12 @@ + int IsValidRequest(size_t idx,size_t off,size_t len); + + void operator=(RequestQueue &rq); ++ int CopyShuffle(RequestQueue &rq); ++ size_t Qsize(); + + int IsEmpty() const { return rq_head ? 0 : 1; } + ++ int Insert(size_t idx,size_t off,size_t len); + int Add(size_t idx,size_t off,size_t len); + int Remove(size_t idx,size_t off,size_t len); + +@@ -60,6 +63,8 @@ + int Pending(RequestQueue *prq); + int ReAssign(RequestQueue *prq, BitField &bf); + int Exist(size_t idx); ++ int Delete(size_t idx); ++ int DeleteSlice(size_t idx, size_t off, size_t len); + }; + + extern PendingQueue PENDINGQUEUE; +diff -u ctorrent-1.3.4.orig/btstream.cpp ctorrent-1.3.4/btstream.cpp +--- ctorrent-1.3.4.orig/btstream.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/btstream.cpp 2005-08-11 23:45:29.428693832 +0200 +@@ -1,5 +1,6 @@ + #include <arpa/inet.h> + #include "btstream.h" ++#include "peer.h" + #include "msgencode.h" + #include "btconfig.h" + +@@ -11,7 +12,8 @@ + ssize_t btStream::Send_State(unsigned char state) + { + char msg[H_BASE_LEN + 4]; +- *(size_t*)msg = htonl(H_BASE_LEN); ++ ++ set_nl(msg, H_BASE_LEN); + msg[4] = (char)state; + return out_buffer.PutFlush(sock,msg,H_BASE_LEN + 4); + } +@@ -19,12 +21,10 @@ + ssize_t btStream::Send_Have(size_t idx) + { + char msg[H_HAVE_LEN + 4]; +- size_t *p = (size_t*)msg; + +- *p = htonl(H_HAVE_LEN); ++ set_nl(msg, H_HAVE_LEN); + msg[4] = (char)M_HAVE; +- p = (size_t*)(msg + 5); +- *p = htonl(idx); ++ set_nl(msg + 5, idx); + + return out_buffer.PutFlush(sock,msg,H_HAVE_LEN + 4); + } +@@ -43,14 +43,12 @@ + ssize_t btStream::Send_Cancel(size_t idx,size_t off,size_t len) + { + char msg[H_CANCEL_LEN + 4]; +- size_t *p = (size_t*)msg; + +- *p = htonl(H_CANCEL_LEN); ++ set_nl(msg, H_CANCEL_LEN); + msg[4] = M_CANCEL; +- p = (size_t*)(msg + 5); +- *p = htonl(idx); p++; +- *p = htonl(off); p++; +- *p = htonl(len); ++ set_nl(msg + 5, idx); ++ set_nl(msg + 9, off); ++ set_nl(msg + 13, len); + return out_buffer.Put(sock,msg,H_CANCEL_LEN + 4); + } + +@@ -72,14 +70,12 @@ + ssize_t btStream::Send_Request(size_t idx, size_t off,size_t len) + { + char msg[H_REQUEST_LEN + 4]; +- size_t *p = (size_t*) msg; + +- *p = htonl(H_REQUEST_LEN); ++ set_nl(msg, H_REQUEST_LEN); + msg[4] = (char)M_REQUEST; +- p = (size_t*)(msg + 5); +- *p = htonl(idx); p++; +- *p = htonl(off); p++; +- *p = htonl(len); ++ set_nl(msg + 5, idx); ++ set_nl(msg + 9, off); ++ set_nl(msg + 13, len); + return out_buffer.Put(sock,msg,H_REQUEST_LEN + 4); + } + +@@ -94,7 +90,7 @@ + // if message arrived. + size_t r; + if( 4 <= in_buffer.Count() ){ +- r = ntohl(*(size_t*)in_buffer.BasePointer()); ++ r = get_nl(in_buffer.BasePointer()); + if( (cfg_max_slice_size + H_PIECE_LEN + 4) < r) return -1; //message too long + if( (r + 4) <= in_buffer.Count() ) return 1; + } +diff -u ctorrent-1.3.4.orig/ctorrent.cpp ctorrent-1.3.4/ctorrent.cpp +--- ctorrent-1.3.4.orig/ctorrent.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/ctorrent.cpp 2005-08-11 23:45:29.428693832 +0200 +@@ -87,9 +87,13 @@ + Tracker.Initial(); + + signal(SIGPIPE,SIG_IGN); +- signal(SIGINT,sigint_catch); ++ signal(SIGINT,sig_catch); ++ signal(SIGTERM,sig_catch); + Downloader(); + } ++ if( cfg_cache_size ) BTCONTENT.FlushCache(); ++ if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file); ++ WORLD.CloseAll(); + + exit(0); + } +@@ -99,7 +103,7 @@ + int param_check(int argc, char **argv) + { + int c, l; +- while ( ( c = getopt(argc,argv,"b:B:cC:e:fl:M:m:P:p:s:tu:xhH")) != -1) ++ while ( ( c = getopt(argc,argv,"b:cC:D:e:fl:M:m:n:P:p:s:tu:U:vxhH")) != -1) + switch( c ){ + case 'b': + arg_bitfield_file = new char[strlen(optarg) + 1]; +@@ -150,14 +154,23 @@ + } + break; + ++ case 'n': // Which file download ++ arg_file_to_download = atoi(optarg); ++ break; ++ ++ + case 'f': // force seed mode, skip sha1 check when startup. + arg_flg_force_seed_mode = 1; + break; + +- case 'B': +- cfg_max_bandwidth = atoi(optarg); ++ case 'D': ++ cfg_max_bandwidth_down = (int)(strtod(optarg, NULL) * 1024); + break; + ++ case 'U': ++ cfg_max_bandwidth_up = (int)(strtod(optarg, NULL) * 1024); ++ break; ++ + case 'P': + l = strlen(optarg); + if (l > MAX_PF_LEN) {printf("-P arg must be 8 or less characters\n"); exit(1);} +@@ -190,6 +203,10 @@ + arg_flg_exam_only = 1; + break; + ++ case 'v': ++ arg_verbose = 1; ++ break; ++ + case 'h': + case 'H': + default: +@@ -217,6 +234,7 @@ + fprintf(stderr,"-h/-H\t\tShow this message.\n"); + fprintf(stderr,"-x\t\tDecode metainfo(torrent) file only, don't download.\n"); + fprintf(stderr,"-c\t\tCheck exist only. don't download.\n"); ++ fprintf(stderr,"-v\t\tVerbose output (for debugging).\n"); + fprintf(stderr,"\nDownload Options:\n"); + fprintf(stderr,"-e int\t\tExit while seed <int> hours later. (default 72 hours)\n"); + fprintf(stderr,"-p port\t\tListen port. (default 2706 -> 2106)\n"); +@@ -226,7 +244,9 @@ + fprintf(stderr,"-b bf_filename\tBit field filename. (use it carefully)\n"); + fprintf(stderr,"-M max_peers\tMax peers count.\n"); + fprintf(stderr,"-m min_peers\tMin peers count.\n"); +- fprintf(stderr,"-B rate\t\tMax bandwidth (unit KB/s)\n"); ++ fprintf(stderr,"-n file_number\tWhich file download.\n"); ++ fprintf(stderr,"-D rate\t\tMax bandwidth down (unit KB/s)\n"); ++ fprintf(stderr,"-U rate\t\tMax bandwidth up (unit KB/s)\n"); + fprintf(stderr,"-P peer_id\tSet Peer ID ["PEER_PFX"]\n"); + fprintf(stderr,"\nMake metainfo(torrent) file Options:\n"); + fprintf(stderr,"-t\t\tWith make torrent. must specify this option.\n"); +diff -u ctorrent-1.3.4.orig/downloader.cpp ctorrent-1.3.4/downloader.cpp +--- ctorrent-1.3.4.orig/downloader.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/downloader.cpp 2005-08-11 23:45:29.429693680 +0200 +@@ -29,10 +29,14 @@ + time_t now; + fd_set rfd; + fd_set wfd; ++ int stopped = 0; + +- for(;;){ ++ do{ + time(&now); +- if( BTCONTENT.SeedTimeout(&now) ) break; ++ if( !stopped && BTCONTENT.SeedTimeout(&now) ) { ++ Tracker.SetStoped(); ++ stopped = 1; ++ } + + FD_ZERO(&rfd); FD_ZERO(&wfd); + maxfd = Tracker.IntervalCheck(&now,&rfd, &wfd); +@@ -48,5 +52,5 @@ + if(T_FREE != Tracker.GetStatus()) Tracker.SocketReady(&rfd,&wfd,&nfds); + if( nfds ) WORLD.AnyPeerReady(&rfd,&wfd,&nfds); + } +- }/* end for(;;) */ ++ } while(Tracker.GetStatus() != T_FINISHED); + } +diff -u ctorrent-1.3.4.orig/httpencode.cpp ctorrent-1.3.4/httpencode.cpp +--- ctorrent-1.3.4.orig/httpencode.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/httpencode.cpp 2005-08-11 23:45:29.429693680 +0200 +@@ -88,7 +88,7 @@ + + /* path */ + if( *p != '/' ) return -1; +- for( ; *p && *p != '?'; p++,path++) *path = *p; ++ for( ; *p; p++,path++) *path = *p; + *path = '\0'; + return 0; + } +diff -u ctorrent-1.3.4.orig/httpencode.h ctorrent-1.3.4/httpencode.h +--- ctorrent-1.3.4.orig/httpencode.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/httpencode.h 2005-08-11 23:45:29.429693680 +0200 +@@ -2,8 +2,11 @@ + #define HTTPENCODE_H + + #define REQ_URL_P1_FMT "GET %s?info_hash=%s&peer_id=%s&port=%d" +-#define REQ_URL_P2_FMT "%s&uploaded=%d&downloaded=%d&left=%d&event=%s&compact=1 HTTP/1.0" +-#define REQ_URL_P3_FMT "%s&uploaded=%d&downloaded=%d&left=%d&compact=1 HTTP/1.0" ++//#define REQ_URL_P2_FMT "%s&uploaded=%d&downloaded=%d&left=%d&event=%s&compact=1 HTTP/1.0" ++//#define REQ_URL_P3_FMT "%s&uploaded=%d&downloaded=%d&left=%d&compact=1 HTTP/1.0" ++#define REQ_URL_P2_FMT "%s&uploaded=%llu&downloaded=%llu&left=%llu&compact=1&event=%s&numwant=%u HTTP/1.0" ++#define REQ_URL_P3_FMT "%s&uploaded=%llu&downloaded=%llu&left=%llu&compact=1&numwant=%u HTTP/1.0" ++ + + char* Http_url_encode(char *s,char *b,size_t n); + int Http_url_analyse(char *url,char *host,int *port,char *path); +diff -u ctorrent-1.3.4.orig/iplist.cpp ctorrent-1.3.4/iplist.cpp +--- ctorrent-1.3.4.orig/iplist.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/iplist.cpp 2005-08-11 23:45:29.429693680 +0200 +@@ -8,8 +8,8 @@ + IPLIST *node = ipl_head; + for(; ipl_head;){ + node = ipl_head; +- delete ipl_head; + ipl_head = node->next; ++ delete node; + } + count = 0; + } +diff -u ctorrent-1.3.4.orig/peer.cpp ctorrent-1.3.4/peer.cpp +--- ctorrent-1.3.4.orig/peer.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/peer.cpp 2005-08-11 23:45:29.431693376 +0200 +@@ -2,12 +2,34 @@ + + #include <stdlib.h> + #include <string.h> ++#include <ctype.h> + ++#include "btstream.h" + #include "./btcontent.h" + #include "./msgencode.h" + #include "./peerlist.h" + #include "./btconfig.h" + ++size_t get_nl(char *sfrom) ++{ ++ unsigned char *from = (unsigned char *)sfrom; ++ size_t t; ++ t = (*from++) << 24; ++ t |= (*from++) << 16; ++ t |= (*from++) << 8; ++ t |= *from; ++ return t; ++} ++ ++void set_nl(char *sto, size_t from) ++{ ++ unsigned char *to = (unsigned char *)sto; ++ *to++ = (from >> 24) & 0xff; ++ *to++ = (from >> 16) & 0xff; ++ *to++ = (from >> 8) & 0xff; ++ *to = from & 0xff; ++} ++ + btBasic Self; + + void btBasic::SetIp(struct sockaddr_in addr) +@@ -44,11 +66,13 @@ + + int btPeer::Need_Remote_Data() + { ++ + if( BTCONTENT.pBF->IsFull()) return 0; + else if( bitfield.IsFull() ) return 1; + else{ + BitField tmpBitfield = bitfield; + tmpBitfield.Except(*BTCONTENT.pBF); ++ tmpBitfield.Except(*BTCONTENT.pBFilter); + return tmpBitfield.IsEmpty() ? 0 : 1; + } + return 0; +@@ -65,6 +89,7 @@ + + m_err_count = 0; + m_cached_idx = BTCONTENT.GetNPieces(); ++ m_standby = 0; + } + + int btPeer::SetLocal(unsigned char s) +@@ -72,20 +97,30 @@ + switch(s){ + case M_CHOKE: + if( m_state.local_choked ) return 0; ++ time(&m_unchoke_timestamp); ++// if(arg_verbose) fprintf(stderr, "Choking %p\n", this); ++ if(arg_verbose) fprintf(stderr, "Choking %p (D=%lluMB@%uK/s)\n", this, ++ TotalDL() >> 20, RateDL() >> 10); + m_state.local_choked = 1; + break; + case M_UNCHOKE: + if( !reponse_q.IsEmpty() ) StartULTimer(); + if( !m_state.local_choked ) return 0; + time(&m_unchoke_timestamp); ++// if(arg_verbose) fprintf(stderr, "Unchoking %p\n", this); ++ if(arg_verbose) fprintf(stderr, "Unchoking %p (D=%lluMB@%uK/s)\n", this, ++ TotalDL() >> 20, RateDL() >> 10); + m_state.local_choked = 0; + break; + case M_INTERESTED: ++ m_standby = 0; + if( m_state.local_interested ) return 0; ++ if(arg_verbose) fprintf(stderr, "Interested in %p\n", this); + m_state.local_interested = 1; + break; + case M_NOT_INTERESTED: + if( !m_state.local_interested ) return 0; ++ if(arg_verbose) fprintf(stderr, "Not interested in %p\n", this); + m_state.local_interested = 0; + break; + default: +@@ -97,12 +132,15 @@ + int btPeer::RequestPiece() + { + size_t idx; ++ int endgame = 0; + + PENDINGQUEUE.ReAssign(&request_q,bitfield); + + if( !request_q.IsEmpty() ) return SendRequest(); + +- if( m_cached_idx < BTCONTENT.GetNPieces() ){ ++ if( m_cached_idx < BTCONTENT.GetNPieces() && !BTCONTENT.pBF->IsEmpty() ){ ++ // A HAVE msg already selected what we want from this peer ++ // but ignore it in initial-piece mode. + idx = m_cached_idx; + m_cached_idx = BTCONTENT.GetNPieces(); + if( !BTCONTENT.pBF->IsSet(idx) && +@@ -110,39 +148,72 @@ + !WORLD.AlreadyRequested(idx) ){ + return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest(); + } +- }else{ ++ } // If we didn't want the cached piece, select another. ++ if( BTCONTENT.pBF->IsEmpty() ){ ++ // If we don't have a complete piece yet, try to get one that's already ++ // in progress. (Initial-piece mode) ++ btPeer *peer = WORLD.Who_Can_Duplicate(this, BTCONTENT.GetNPieces()); ++ if(peer){ ++ if(arg_verbose) fprintf( stderr, "Duping: %p to %p (#%u)\n", ++ peer, this, peer->request_q.GetRequestIdx() ); ++ return (request_q.CopyShuffle(peer->request_q) < 0) ? -1 : SendRequest(); ++ } ++ } // Doesn't have a piece that's already in progress--choose another. + BitField tmpBitField; + if( bitfield.IsFull() ){ ++ // peer is a seed + tmpBitField = *BTCONTENT.pBF; + tmpBitField.Invert(); + }else{ + tmpBitField = bitfield; + tmpBitField.Except(*BTCONTENT.pBF); + } ++ // The filter tells what we don't want. ++ tmpBitField.Except(*BTCONTENT.pBFilter); ++ // tmpBitField tells what we need from this peer... + + if( !tmpBitField.IsEmpty() ){ +- WORLD.CheckBitField(tmpBitField); +- if(tmpBitField.IsEmpty()){ +- +- btPeer *peer = WORLD.Who_Can_Abandon(this); +- if(peer){ +- peer->StopDLTimer(); +- request_q = peer->request_q; +- +- if(peer->CancelRequest(request_q.GetHead()) < 0 || +- peer->RequestCheck() < 0){ +- peer->CloseConnection(); +- } +- +- return SendRequest(); +- } +- ++ BitField tmpBitField2 = tmpBitField; ++ WORLD.CheckBitField(tmpBitField2); ++ // [tmpBitField2]... that we haven't requested from anyone. ++ if(tmpBitField2.IsEmpty()){ ++ // Everything this peer has that I want, I've already requested. ++ endgame = ( WORLD.Pieces_I_Can_Get() - BTCONTENT.pBF->Count() ) ++ < WORLD.TotalPeers(); ++ if(endgame){ // OK to duplicate a request. ++// idx = tmpBitField.Random(); ++ idx = 0; // flag for Who_Can_Duplicate() ++ btPeer *peer = WORLD.Who_Can_Duplicate(this, idx); ++ if(arg_verbose) fprintf( stderr, "Duping: %p to %p (#%u)\n", ++ peer, this, peer->request_q.GetRequestIdx() ); ++ return (request_q.CopyShuffle(peer->request_q) < 0) ? ++ -1 : SendRequest(); ++ }else{ // not endgame mode ++ btPeer *peer = WORLD.Who_Can_Abandon(this); // slowest choice ++ if(peer){ ++ // Cancel a request to the slowest peer & request it from this one. ++ if(arg_verbose) fprintf( stderr, "Reassigning %p to %p (#%u)\n", ++ peer, this, peer->request_q.GetRequestIdx() ); ++ peer->StopDLTimer(); ++ // RequestQueue class "moves" rather than "copies" in assignment! ++ request_q = peer->request_q; ++ ++ if(peer->CancelRequest(request_q.GetHead()) < 0 || ++ peer->RequestCheck() < 0){ ++ peer->CloseConnection(); ++ } ++ return SendRequest(); ++ }else m_standby = 1; // nothing to do at the moment ++ } + }else{ +- idx = tmpBitField.Random(); +- return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest(); ++ // Request something that we haven't requested yet (most common case). ++ idx = tmpBitField2.Random(); ++ return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest(); + } ++ } else { ++ // We don't need anything from the peer. How'd we get here? ++ return SetLocal(M_NOT_INTERESTED); + } +- } + return 0; + } + +@@ -152,37 +223,46 @@ + + char *msgbuf = stream.in_buffer.BasePointer(); + +- r = ntohl(*(size_t*) msgbuf); ++ r = get_nl(msgbuf); + ++ // Don't require keepalives if we're receiving other messages. ++ time(&m_last_timestamp); + if( 0 == r ){ +- time(&m_last_timestamp); + if( !m_f_keepalive ) if( stream.Send_Keepalive() < 0 ) return -1; + m_f_keepalive = 0; +- return (!m_state.remote_choked && request_q.IsEmpty()) ? RequestCheck() : 0; ++ return 0; + }else{ + switch(msgbuf[4]){ + case M_CHOKE: + if(H_BASE_LEN != r){ return -1;} ++ if(arg_verbose) fprintf(stderr, "%p choked me\n", this); + m_state.remote_choked = 1; + StopDLTimer(); + if( !request_q.IsEmpty()){ + PSLICE ps = request_q.GetHead(); +- PENDINGQUEUE.Pending(&request_q); ++ if( !PENDINGQUEUE.Exist(request_q.GetRequestIdx()) ) ++ PENDINGQUEUE.Pending(&request_q); + if( CancelRequest(ps) < 0) return -1; + } + return 0; ++ + case M_UNCHOKE: + if(H_BASE_LEN != r){return -1;} ++ if(arg_verbose) fprintf(stderr, "%p unchoked me\n", this); + m_state.remote_choked = 0; ++ if(!request_q.IsEmpty()) // shouldn't happen; maybe peer is confused. ++ return SendRequest(); + return RequestCheck(); + + case M_INTERESTED: + if(H_BASE_LEN != r){return -1;} ++ if(arg_verbose) fprintf(stderr, "%p is interested\n", this); + m_state.remote_interested = 1; + break; + + case M_NOT_INTERESTED: + if(r != H_BASE_LEN){return -1;} ++ if(arg_verbose) fprintf(stderr, "%p is not interested\n", this); + + m_state.remote_interested = 0; + StopULTimer(); +@@ -190,10 +270,11 @@ + /* remove peer's reponse queue */ + if( !reponse_q.IsEmpty()) reponse_q.Empty(); + return 0; ++ + case M_HAVE: + if(H_HAVE_LEN != r){return -1;} + +- idx = ntohl(*(size_t*) (msgbuf + 5)); ++ idx = get_nl(msgbuf + 5); + + if( idx >= BTCONTENT.GetNPieces() || bitfield.IsSet(idx)) return -1; + +@@ -201,19 +282,24 @@ + + if( bitfield.IsFull() && BTCONTENT.pBF->IsFull() ){ return -2; } + +- if( !BTCONTENT.pBF->IsSet(idx) ) m_cached_idx = idx; ++ if( !BTCONTENT.pBF->IsSet(idx) && !BTCONTENT.pBFilter->IsSet(idx) ){ ++ m_cached_idx = idx; ++ m_standby = 0; ++ } ++ // if( !BTCONTENT.pBF->IsSet(idx) ) m_cached_idx = idx; + +- return ( !m_state.remote_choked && request_q.IsEmpty() ) ? RequestCheck() : 0; ++ // see if we're Interested now ++ return request_q.IsEmpty() ? RequestCheck() : 0; + + case M_REQUEST: + if(H_REQUEST_LEN != r || !m_state.remote_interested){ return -1; } + +- idx = ntohl(*(size_t*)(msgbuf + 5)); ++ idx = get_nl(msgbuf + 5); + + if( !BTCONTENT.pBF->IsSet(idx) ) return -1; + +- off = ntohl(*(size_t*)(msgbuf + 9)); +- len = ntohl(*(size_t*)(msgbuf + 13)); ++ off = get_nl(msgbuf + 9); ++ len = get_nl(msgbuf + 13); + + if( !reponse_q.IsValidRequest(idx, off, len) ) return -1; + +@@ -222,6 +308,8 @@ + case M_PIECE: + if( request_q.IsEmpty() || !m_state.local_interested){ + m_err_count++; ++ if(arg_verbose) fprintf(stderr,"err: %p (%d) Unwanted piece\n", ++ this, m_err_count); + return 0; + } + return PieceDeliver(r); +@@ -230,22 +318,28 @@ + if( (r - 1) != bitfield.NBytes() || !bitfield.IsEmpty()) return -1; + bitfield.SetReferBuffer(msgbuf + 5); + if(bitfield.IsFull() && BTCONTENT.pBF->IsFull()) return -2; +- return 0; ++ ++ //This is needed in order to set our Interested state ++ return RequestCheck(); // fixed client stall + + case M_CANCEL: + if(r != H_CANCEL_LEN || !m_state.remote_interested) return -1; + +- idx = ntohl(*(size_t*)(msgbuf + 5)); +- off = ntohl(*(size_t*)(msgbuf + 9)); +- len = ntohl(*(size_t*)(msgbuf + 13)); ++ idx = get_nl(msgbuf + 5); ++ off = get_nl(msgbuf + 9); ++ len = get_nl(msgbuf + 13); + if( reponse_q.Remove(idx,off,len) < 0 ){ + m_err_count++; ++ if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad cancel\n", ++ this, m_err_count); + return 0; + } + if( reponse_q.IsEmpty() ) StopULTimer(); + return 0; + default: +- return -1; // unknow message type ++ if(arg_verbose) fprintf(stderr, "Unknown message type %u from peer %p\n", ++ msgbuf[4], this); ++ return 0; // ignore unknown message & continue (forward compatibility) + } + } + return 0; +@@ -279,8 +373,13 @@ + int btPeer::SendRequest() + { + PSLICE ps = request_q.GetHead(); +- for( ; ps ; ps = ps->next ) ++ if(arg_verbose) fprintf(stderr, "Requesting #%u from %p:", ++ request_q.GetRequestIdx(), this); ++ for( ; ps ; ps = ps->next ){ ++ if(arg_verbose) fprintf(stderr, "."); + if(stream.Send_Request(ps->index,ps->offset,ps->length) < 0){ return -1; } ++ } ++ if(arg_verbose) fprintf(stderr, "\n"); + + return stream.Flush(); + } +@@ -294,16 +393,56 @@ + return stream.Flush(); + } + ++int btPeer::CancelSliceRequest(size_t idx, size_t off, size_t len) ++{ ++ PSLICE ps; ++ ++ for(ps = request_q.GetHead() ; ps; ps = ps->next){ ++ if( idx == ps->index && off == ps->offset && len == ps->length ){ ++ if( request_q.Remove(idx,off,len) < 0 ){ ++ m_err_count++; ++ if(arg_verbose) fprintf(stderr,"err: %p (%d) Bad CS remove\n", ++ this, m_err_count); ++ } ++ if(stream.Send_Cancel(idx,off,len) < 0) ++ return -1; ++ return stream.Flush(); ++ } ++ } ++ return 0; ++} ++ + int btPeer::ReportComplete(size_t idx) + { + if( BTCONTENT.APieceComplete(idx) ){ ++ if(arg_verbose) fprintf(stderr, "Piece #%u completed\n", idx); + WORLD.Tell_World_I_Have(idx); ++ PENDINGQUEUE.Delete(idx); + if( BTCONTENT.pBF->IsFull() ){ + ResetDLTimer(); + WORLD.CloseAllConnectionToSeed(); + } +- }else ++ ++ if( arg_file_to_download ){ ++ BitField tmpBitField = *BTCONTENT.pBF; ++ tmpBitField.Except(*BTCONTENT.pBFilter); ++ ++ while( arg_file_to_download && ++ tmpBitField.Count() >= BTCONTENT.getFilePieces(arg_file_to_download) ){ ++ //when the file is complete, we go after the next ++ ++arg_file_to_download; ++ BTCONTENT.FlushCache(); ++ BTCONTENT.SetFilter(); ++ tmpBitField = *BTCONTENT.pBF; ++ tmpBitField.Except(*BTCONTENT.pBFilter); ++ } ++ WORLD.CheckInterest(); ++ } ++ }else{ + m_err_count++; ++ if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad complete\n", ++ this, m_err_count); ++ } + return (P_FAILED == m_status) ? -1 : RequestCheck(); + } + +@@ -312,12 +451,14 @@ + size_t idx,off,len; + char *msgbuf = stream.in_buffer.BasePointer(); + +- idx = ntohl(*(size_t*) (msgbuf + 5)); +- off = ntohl(*(size_t*) (msgbuf + 9)); ++ idx = get_nl(msgbuf + 5); ++ off = get_nl(msgbuf + 9); + len = mlen - 9; + + if( request_q.Remove(idx,off,len) < 0 ){ + m_err_count++; ++ if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad remove\n", ++ this, m_err_count); + return 0; + } + +@@ -329,13 +470,21 @@ + Self.DataRecved(len); + DataRecved(len); + ++ // Check for & cancel requests for this slice from other peers in initial ++ // and endgame modes. ++ if( BTCONTENT.pBF->Count() < 2 || ++ WORLD.Pieces_I_Can_Get() - BTCONTENT.pBF->Count() < WORLD.TotalPeers() ){ ++ WORLD.CancelSlice(idx, off, len); ++ PENDINGQUEUE.DeleteSlice(idx, off, len); ++ } ++ + /* if piece download complete. */ + return request_q.IsEmpty() ? ReportComplete(idx) : 0; + } + + int btPeer::RequestCheck() + { +- if( BandWidthLimit() ) return 0; ++ if( BandWidthLimitDown() ) return 0; + + if( BTCONTENT.pBF->IsFull() ){ + if( bitfield.IsFull() ){ return -1; } +@@ -347,7 +496,8 @@ + if(request_q.IsEmpty() && !m_state.remote_choked){ + if( RequestPiece() < 0 ) return -1; + } +- } ++ } else ++ if(m_state.local_interested && SetLocal(M_NOT_INTERESTED) < 0) return -1; + + if(!request_q.IsEmpty()) StartDLTimer(); + return 0; +@@ -355,6 +505,7 @@ + + void btPeer::CloseConnection() + { ++ if(arg_verbose) fprintf(stderr, "%p closed\n", this); + if( P_FAILED != m_status ){ + m_status = P_FAILED; + stream.Close(); +@@ -364,13 +515,76 @@ + int btPeer::HandShake() + { + ssize_t r = stream.Feed(); +- if( r < 0 ) return -1; ++ if( r < 0 ){ ++// if(arg_verbose) fprintf(stderr, "hs: r<0 (%d)\n", r); ++ return -1; ++ } + else if( r < 68 ){ +- if(r && memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),r) != 0) return -1; ++ if(r >= 21){ // Ignore 8 reserved bytes following protocol ID. ++ if( memcmp(stream.in_buffer.BasePointer()+20, ++ BTCONTENT.GetShakeBuffer()+20, (r<28) ? r-20 : 8) != 0 ){ ++ if(arg_verbose){ ++ if( r>48 ) fprintf( stderr, "\npeer %p gave 0x", this); ++ else fprintf( stderr, "\npeer gave 0x" ); ++ for(int i=20; i<r && i<27; i++) fprintf(stderr, "%2.2hx", ++ (u_short)(u_char)(stream.in_buffer.BasePointer()[i])); ++ fprintf( stderr, " as reserved bytes (partial)\n" ); ++ } ++ memcpy(stream.in_buffer.BasePointer()+20, BTCONTENT.GetShakeBuffer()+20, ++ (r<28) ? r-20 : 8); ++ } ++ } ++ if(r && memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(), ++ (r<48) ? r : 48) != 0){ ++ if(arg_verbose){ ++ fprintf(stderr, "\nmine: 0x"); ++ for(int i=0; i<r && i<48; i++) fprintf(stderr, "%2.2hx", ++ (u_short)(u_char)(BTCONTENT.GetShakeBuffer()[i])); ++ fprintf(stderr, "\npeer: 0x"); ++ for(int i=0; i<r && i<48; i++) fprintf(stderr, "%2.2hx", ++ (u_short)(u_char)(stream.in_buffer.BasePointer()[i])); ++ fprintf(stderr, "\n"); ++ fprintf(stderr, "peer is %.8s\n", stream.in_buffer.BasePointer()+48); ++ } ++ return -1; ++ } + return 0; + } + +- if( memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),48) != 0 ) return -1; ++ // If the reserved bytes differ, make them the same. ++ // If they mean anything important, the handshake is likely to fail anyway. ++ if( memcmp(stream.in_buffer.BasePointer()+20, BTCONTENT.GetShakeBuffer()+20, ++ 8) != 0 ){ ++ if(arg_verbose){ ++ fprintf(stderr, "\npeer %p gave 0x", this); ++ for(int i=20; i<27; i++) fprintf(stderr, "%2.2hx", ++ (u_short)(u_char)(stream.in_buffer.BasePointer()[i])); ++ fprintf( stderr, " as reserved bytes\n" ); ++ } ++ memcpy(stream.in_buffer.BasePointer()+20, BTCONTENT.GetShakeBuffer()+20, 8); ++ } ++ if( memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),48) != 0 ){ ++ if(arg_verbose){ ++ fprintf(stderr, "\nmine: 0x"); ++ for(int i=0; i<48; i++) fprintf(stderr, "%2.2hx", ++ (u_short)(u_char)(BTCONTENT.GetShakeBuffer()[i])); ++ fprintf(stderr, "\npeer: 0x"); ++ for(int i=0; i<48; i++) fprintf(stderr, "%2.2hx", ++ (u_short)(u_char)(stream.in_buffer.BasePointer()[i])); ++ fprintf(stderr, "\n"); ++ } ++ return -1; ++ } ++ ++ if(arg_verbose){ ++ fprintf(stderr, "Peer %p ID: ", this); ++ for(int i=48; i<60; i++){ ++ if( isprint(stream.in_buffer.BasePointer()[i]) ) ++ fprintf(stderr, "%c", stream.in_buffer.BasePointer()[i]); ++ else break; ++ } ++ fprintf(stderr, "\n"); ++ } + + // ignore peer id verify + if( !BTCONTENT.pBF->IsEmpty()){ +@@ -395,10 +609,17 @@ + return stream.Send_Buffer((char*)BTCONTENT.GetShakeBuffer(),68); + } + +-int btPeer::BandWidthLimit() ++int btPeer::BandWidthLimitUp() ++{ ++ if( cfg_max_bandwidth_up <= 0 ) return 0; ++ return ((Self.RateUL()) >= cfg_max_bandwidth_up) ? ++ 1:0; ++} ++ ++int btPeer::BandWidthLimitDown() + { +- if( cfg_max_bandwidth <= 0 ) return 0; +- return ((Self.RateDL() + Self.RateUL()*2) / 1024 >= cfg_max_bandwidth) ? ++ if( cfg_max_bandwidth_down <= 0 ) return 0; ++ return ((Self.RateDL()) >= cfg_max_bandwidth_down) ? + 1:0; + } + +@@ -406,12 +627,23 @@ + { + int yn = 0; + if( stream.out_buffer.Count() || // data need send in buffer. +- (!reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimit()) || ++ (!reponse_q.IsEmpty() && CouldReponseSlice() && ! BandWidthLimitUp()) || ++ ( !m_state.remote_choked && request_q.IsEmpty() ++ && m_state.local_interested ++ && !BandWidthLimitDown() && !m_standby ) || // can request a piece. + P_CONNECTING == m_status ) // peer is connecting + yn = 1; + return yn; + } + ++int btPeer::NeedRead() ++{ ++ int yn = 1; ++ if( !request_q.IsEmpty() && BandWidthLimitDown() ) ++ yn = 0; ++ return yn; ++} ++ + int btPeer::CouldReponseSlice() + { + if(!m_state.local_choked && +@@ -453,15 +685,15 @@ + { + if( stream.out_buffer.Count() && stream.Flush() < 0) return -1; + +- if(! reponse_q.IsEmpty() && CouldReponseSlice() ) { ++ if( !reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimitUp() ) { + StartULTimer(); + Self.StartULTimer(); + } + +- for(; !reponse_q.IsEmpty() && CouldReponseSlice(); ) ++ for(; !reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimitUp(); ) + if( ReponseSlice() < 0) return -1; + +- return 0; ++ return (!m_state.remote_choked && request_q.IsEmpty()) ? RequestCheck() : 0; + } + + void btPeer::dump() +diff -u ctorrent-1.3.4.orig/peer.h ctorrent-1.3.4/peer.h +--- ctorrent-1.3.4.orig/peer.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/peer.h 2005-08-11 23:45:29.432693224 +0200 +@@ -34,6 +34,9 @@ + unsigned char reserved:4; /* unused */ + }BTSTATUS; + ++size_t get_nl(char *from); ++void set_nl(char *to, size_t from); ++ + class btBasic + { + private: +@@ -84,6 +87,7 @@ + + size_t m_cached_idx; + size_t m_err_count; ++ int m_standby; + + int PieceDeliver(size_t mlen); + int ReportComplete(size_t idx); +@@ -96,6 +100,8 @@ + int CouldReponseSlice(); + + int BandWidthLimit(); ++ int BandWidthLimitUp(); ++ int BandWidthLimitDown(); + public: + BitField bitfield; + btStream stream; +@@ -118,10 +124,12 @@ + int Is_Local_UnChoked() const { return m_state.local_choked ? 0 : 1; } + int SetLocal(unsigned char s); + ++ int CancelSliceRequest(size_t idx, size_t off, size_t len); + + void SetStatus(unsigned char s){ m_status = s; } + unsigned char GetStatus() const { return m_status; } + int NeedWrite(); ++ int NeedRead(); + + + void CloseConnection(); +diff -u ctorrent-1.3.4.orig/peerlist.cpp ctorrent-1.3.4/peerlist.cpp +--- ctorrent-1.3.4.orig/peerlist.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/peerlist.cpp 2005-08-11 23:45:29.433693072 +0200 +@@ -21,6 +21,8 @@ + #define MAX_UNCHOKE 3 + #define UNCHOKE_INTERVAL 10 + ++#define OPT_INTERVAL 30 ++ + #define KEEPALIVE_INTERVAL 117 + + #define LISTEN_PORT_MAX 2706 +@@ -36,12 +38,13 @@ + + PeerList::PeerList() + { +- m_unchoke_check_timestamp = +- m_keepalive_check_timestamp = time((time_t*) 0); ++ m_unchoke_check_timestamp = ++ m_keepalive_check_timestamp = ++ m_opt_timestamp = time((time_t*) 0); + + m_head = (PEERNODE*) 0; + m_listen_sock = INVALID_SOCKET; +- m_peers_count = 0; ++ m_peers_count = m_seeds_count = 0; + m_live_idx = 0; + } + +@@ -118,6 +121,8 @@ + + if( setfd_nonblock(sk) < 0) goto err; + ++ if(arg_verbose) fprintf(stderr, "Connecting to %s:%hu\n", ++ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + if( -1 == (r = connect_nonb(sk,(struct sockaddr*)&addr)) ) return -1; + + peer = new btPeer; +@@ -182,19 +187,44 @@ + if(NewPeer(addr,INVALID_SOCKET) == -4) break; + } + ++ + // show status line. + if( m_pre_dlrate.TimeUsed(pnow) ){ +- printf("\r "); +- printf("\r%c %u,[%u/%u/%u],%u,%u | %u,%u E:%u", ++ char partial[30] = ""; ++ if(arg_file_to_download){ ++ BitField tmpBitField = *BTCONTENT.pBF; ++ tmpBitField.Except(*BTCONTENT.pBFilter); ++ sprintf( partial, "P:%u/%u ", ++ tmpBitField.Count(), ++ BTCONTENT.getFilePieces(arg_file_to_download) ); ++ } ++ printf("\r "); ++ printf("\r%c %u/%u/%u [%u/%u/%u] %lluMB,%lluMB | %u,%uK/s | %u,%uK E:%u,%u %s%s ", + LIVE_CHAR[m_live_idx], +- m_peers_count, ++ ++ m_seeds_count, ++ m_peers_count - m_seeds_count, ++ Tracker.GetPeersCount(), ++ + BTCONTENT.pBF->Count(), + BTCONTENT.pBF->NBits(), + Pieces_I_Can_Get(), +- Self.RateDL(), Self.RateUL(), +- m_pre_dlrate.RateMeasure(Self.GetDLRate()), +- m_pre_ulrate.RateMeasure(Self.GetULRate()), +- Tracker.GetRefuseClick()); ++ ++ Self.TotalDL() >> 20, Self.TotalUL() >> 20, ++ ++ Self.RateDL() >> 10, Self.RateUL() >> 10, ++ ++ m_pre_dlrate.RateMeasure(Self.GetDLRate()) >> 10, ++ m_pre_ulrate.RateMeasure(Self.GetULRate()) >> 10, ++ ++ Tracker.GetRefuseClick(), ++ Tracker.GetOkClick(), ++ ++ partial, ++ ++ (Tracker.GetStatus()==1) ? "Connecting" : ++ ((Tracker.GetStatus()==2) ? "Connected" : "") ++ ); + fflush(stdout); + m_pre_dlrate = Self.GetDLRate(); + m_pre_ulrate = Self.GetULRate(); +@@ -214,8 +244,12 @@ + Sort(); + } + +- if( f_unchoke_check ) memset(UNCHOKER, 0, (MAX_UNCHOKE + 1) * sizeof(btPeer*)); ++ if( f_unchoke_check ) { ++ memset(UNCHOKER, 0, (MAX_UNCHOKE + 1) * sizeof(btPeer*)); ++ if (OPT_INTERVAL <= *pnow - m_opt_timestamp) m_opt_timestamp = 0; ++ } + ++ m_seeds_count = 0; + for(p = m_head; p;){ + if( PEER_IS_FAILED(p->peer)){ + if( pp ) pp->next = p->next; else m_head = p->next; +@@ -225,9 +259,11 @@ + if( pp ) p = pp->next; else p = m_head; + continue; + }else{ ++ if (p->peer->bitfield.IsFull()) m_seeds_count++; + if( f_keepalive_check ){ + + if(3 * KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp())){ ++ if(arg_verbose) fprintf(stderr, "close: keepalive expired\n"); + p->peer->CloseConnection(); + goto skip_continue; + } +@@ -235,28 +271,26 @@ + if(PEER_IS_SUCCESS(p->peer) && + KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp()) && + p->peer->AreYouOK() < 0){ ++ if(arg_verbose) fprintf(stderr, "close: keepalive death\n"); + p->peer->CloseConnection(); + goto skip_continue; + } + } + +- if( f_unchoke_check ){ +- +- if(PEER_IS_SUCCESS(p->peer) && p->peer->Need_Local_Data()){ ++ if( f_unchoke_check && PEER_IS_SUCCESS(p->peer) ){ + +- if((time_t) 0 == p->peer->GetLastUnchokeTime()){ +- if(p->peer->SetLocal(M_UNCHOKE) < 0){ +- p->peer->CloseConnection(); +- goto skip_continue; +- } +- }else ++ if( p->peer->Is_Remote_Interested() && p->peer->Need_Local_Data() ) + UnChokeCheck(p->peer, UNCHOKER); +- } ++ else if(p->peer->SetLocal(M_CHOKE) < 0){ ++ if(arg_verbose) fprintf(stderr, "close: Can't choke peer\n"); ++ p->peer->CloseConnection(); ++ goto skip_continue; ++ } + } + + sk = p->peer->stream.GetSocket(); + if(maxfd < sk) maxfd = sk; +- FD_SET(sk,rfdp); ++ if( p->peer->NeedRead() ) FD_SET(sk,rfdp); + + if( p->peer->NeedWrite() ) FD_SET(sk,wfdp); + skip_continue: +@@ -272,13 +306,26 @@ + } + + if( f_unchoke_check ){ ++// if (!m_opt_timestamp) m_opt_timestamp = *pnow; ++ if(arg_verbose) fprintf(stderr, "\nUnchoker "); ++ if (!m_opt_timestamp){ ++ if(arg_verbose) fprintf(stderr, "(opt) "); ++ m_opt_timestamp = *pnow; ++ } + for( i = 0; i < MAX_UNCHOKE + 1; i++){ + + if( (btPeer*) 0 == UNCHOKER[i]) break; + + if( PEER_IS_FAILED(UNCHOKER[i]) ) continue; + ++ if(arg_verbose){ ++ fprintf(stderr, "D=%lluMB@%uK/s:U=%lluMB ", ++ UNCHOKER[i]->TotalDL() >> 20, UNCHOKER[i]->RateDL() >> 10, ++ UNCHOKER[i]->TotalUL() >> 20); ++ if( UNCHOKER[i]->bitfield.IsEmpty() ) fprintf(stderr, "(empty) "); ++ } + if( UNCHOKER[i]->SetLocal(M_UNCHOKE) < 0){ ++ if(arg_verbose) fprintf(stderr, "close: Can't unchoke peer\n"); + UNCHOKER[i]->CloseConnection(); + continue; + } +@@ -290,6 +337,7 @@ + if( maxfd < sk) maxfd = sk; + } + } // end for ++ if(arg_verbose) fprintf(stderr, "\n"); + } + + return maxfd; +@@ -314,6 +362,64 @@ + return peer; + } + ++// Duplicating a request queue that's in progress rather than creating a new ++// one helps avoid requesting slices that we already have. ++// This takes an index parameter to facilitate modification of the function to ++// allow targeting of a specific piece. It's currently only used as a flag to ++// specify endgame or initial-piece mode though. ++btPeer* PeerList::Who_Can_Duplicate(btPeer *proposer, size_t idx) ++{ ++ PEERNODE *p; ++ btPeer *peer = (btPeer*) 0; ++ int endgame; ++ size_t qsize, mark, bench; ++ // In endgame mode, select from peers with the longest request queue. ++ // In initial mode, select from peers with the shortest non-empty request ++ // queue. ++ ++ endgame = idx < BTCONTENT.GetNPieces(); // else initial-piece mode ++ if(endgame) mark = 0; ++ else mark = cfg_req_queue_length; ++ bench = BTCONTENT.GetNPieces(); ++ ++ for(p = m_head; p; p = p->next){ ++ if(!PEER_IS_SUCCESS(p->peer) || p->peer == proposer || ++ p->peer->request_q.IsEmpty() ) continue; ++ ++ if(proposer->bitfield.IsSet(p->peer->request_q.GetRequestIdx())){ ++ qsize = p->peer->request_q.Qsize(); ++ if( (endgame && qsize > mark) || (!endgame && qsize && qsize < mark) ){ ++ mark = qsize; ++ peer = p->peer; ++ }else if( qsize == mark ){ ++ if( bench != p->peer->request_q.GetRequestIdx() && random()&01 ){ ++ bench = peer->request_q.GetRequestIdx(); ++ peer = p->peer; ++ } ++ } ++ } ++ } ++ return peer; ++} ++ ++void PeerList::CancelSlice(size_t idx, size_t off, size_t len) ++{ ++ PEERNODE *p; ++ PSLICE ps; ++ ++ for( p = m_head; p; p = p->next){ ++ ++ if( !PEER_IS_SUCCESS(p->peer) ) continue; ++ ++ if( idx == p->peer->request_q.GetRequestIdx() ) { ++ if (p->peer->CancelSliceRequest(idx,off,len) < 0) { ++ if(arg_verbose) fprintf(stderr, "close: CancelSlice\n"); ++ p->peer->CloseConnection(); ++ } ++ } ++ } ++} ++ + void PeerList::Tell_World_I_Have(size_t idx) + { + PEERNODE *p; +@@ -330,7 +436,12 @@ + + if( f_seed ){ + if( !p->peer->request_q.IsEmpty() ) p->peer->request_q.Empty(); +- if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) p->peer->CloseConnection(); ++// if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) p->peer->CloseConnection(); ++ if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) { ++ if(arg_verbose) ++ fprintf(stderr, "close: Can't set self not interested (T_W_I_H)\n"); ++ p->peer->CloseConnection(); ++ } + } + + } // end for +@@ -474,15 +585,20 @@ + FD_CLR(sk,wfdp); + + if(FD_ISSET(sk,rfdp)){ // connect failed. ++ (*nready)--; + FD_CLR(sk,rfdp); + peer->CloseConnection(); + }else{ + if(peer->Send_ShakeInfo() < 0){ ++ if(arg_verbose) fprintf(stderr, "close: Sending handshake\n"); + peer->CloseConnection(); + } + else + peer->SetStatus(P_HANDSHAKE); + } ++ }else if(FD_ISSET(sk,rfdp)){ ++ (*nready)--; ++ peer->CloseConnection(); + } + }else{ + if(FD_ISSET(sk,rfdp)){ +@@ -493,18 +609,29 @@ + (*nready)--; + FD_CLR(sk,rfdp); + if(peer->GetStatus() == P_HANDSHAKE){ +- if( peer->HandShake() < 0 ) peer->CloseConnection(); +- }else{ +- if( peer->RecvModule() < 0 ) peer->CloseConnection(); ++ if( peer->HandShake() < 0 ) { ++ if(arg_verbose) fprintf(stderr, "close: bad handshake\n"); ++ peer->CloseConnection(); ++ } ++ } // fixed client stall ++ if(peer->GetStatus() == P_SUCCESS){ ++ if( peer->RecvModule() < 0 ) { ++ if(arg_verbose) fprintf(stderr, "close: receive\n"); ++ peer->CloseConnection(); ++ } + } +- }else if(PEER_IS_SUCCESS(peer) && FD_ISSET(sk,wfdp)){ ++ } ++ if(PEER_IS_SUCCESS(peer) && FD_ISSET(sk,wfdp)){ + p->click++; + if( !(p->click) ) + for(p2 = m_head; p2; p2=p2->next) p2->click = 0; + + (*nready)--; + FD_CLR(sk,wfdp); +- if( peer->SendModule() < 0 ) peer->CloseConnection(); ++ if( peer->SendModule() < 0 ) { ++ if(arg_verbose) fprintf(stderr, "close: send\n"); ++ peer->CloseConnection(); ++ } + } + } + }// end for +@@ -514,7 +641,11 @@ + { + PEERNODE *p = m_head; + for( ; p; p = p->next) +- if(p->peer->bitfield.IsFull()) p->peer->CloseConnection(); ++// if(p->peer->bitfield.IsFull()) p->peer->CloseConnection(); ++ if(p->peer->bitfield.IsFull()) { ++ if(arg_verbose) fprintf(stderr, "close: seed<->seed\n"); ++ p->peer->CloseConnection(); ++ } + } + + void PeerList::UnChokeCheck(btPeer* peer, btPeer *peer_array[]) +@@ -523,8 +654,15 @@ + int cancel_idx = 0; + btPeer *loster = (btPeer*) 0; + int f_seed = BTCONTENT.pBF->IsFull(); ++ int no_opt = 0; ++ ++ if (m_opt_timestamp) no_opt = 1; + +- for( cancel_idx = i = 0; i < MAX_UNCHOKE; i++ ){ ++// Find my 3 or 4 fastest peers. ++// The MAX_UNCHOKE+1 (4th) slot is for the optimistic unchoke when it happens. ++ ++ // Find a slot for the candidate--the slowest peer, or an available slot. ++ for( cancel_idx = i = 0; i < MAX_UNCHOKE+no_opt; i++ ){ + if((btPeer*) 0 == peer_array[i] || PEER_IS_FAILED(peer_array[i]) ){ // 有空位 + cancel_idx = i; + break; +@@ -537,7 +675,13 @@ + cancel_idx = i; + }else{ + // compare download rate. +- if(peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL()) ++// if(peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL()) ++ if( peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL() ++ //if equal, reciprocate to the peer we've sent less to, proportionally ++ ||(peer_array[cancel_idx]->RateDL() == peer_array[i]->RateDL() ++ && peer_array[cancel_idx]->TotalUL() ++ / (peer_array[cancel_idx]->TotalDL()+.001) ++ < peer_array[i]->TotalUL() / (peer_array[i]->TotalDL()+.001)) ) + cancel_idx = i; + } + } +@@ -551,7 +695,13 @@ + }else + loster = peer; + }else{ +- if(peer->RateDL() > peer_array[cancel_idx]->RateDL()){ ++// if(peer->RateDL() > peer_array[cancel_idx]->RateDL()){ ++ if( peer->RateDL() > peer_array[cancel_idx]->RateDL() ++ // If equal, reciprocate to the peer we've sent less to, proportionally ++ ||(peer_array[cancel_idx]->RateDL() == peer->RateDL() ++ && peer_array[cancel_idx]->TotalUL() ++ / (peer_array[cancel_idx]->TotalDL()+.001) ++ > peer->TotalUL() / (peer->TotalDL()+.001)) ){ + loster = peer_array[cancel_idx]; + peer_array[cancel_idx] = peer; + }else +@@ -559,15 +709,56 @@ + } + + // opt unchoke +- if((btPeer*) 0 == peer_array[MAX_UNCHOKE] || PEER_IS_FAILED(peer_array[MAX_UNCHOKE]) ) ++ if (no_opt) { ++ if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection(); ++ } ++ else ++ // The last slot is for the optimistic unchoke. ++ // Bump the loser into it if he's been waiting longer than the occupant. ++ if((btPeer*) 0 == peer_array[MAX_UNCHOKE] || PEER_IS_FAILED(peer_array[MAX_UNCHOKE])) + peer_array[MAX_UNCHOKE] = loster; +- else{ +- if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime()) +- peer_array[MAX_UNCHOKE] = loster; +- else{ +- if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection(); ++ else { ++// if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime()) { ++ // if loser is empty and current is not, loser gets 75% chance. ++ if( loster->bitfield.IsEmpty() && !peer_array[MAX_UNCHOKE]->bitfield.IsEmpty() ++ && random()&03 ) { ++ btPeer* tmp = peer_array[MAX_UNCHOKE]; ++ peer_array[MAX_UNCHOKE] = loster; ++ loster = tmp; ++ } else // if loser waited longer: ++ if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime()) { ++ // if current is empty and loser is not, loser gets 25% chance; ++ // else loser wins. ++ // transformed to: if loser is empty or current isn't, or 25% chance, ++ // then loser wins. ++ if( !peer_array[MAX_UNCHOKE]->bitfield.IsEmpty() || loster->bitfield.IsEmpty() ++ || !random()&03 ) { ++ btPeer* tmp = peer_array[MAX_UNCHOKE]; ++ peer_array[MAX_UNCHOKE] = loster; ++ loster = tmp; ++ } + } ++ if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection(); + } + }else //else if((btPeer*) 0 != peer_array[cancel_idx]..... + peer_array[cancel_idx] = peer; + } ++ ++// When we change what we're going after, we need to evaluate & set our ++// interest with each peer appropriately. ++void PeerList::CheckInterest() ++{ ++ PEERNODE *p = m_head; ++ for( ; p; p = p->next) { ++ // Don't shortcut by checking Is_Local_Interested(), as we need to let ++ // SetLocal() reset the m_standby flag. ++ if( p->peer->Need_Remote_Data() ) { ++ if( p->peer->SetLocal(M_INTERESTED) < 0 ) ++ p->peer->CloseConnection(); ++ } else { ++ if( p->peer->SetLocal(M_NOT_INTERESTED) < 0 ) ++ p->peer->CloseConnection(); ++ } ++ } ++} ++ +diff -u ctorrent-1.3.4.orig/peerlist.h ctorrent-1.3.4/peerlist.h +--- ctorrent-1.3.4.orig/peerlist.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/peerlist.h 2005-08-11 23:45:29.434692920 +0200 +@@ -18,7 +18,8 @@ + SOCKET m_listen_sock; + PEERNODE *m_head; + size_t m_peers_count; +- time_t m_unchoke_check_timestamp, m_keepalive_check_timestamp, m_last_progress_timestamp; ++ size_t m_seeds_count; ++ time_t m_unchoke_check_timestamp, m_keepalive_check_timestamp, m_last_progress_timestamp, m_opt_timestamp; + + unsigned char m_live_idx:2; + unsigned char m_reserved:6; +@@ -50,9 +51,12 @@ + + void Tell_World_I_Have(size_t idx); + btPeer* Who_Can_Abandon(btPeer *proposer); ++ btPeer* Who_Can_Duplicate(btPeer *proposer, size_t idx); ++ void CancelSlice(size_t idx, size_t off, size_t len); + void CheckBitField(BitField &bf); + int AlreadyRequested(size_t idx); + size_t Pieces_I_Can_Get(); ++ void CheckInterest(); + }; + + extern PeerList WORLD; +diff -u ctorrent-1.3.4.orig/rate.cpp ctorrent-1.3.4/rate.cpp +--- ctorrent-1.3.4.orig/rate.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/rate.cpp 2005-08-11 23:45:29.434692920 +0200 +@@ -1,5 +1,7 @@ + #include "rate.h" + ++#define RATE_INTERVAL 20 ++ + void Rate::StartTimer() + { + if( !m_last_timestamp ) time(&m_last_timestamp); +@@ -7,7 +9,7 @@ + + void Rate::StopTimer() + { +- if( !m_last_timestamp ){ ++ if( m_last_timestamp ){ + m_total_timeused += (time((time_t*) 0) - m_last_timestamp); + m_last_timestamp = 0; + } +@@ -15,7 +17,27 @@ + + void Rate::CountAdd(size_t nbytes) + { ++ time_t now = time((time_t*) 0); ++ + m_count_bytes += nbytes; ++ ++ // save bandwidth history data ++ for (int i=0; i <= n_samples; i++) ++ { ++ if (i < MAX_SAMPLES) ++ { ++ if (now == m_timestamp_sample[i]) { ++ m_bytes_sample[i] += nbytes; ++ break; ++ } ++ else if (now - RATE_INTERVAL > m_timestamp_sample[i]) { ++ m_timestamp_sample[i] = now; ++ m_bytes_sample[i] = nbytes; ++ if (n_samples < MAX_SAMPLES) n_samples++; ++ break; ++ } ++ } ++ } + } + + void Rate::operator=(const Rate &ra) +@@ -26,17 +48,33 @@ + + size_t Rate::RateMeasure() const + { +- time_t timeused = m_total_timeused; +- if( m_last_timestamp ) timeused += (time((time_t*) 0) - m_last_timestamp); ++ // calculate rate based on bandwidth history data ++ time_t timestamp = time((time_t*) 0); ++ u_int64_t countbytes = 0; ++ time_t timeused = 0; ++ ++ if( !m_last_timestamp ) return 0; // no current rate ++ ++ timeused = (TimeUsed(×tamp) < RATE_INTERVAL) ? ++ TimeUsed(×tamp) : RATE_INTERVAL; + if( timeused < 1 ) timeused = 1; +- return (size_t)(m_count_bytes / timeused); ++ ++ for (int i=0; i<n_samples; i++) ++ { ++ if (timestamp - m_timestamp_sample[i] <= timeused) ++ countbytes += m_bytes_sample[i]; ++ } ++ return (size_t)(countbytes / timeused); + } + + size_t Rate::RateMeasure(const Rate &ra_to) const + { ++ int tmp; + time_t timeused = time((time_t*) 0) - m_last_timestamp; + if( timeused < 1 ) timeused = 1; +- return (size_t)((ra_to.m_count_bytes - m_count_bytes) / timeused); ++ tmp = (ra_to.m_count_bytes - ra_to.m_recent_base) ++ - (m_count_bytes - m_recent_base); ++ return (size_t)( (tmp>0) ? (tmp/timeused) : 0 ); + } + + time_t Rate::TimeUsed(const time_t *pnow) const +diff -u ctorrent-1.3.4.orig/rate.h ctorrent-1.3.4/rate.h +--- ctorrent-1.3.4.orig/rate.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/rate.h 2005-08-11 23:45:29.434692920 +0200 +@@ -5,14 +5,29 @@ + #include <time.h> + #include "def.h" + ++#define MAX_SAMPLES 20 ++ + class Rate{ + private: + time_t m_last_timestamp; + time_t m_total_timeused; + u_int64_t m_count_bytes; ++ u_int64_t m_recent_base; ++ ++ // bandwidth history data ++ size_t n_samples; ++ time_t m_timestamp_sample[MAX_SAMPLES]; ++ u_int64_t m_bytes_sample[MAX_SAMPLES]; ++ + public: +- Rate(){ m_last_timestamp = m_total_timeused = (time_t)0; m_count_bytes = 0; } +- void Reset(){ m_last_timestamp = m_total_timeused = (time_t)0; m_count_bytes = 0;} ++ Rate(){ m_last_timestamp = m_total_timeused = (time_t)0; ++ m_recent_base = m_count_bytes = 0; ++ n_samples=0; for(int i=0;i<MAX_SAMPLES;i++) m_timestamp_sample[i]=0; ++ } ++ void Reset(){ m_last_timestamp = m_total_timeused = (time_t)0; ++ m_recent_base = m_count_bytes; ++ n_samples = 0; for(int i=0;i<MAX_SAMPLES;i++) m_timestamp_sample[i]=0; ++ } + void StartTimer(); + void StopTimer(); + void CountAdd(size_t nbytes); +diff -u ctorrent-1.3.4.orig/sigint.cpp ctorrent-1.3.4/sigint.cpp +--- ctorrent-1.3.4.orig/sigint.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/sigint.cpp 2005-08-11 23:45:29.434692920 +0200 +@@ -4,17 +4,27 @@ + #include <signal.h> + + #include "btcontent.h" ++#include "tracker.h" + #include "peerlist.h" + #include "btconfig.h" ++#include "sigint.h" + +-void sigint_catch(int sig_no) ++void sig_catch(int sig_no) + { +- if(SIGINT == sig_no){ ++ if(SIGINT == sig_no || SIGTERM == sig_no){ ++ Tracker.SetStoped(); ++ signal(sig_no,sig_catch2); ++ } ++} ++ ++static void sig_catch2(int sig_no) ++{ ++ if(SIGINT == sig_no || SIGTERM == sig_no){ + if( cfg_cache_size ) BTCONTENT.FlushCache(); + if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file); + WORLD.CloseAll(); +- signal(SIGINT,SIG_DFL); +- raise(SIGINT); ++ signal(sig_no,SIG_DFL); ++ raise(sig_no); + } + } + +diff -u ctorrent-1.3.4.orig/sigint.h ctorrent-1.3.4/sigint.h +--- ctorrent-1.3.4.orig/sigint.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/sigint.h 2005-08-11 23:45:29.435692768 +0200 +@@ -2,7 +2,8 @@ + #define SIGINT_H + + #ifndef WINDOWS +-void sigint_catch(int sig_no); ++void sig_catch(int sig_no); ++static void sig_catch2(int sig_no); + #endif + + #endif +diff -u ctorrent-1.3.4.orig/tracker.cpp ctorrent-1.3.4/tracker.cpp +--- ctorrent-1.3.4.orig/tracker.cpp 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/tracker.cpp 2005-08-11 23:45:29.435692768 +0200 +@@ -31,11 +31,12 @@ + m_sock = INVALID_SOCKET; + m_port = 80; + m_status = T_FREE; +- m_f_started = m_f_stoped = m_f_pause = 0; ++ m_f_started = m_f_stoped = m_f_pause = m_f_completed = 0; + m_interval = 15; + + m_connect_refuse_click = 0; + m_last_timestamp = (time_t) 0; ++ m_prevpeers = 0; + } + + btTracker::~btTracker() +@@ -54,7 +55,8 @@ + + m_reponse_buffer.Reset(); + time(&m_last_timestamp); +- m_status = T_FREE; ++ if (m_f_stoped) m_status = T_FINISHED; ++ else m_status = T_FREE; + } + + int btTracker:: _IPsin(char *h, int p, struct sockaddr_in *psin) +@@ -111,6 +113,13 @@ + + if(m_interval != (time_t)i) m_interval = (time_t)i; + ++ if(decode_query(buf,bufsiz,"complete",(const char**) 0,&i,QUERY_INT)) { ++ m_peers_count = i; ++ } ++ if(decode_query(buf,bufsiz,"incomplete",(const char**) 0,&i,QUERY_INT)) { ++ m_peers_count += i; ++ } ++ + pos = decode_query(buf,bufsiz,"peers",(const char**) 0,(size_t *) 0,QUERY_POS); + + if( !pos ){ +@@ -161,7 +170,10 @@ + } + } + +- if( !cnt ) fprintf(stderr,"warn, peers list received from tracker is empty.\n"); ++ if(arg_verbose) ++ fprintf(stderr, "\nnew peers=%u; next check in %u sec\n", cnt, m_interval); ++// moved to CheckResponse--this function isn't called if no peer data. ++// if( !cnt ) fprintf(stderr,"warn, peers list received from tracker is empty.\n"); + return 0; + } + +@@ -230,10 +242,14 @@ + return 0; + } + +- if ( !pdata ) return 0; ++ if ( !pdata ){ ++ fprintf(stderr,"warn, peers list received from tracker is empty.\n"); ++ return 0; ++ } + + if( !m_f_started ) m_f_started = 1; + m_connect_refuse_click = 0; ++ m_ok_click++; + + return _UpdatePeerList(pdata,dlen); + } +@@ -329,30 +345,34 @@ + // fprintf(stdout,"Old Set Self:"); + // fprintf(stdout,"%s\n", inet_ntoa(Self.m_sin.sin_addr)); + +- if( m_f_stoped ) /* stopped */ +- event = str_event[1]; +- else if( BTCONTENT.pBF->IsFull()) /* download complete */ +- event = str_event[2]; +- else if( m_f_started ) /* interval */ +- event = (char*) 0; +- else ++ if( m_f_stoped ) ++ event = str_event[1]; /* stopped */ ++ else if( m_f_started == 0 ) { ++ if( BTCONTENT.pBF->IsFull() ) m_f_completed = 1; + event = str_event[0]; /* started */ ++ } else if( BTCONTENT.pBF->IsFull() && !m_f_completed){ ++ event = str_event[2]; /* download complete */ ++ m_f_completed = 1; /* only send download complete once */ ++ } else ++ event = (char*) 0; /* interval */ + + if(event){ + if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT, + m_path, +- (size_t)Self.TotalUL(), +- (size_t)Self.TotalDL(), +- (size_t)BTCONTENT.GetLeftBytes(), +- event)){ ++ Self.TotalUL(), ++ Self.TotalDL(), ++ BTCONTENT.GetLeftBytes(), ++ event, ++ cfg_max_peers)){ + return -1; + } + }else{ + if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P3_FMT, + m_path, +- (size_t)Self.TotalUL(), +- (size_t)Self.TotalDL(), +- (size_t)BTCONTENT.GetLeftBytes() ++ Self.TotalUL(), ++ Self.TotalDL(), ++ BTCONTENT.GetLeftBytes(), ++ cfg_max_peers + )){ + return -1; + } +@@ -380,8 +400,12 @@ + { + /* tracker communication */ + if( T_FREE == m_status ){ +- if((*pnow - m_last_timestamp >= m_interval) && +- (cfg_min_peers > WORLD.TotalPeers())){ ++// if(*pnow - m_last_timestamp >= m_interval){ ++ if(*pnow - m_last_timestamp >= m_interval || ++ // Connect to tracker early if we run out of peers. ++ (!WORLD.TotalPeers() && m_prevpeers && ++ *pnow - m_last_timestamp >= 15) ){ ++ m_prevpeers = WORLD.TotalPeers(); + + if(Connect() < 0){ Reset(15); return -1; } + +@@ -396,7 +420,7 @@ + if( m_status == T_CONNECTING ){ + FD_SET(m_sock, rfdp); + FD_SET(m_sock, wfdp); +- }else{ ++ }else if (INVALID_SOCKET != m_sock){ + FD_SET(m_sock, rfdp); + } + } +@@ -425,7 +449,7 @@ + if( SendRequest() == 0 ) m_status = T_READY; + else { Reset(15); return -1; } + } +- }else if(FD_ISSET(m_sock, rfdp) ){ ++ }else if(INVALID_SOCKET != m_sock && FD_ISSET(m_sock, rfdp) ){ + (*nfds)--; + FD_CLR(m_sock,rfdp); + CheckReponse(); +diff -u ctorrent-1.3.4.orig/tracker.h ctorrent-1.3.4/tracker.h +--- ctorrent-1.3.4.orig/tracker.h 2004-09-09 01:10:51.000000000 +0200 ++++ ctorrent-1.3.4/tracker.h 2005-08-11 23:45:29.436692616 +0200 +@@ -21,6 +21,7 @@ + #define T_FREE 0 + #define T_CONNECTING 1 + #define T_READY 2 ++#define T_FINISHED 3 + + class btTracker + { +@@ -34,15 +35,20 @@ + unsigned char m_status:2; + unsigned char m_f_started:1; + unsigned char m_f_stoped:1; ++ unsigned char m_f_completed:1; + + unsigned char m_f_pause:1; +- unsigned char m_f_reserved:3; ++ unsigned char m_f_reserved:2; + + + time_t m_interval; // 与Tracker通信的时间间隔 + time_t m_last_timestamp; // 最后一次成功与Tracker通信的时间 + size_t m_connect_refuse_click; + ++ size_t m_ok_click; // tracker ok response counter ++ size_t m_peers_count; // total number of peers ++ size_t m_prevpeers; // number of peers previously seen ++ + SOCKET m_sock; + BufIo m_reponse_buffer; + +@@ -66,6 +72,8 @@ + void SetPause() { m_f_pause = 1; } + void ClearPause() { m_f_pause = 0; } + ++ void SetStoped() { Reset(15); m_f_stoped = 1; m_last_timestamp -= 15;} ++ + int Connect(); + int SendRequest(); + int CheckReponse(); +@@ -73,6 +81,8 @@ + int SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds); + + size_t GetRefuseClick() const { return m_connect_refuse_click; } ++ size_t GetOkClick() const { return m_ok_click; } ++ size_t GetPeersCount() const { return m_peers_count; } + }; + + extern btTracker Tracker; diff --git a/packages/ctorrent/files/fmt.patch b/packages/ctorrent/files/fmt.patch deleted file mode 100644 index 2c4a7440a7..0000000000 --- a/packages/ctorrent/files/fmt.patch +++ /dev/null @@ -1,42 +0,0 @@ -diff -ur new.x86/httpencode.h new/httpencode.h ---- new.x86/httpencode.h 2004-09-09 00:10:51.000000000 +0100 -+++ new/httpencode.h 2005-02-01 18:13:59.936139832 +0000 -@@ -2,8 +2,8 @@ - #define HTTPENCODE_H - - #define REQ_URL_P1_FMT "GET %s?info_hash=%s&peer_id=%s&port=%d" --#define REQ_URL_P2_FMT "%s&uploaded=%d&downloaded=%d&left=%d&event=%s&compact=1 HTTP/1.0" --#define REQ_URL_P3_FMT "%s&uploaded=%d&downloaded=%d&left=%d&compact=1 HTTP/1.0" -+#define REQ_URL_P2_FMT "%s&uploaded=%llu&downloaded=%llu&left=%llu&event=%s&compact=1 HTTP/1.0" -+#define REQ_URL_P3_FMT "%s&uploaded=%llu&downloaded=%llu&left=%llu&compact=1 HTTP/1.0" - - char* Http_url_encode(char *s,char *b,size_t n); - int Http_url_analyse(char *url,char *host,int *port,char *path); -diff -ur new.x86/tracker.cpp new/tracker.cpp ---- new.x86/tracker.cpp 2005-02-01 17:34:43.588359144 +0000 -+++ new/tracker.cpp 2005-02-01 18:14:58.632216672 +0000 -@@ -360,18 +345,18 @@ - if(event){ - if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT, - m_path, -- (size_t)Self.TotalUL(), -- (size_t)Self.TotalDL(), -- (size_t)BTCONTENT.GetLeftBytes(), -+ Self.TotalUL(), -+ Self.TotalDL(), -+ BTCONTENT.GetLeftBytes(), - event)){ - return -1; - } - }else{ - if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P3_FMT, - m_path, -- (size_t)Self.TotalUL(), -- (size_t)Self.TotalDL(), -- (size_t)BTCONTENT.GetLeftBytes() -+ Self.TotalUL(), -+ Self.TotalDL(), -+ BTCONTENT.GetLeftBytes() - )){ - return -1; - } diff --git a/packages/ctorrent/files/nogetwd.patch b/packages/ctorrent/files/nogetwd.patch deleted file mode 100644 index d150521cca..0000000000 --- a/packages/ctorrent/files/nogetwd.patch +++ /dev/null @@ -1,34 +0,0 @@ -Index: ctorrent-1.3.4/btfiles.cpp -=================================================================== ---- ctorrent-1.3.4.orig/btfiles.cpp 2004-09-08 18:10:51.000000000 -0500 -+++ ctorrent-1.3.4/btfiles.cpp 2005-02-10 17:27:55.000000000 -0600 -@@ -169,7 +169,7 @@ - DIR *dp; - BTFILE *pbf; - -- if( !getwd(full_cur) ) return -1; -+ if( !getcwd(full_cur, MAXPATHLEN) ) return -1; - - if( cur_path ){ - strcpy(fn, full_cur); -@@ -293,7 +293,7 @@ - m_btfhead = pbf; - }else if( S_IFDIR & sb.st_mode ){ - char wd[MAXPATHLEN]; -- if( !getwd(wd) ) return -1; -+ if( !getcwd(wd, MAXPATHLEN) ) return -1; - m_directory = new char[strlen(pathname) + 1]; - #ifndef WINDOWS - if( !m_directory ) return -1; -Index: ctorrent-1.3.4/configure.ac -=================================================================== ---- ctorrent-1.3.4.orig/configure.ac 2004-09-08 18:10:51.000000000 -0500 -+++ ctorrent-1.3.4/configure.ac 2005-02-10 17:28:03.000000000 -0600 -@@ -32,6 +32,6 @@ - AC_FUNC_MEMCMP - AC_TYPE_SIGNAL - AC_FUNC_STAT --AC_CHECK_FUNCS([ftruncate gethostbyname gettimeofday getwd inet_ntoa memchr memmove memset mkdir select socket strchr strerror strncasecmp strstr strtol strnstr]) -+AC_CHECK_FUNCS([ftruncate gethostbyname gettimeofday getcwd inet_ntoa memchr memmove memset mkdir select socket strchr strerror strncasecmp strstr strtol strnstr]) - - AC_OUTPUT(Makefile) diff --git a/packages/ctorrent/files/passkey.patch b/packages/ctorrent/files/passkey.patch deleted file mode 100644 index 3debc44599..0000000000 --- a/packages/ctorrent/files/passkey.patch +++ /dev/null @@ -1,16 +0,0 @@ -*** ctorrent/httpencode.cpp.orig Thu Sep 9 01:10:51 2004 ---- ctorrent/httpencode.cpp Thu Aug 4 15:00:45 2005 -*************** -*** 88,94 **** ---- 88,98 ---- - - /* path */ - if( *p != '/' ) return -1; -+ #if 1 /* The passkey patch */ -+ for( ; *p; p++,path++) *path = *p; -+ #else - for( ; *p && *p != '?'; p++,path++) *path = *p; -+ #endif - *path = '\0'; - return 0; - } diff --git a/packages/ctorrent/files/stall.patch b/packages/ctorrent/files/stall.patch deleted file mode 100644 index f81f000921..0000000000 --- a/packages/ctorrent/files/stall.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --exclude '*Po' -ur ctorrent/peer.cpp ctorrent.new/peer.cpp ---- ctorrent/peer.cpp 2005-02-10 18:27:44.980091472 +0000 -+++ ctorrent.new/peer.cpp 2005-02-03 17:55:01.000000000 +0000 -@@ -252,7 +252,8 @@ - if( (r - 1) != bitfield.NBytes() || !bitfield.IsEmpty()) return -1; - bitfield.SetReferBuffer(msgbuf + 5); - if(bitfield.IsFull() && BTCONTENT.pBF->IsFull()) return -2; -- return 0; -+ -+ return RequestCheck(); - - case M_CANCEL: - if(r != H_CANCEL_LEN || !m_state.remote_interested) return -1; -diff --exclude '*Po' -ur ctorrent/peerlist.cpp ctorrent.new/peerlist.cpp ---- ctorrent/peerlist.cpp 2004-09-09 00:10:51.000000000 +0100 -+++ ctorrent.new/peerlist.cpp 2005-02-02 00:23:04.000000000 +0000 -@@ -495,7 +496,9 @@ - if(peer->GetStatus() == P_HANDSHAKE){ - if( peer->HandShake() < 0 ) peer->CloseConnection(); - }else{ -- if( peer->RecvModule() < 0 ) peer->CloseConnection(); -+ if(peer->GetStatus() == P_SUCCESS) { -+ if( peer->RecvModule() < 0 ) peer->CloseConnection(); -+ } - } - }else if(PEER_IS_SUCCESS(peer) && FD_ISSET(sk,wfdp)){ - p->click++; diff --git a/packages/ctorrent/files/tracker.patch b/packages/ctorrent/files/tracker.patch deleted file mode 100644 index 4d9a0d4973..0000000000 --- a/packages/ctorrent/files/tracker.patch +++ /dev/null @@ -1,175 +0,0 @@ -diff -ur ctorrent-1.3.4/ctorrent.cpp new/ctorrent.cpp ---- ctorrent-1.3.4/ctorrent.cpp 2005-01-26 00:40:07.747876016 +0000 -+++ new/ctorrent.cpp 2005-01-25 01:34:16.000000000 +0000 -@@ -87,9 +87,13 @@ - Tracker.Initial(); - - signal(SIGPIPE,SIG_IGN); -- signal(SIGINT,sigint_catch); -+ signal(SIGINT,sig_catch); -+ signal(SIGTERM,sig_catch); - Downloader(); - } -+ if( cfg_cache_size ) BTCONTENT.FlushCache(); -+ if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file); -+ WORLD.CloseAll(); - - exit(0); - } -diff -ur ctorrent-1.3.4/downloader.cpp new/downloader.cpp ---- ctorrent-1.3.4/downloader.cpp 2005-01-26 00:40:07.748875864 +0000 -+++ new/downloader.cpp 2005-01-24 19:29:18.000000000 +0000 -@@ -30,9 +30,9 @@ - fd_set rfd; - fd_set wfd; - -- for(;;){ -+ do{ - time(&now); -- if( BTCONTENT.SeedTimeout(&now) ) break; -+ if( BTCONTENT.SeedTimeout(&now) ) Tracker.SetStoped(); - - FD_ZERO(&rfd); FD_ZERO(&wfd); - maxfd = Tracker.IntervalCheck(&now,&rfd, &wfd); -@@ -48,5 +48,5 @@ - if(T_FREE != Tracker.GetStatus()) Tracker.SocketReady(&rfd,&wfd,&nfds); - if( nfds ) WORLD.AnyPeerReady(&rfd,&wfd,&nfds); - } -- }/* end for(;;) */ -+ } while(Tracker.GetStatus() != T_FINISHED); - } -diff -ur ctorrent-1.3.4/sigint.cpp new/sigint.cpp ---- ctorrent-1.3.4/sigint.cpp 2005-01-26 00:40:07.749875712 +0000 -+++ new/sigint.cpp 2005-01-26 00:39:48.175851416 +0000 -@@ -4,17 +4,27 @@ - #include <signal.h> - - #include "btcontent.h" -+#include "tracker.h" - #include "peerlist.h" - #include "btconfig.h" -+#include "sigint.h" - --void sigint_catch(int sig_no) -+void sig_catch(int sig_no) - { -- if(SIGINT == sig_no){ -+ if(SIGINT == sig_no || SIGTERM == sig_no){ -+ Tracker.SetStoped(); -+ signal(sig_no,sig_catch2); -+ } -+} -+ -+static void sig_catch2(int sig_no) -+{ -+ if(SIGINT == sig_no || SIGTERM == sig_no){ - if( cfg_cache_size ) BTCONTENT.FlushCache(); - if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file); - WORLD.CloseAll(); -- signal(SIGINT,SIG_DFL); -- raise(SIGINT); -+ signal(sig_no,SIG_DFL); -+ raise(sig_no); - } - } - -diff -ur ctorrent-1.3.4/sigint.h new/sigint.h ---- ctorrent-1.3.4/sigint.h 2005-01-26 00:40:07.749875712 +0000 -+++ new/sigint.h 2005-01-25 01:30:11.000000000 +0000 -@@ -2,7 +2,8 @@ - #define SIGINT_H - - #ifndef WINDOWS --void sigint_catch(int sig_no); -+void sig_catch(int sig_no); -+static void sig_catch2(int sig_no); - #endif - - #endif -diff -ur ctorrent-1.3.4/tracker.cpp new/tracker.cpp ---- ctorrent-1.3.4/tracker.cpp 2005-01-26 00:40:07.751875408 +0000 -+++ new/tracker.cpp 2005-01-26 00:38:52.828265528 +0000 -@@ -31,7 +31,7 @@ - m_sock = INVALID_SOCKET; - m_port = 80; - m_status = T_FREE; -- m_f_started = m_f_stoped = m_f_pause = 0; -+ m_f_started = m_f_stoped = m_f_pause = m_f_completed = 0; - m_interval = 15; - - m_connect_refuse_click = 0; -@@ -54,7 +54,8 @@ - - m_reponse_buffer.Reset(); - time(&m_last_timestamp); -- m_status = T_FREE; -+ if (m_f_stoped) m_status = T_FINISHED; -+ else m_status = T_FREE; - } - - int btTracker:: _IPsin(char *h, int p, struct sockaddr_in *psin) -@@ -329,14 +332,15 @@ - // fprintf(stdout,"Old Set Self:"); - // fprintf(stdout,"%s\n", inet_ntoa(Self.m_sin.sin_addr)); - -- if( m_f_stoped ) /* stopped */ -- event = str_event[1]; -- else if( BTCONTENT.pBF->IsFull()) /* download complete */ -- event = str_event[2]; -- else if( m_f_started ) /* interval */ -- event = (char*) 0; -- else -+ if( m_f_stoped ) -+ event = str_event[1]; /* stopped */ -+ else if( m_f_started == 0 ) - event = str_event[0]; /* started */ -+ else if( BTCONTENT.pBF->IsFull() && !m_f_completed){ -+ event = str_event[2]; /* download complete */ -+ m_f_completed = 1; /* only send download complete once */ -+ } else -+ event = (char*) 0; /* interval */ - - if(event){ - if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT, -@@ -380,8 +390,7 @@ - { - /* tracker communication */ - if( T_FREE == m_status ){ -- if((*pnow - m_last_timestamp >= m_interval) && -- (cfg_min_peers > WORLD.TotalPeers())){ -+ if(*pnow - m_last_timestamp >= m_interval){ - - if(Connect() < 0){ Reset(15); return -1; } - -diff -ur ctorrent-1.3.4/tracker.h new/tracker.h ---- ctorrent-1.3.4/tracker.h 2005-01-26 00:40:07.752875256 +0000 -+++ new/tracker.h 2005-01-26 00:38:21.003103688 +0000 -@@ -21,6 +21,7 @@ - #define T_FREE 0 - #define T_CONNECTING 1 - #define T_READY 2 -+#define T_FINISHED 3 - - class btTracker - { -@@ -34,9 +35,10 @@ - unsigned char m_status:2; - unsigned char m_f_started:1; - unsigned char m_f_stoped:1; -+ unsigned char m_f_completed:1; - - unsigned char m_f_pause:1; -- unsigned char m_f_reserved:3; -+ unsigned char m_f_reserved:2; - - - time_t m_interval; // 与Tracker通信的时间间隔 -@@ -66,6 +68,8 @@ - void SetPause() { m_f_pause = 1; } - void ClearPause() { m_f_pause = 0; } - -+ void SetStoped() { Reset(15); m_f_stoped = 1;} -+ - int Connect(); - int SendRequest(); - int CheckReponse(); |