Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 72782 Details for
Bug 112352
enhanced ctorrent patch dnh1.1 release
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Release dnh1
patchset-ctorrent-1.3.4-dnh1.diff (text/plain), 72.43 KB, created by
René Wilhelm
on 2005-11-12 17:12:12 UTC
(
hide
)
Description:
Release dnh1
Filename:
MIME Type:
Creator:
René Wilhelm
Created:
2005-11-12 17:12:12 UTC
Size:
72.43 KB
patch
obsolete
>--- /dev/null Thu Jul 28 14:22:03 2005 >+++ README-DNH.TXT Sat Jul 16 10:47:30 2005 >@@ -0,0 +1,232 @@ >+Please see http://www.rahul.net/dholmes/ctorrent/ for the latest version >+of this information. >+ >+ Enhanced CTorrent >+ >+ [ [1]Info | [2]Notes | [3]Changes | [4]Download | [5]Resources | >+ [6]Contact ] >+ >+Information >+ >+ [7]CTorrent is a [8]BitTorrent client implemented in C++ to be >+ lightweight and quick. It has fallen a little behind in updates and >+ bug fixes though. >+ >+ The files here contain the good work of those who wrote the original >+ CTorrent base code and a number of patches that provide fixes and >+ enhancements, as well as additional fixes and enhancements that I am >+ contributing. I am not the original author, current maintainer, or any >+ other official representative of CTorrent. The files on this page are >+ not the original or official CTorrent distribution. I encourage you to >+ visit the [9]CTorrent project page on SourceForge for further >+ information. >+ >+Notes >+ >+ Use of the -P option (or changing the peer ID in btconfig.h) is >+ recommended, as some other clients and trackers assume that Ctorrent >+ is "buggy" and won't cooperate with it. [Guess what, there are plenty >+ of others with bugs too.] It isn't necessary to impersonate another >+ known client; just changing or adding one letter or number should be >+ sufficient. >+ >+Changes for "dnh1" Release >+ >+ Patches >+ * Incorporates the following patches. The number is the Request ID >+ from the [10]SourceForge patches page, which you can reference for >+ the details of each patch. The name in brackets is the name of the >+ patch file or a name I chose to refer to the patch. Some of these >+ names are used below (in brackets) to describe a fix or change to >+ a particular patch. >+ 1042808 [getcwd] (incorporated in get1file patch) >+ 1084776 [passkey] (incorporated in udlimit patch) >+ 1109266 [align] >+ 1109287 [tracker/tracker2] >+ 1114197 [fmt] (incorporated in get1file patch) >+ 1114364 [resetdl] >+ 1116448 [get1file] >+ 1118597 [crash] >+ 1119467 [stall] >+ 1119492 [rate] >+ 1119497 [flush] >+ 1119519 [opt] >+ 1119689 [status] >+ 1124342 [udlimit] >+ >+ Download performance >+ * If a peer socket is ready for reading and writing, perform both. >+ Previously the cases were exclusive, with preference given to >+ reading. >+ * Download requests are now made to peers when they are ready for >+ writing (in addition to the existing event-driven cases). This >+ fixes peer stalls when a request couldn't be sent in an >+ event-triggered case due to bandwidth limiting or other >+ circumstances. >+ * Additional tests added so that the above request checking doesn't >+ create hard loops. >+ >+ Bandwidth measurement/management >+ * [rate] Bandwidth reporting is now not capped. Also, only the time >+ used for the samples taken is used in the calculation rather than >+ the maximum interval (this affects rate calculation for individual >+ peers). >+ * Additional upload and download bandwidth limit checks added so >+ that bw management is more accurate. >+ * Corrected condition inversion bug in Rate::StopTimer(), which >+ affects peer rate calculations. >+ >+ Peer count >+ * Request our max number of peers from the tracker each time rather >+ than just taking the tracker's default, so we can try to fill up. >+ * The tracker will be contacted early if all peers disconnect so >+ that we can actively try to establish some more peer connections. >+ To avoid hammering the tracker, we must have at least one peer for >+ 15 seconds in order for this to be invoked. >+ * Some clients use nonzero bytes in the "reserved" part of the >+ handshake. Added code to ignore the reserved bytes if the rest of >+ the handshake is as expected. This includes Azureus 2300 thru 2304 >+ (latest) which gives 0x80 as the first reserved byte and BitComet >+ which gives 0x6578 ("ex") as the first two bytes. >+ * Update peer's timestamp on any message, not just keepalives. Any >+ receipt of data from a peer now resets its timeout, preventing >+ early disconnect. >+ >+ Parallel requests >+ * Initial-piece and endgame cases have been improved so that pieces >+ will be requested from multiple peers. Cancels are sent as slices >+ (subpieces) are received. This endgame strategy is described in >+ the BitTorrent online spec. The startup strategy is also described >+ in posts and facilitates obtaining a single piece more rapidly in >+ order to obtain some trade value. In initial mode, the piece of >+ which we need the least parts is targeted. In endgame mode, the >+ piece of which we need the most parts is targeted. Slices that are >+ cancelled are also removed from the "pending" queue, as are pieces >+ that are completed. >+ * When duplicating a piece request, the slice request order is also >+ shuffled in order to minimize duplication of effort. >+ >+ Tracker info >+ * [status] Seems to be missing tracker.cpp diff. Added code to get >+ tracker's total peers, but not all trackers report these fields in >+ the normal response. Also added code to count successful updates >+ from the tracker. >+ * Added tracker connection state to status line (when >+ connecting/connected). >+ >+ Tracker contact >+ * When interrupting (ctrl-C), connect to the tracker immediately >+ rather than waiting 15 seconds. >+ * Contact tracker "soon" after transitioning to seeder state. >+ >+ Peer interaction >+ * Manage our interested state for each peer dynamically as content >+ changes. >+ * Unchoking >+ + Use the peer's interested state (confirming via the bitfield >+ that it needs our data) to consider unchoking. Using only the >+ bitfield could cause us to waste an upload slot on a peer >+ that doesn't have all content but isn't interested (like a >+ single-file downloader). >+ + Choke peers that become uninterested or don't need our data. >+ + Try unchoking new peers only as slots open or the optimistic >+ unchoke rotates. Unchoking too many peers can temporarily >+ reduce per-peer upload rates, which would make uploading to >+ us unappealing for good peers. >+ + In a tie for download speed, prefer to unchoke the peer to >+ whom we've uploaded the least data relative to what we've >+ downloaded from him. >+ * Optimistic unchoking >+ + Fixed condition inversion bug causing opt unchoking to occur >+ too often. >+ + A peer who has no pieces is now preferred 75% vs. a peer who >+ already has at least one piece, in order to help the new peer >+ become productive. This is documented in the online spec. >+ + Set peer's last-unchoke-time when choking the peer to get >+ better rotation of the optimistic unchoke. The value is now >+ the last time that a peer was in the unchoked state rather >+ than the time of the last unchoke event. >+ >+ Miscellaneous items >+ * [tracker] Fixed normal program end (stop) process, which was >+ crashing. >+ * [get1file] Restore compact tracker response support. >+ * [get1file] Made display of the status line info dependent on >+ whether the option is in use. >+ * [get1file] Apply the filter when checking for what we need from a >+ peer instead of when recording what the peer has; this prevents >+ stalls when we move on to the next file. Update interested state >+ for each peer when we begin a new file. Also move the file-done >+ check into the piece completion code and check whether the next >+ file(s) has also been completed. >+ * Reduced the slice size from 32K to 16K (same as BT & Azureus). >+ This provides more precise DL rate measurement, and helps insure >+ that we receive a productive amount of data (i.e. a complete >+ slice) even if we are unchoked by a peer for only one cycle. See >+ [11]http://groups.yahoo.com/group/BitTorrent/message/1260 for more >+ discussion/analysis on this. >+ * Added -v (verbose) option for additional debugging output. >+ >+Download >+ >+ [12]FreeBSD patch file >+ A patch file of changes to the CTorrent 1.3.4 base, including the >+ patches from the FreeBSD ports tree. >+ >+ [13]Patch file >+ A patch file of changes to the CTorrent 1.3.4 base. >+ >+ [14]FreeBSD patched source >+ This includes the patches from the FreeBSD ports tree. >+ >+ [15]Linux/Windows/Other patched source >+ Please [16]let me know if you encounter any portability issues, as I >+ don't have a test environment set up for these platforms. >+ >+Resources >+ >+ [17]CTorrent Home Page >+ Outdated, but you may find some useful info (particularly the FAQ). >+ >+ [18]CTorrent SourceForge Project >+ Hosts the CTorrent codebase, bug reports, patches, and forum. >+ >+ [19]Custom CTorrent >+ A page by the author of the "get1file" patch and other fixes. It >+ contains a custom version and a GUI for CTorrent. >+ >+ [20]BitTorrent >+ The official BitTorrent home page. >+ >+ [21]BitTorrent wiki >+ Various documentation. >+ >+ [22]BitTorrent protocol specification (official version) >+ >+ [23]BitTorrent protocol specification (wiki version) >+ >+References >+ >+ 1. http://www.rahul.net/dholmes/ctorrent/index.html#info >+ 2. http://www.rahul.net/dholmes/ctorrent/index.html#notes >+ 3. http://www.rahul.net/dholmes/ctorrent/index.html#changes >+ 4. http://www.rahul.net/dholmes/ctorrent/index.html#download >+ 5. http://www.rahul.net/dholmes/ctorrent/index.html#resources >+ 6. mailto:dholmes@ct.boxmail.com >+ 7. http://ctorrent.sourceforge.net/ >+ 8. http://www.bittorrent.com/ >+ 9. http://sourceforge.net/projects/ctorrent/ >+ 10. http://sourceforge.net/tracker/?atid=598034&group_id=91688&func=browse >+ 11. http://groups.yahoo.com/group/BitTorrent/message/1260 >+ 12. http://www.rahul.net/dholmes/ctorrent/ctorrent-dnh1-fbsd.diff >+ 13. http://www.rahul.net/dholmes/ctorrent/ctorrent-dnh1.diff >+ 14. http://www.rahul.net/dholmes/ctorrent/ctorrent-dnh1-fbsd.tar.gz >+ 15. http://www.rahul.net/dholmes/ctorrent/ctorrent-dnh1.tar.gz >+ 16. mailto:dholmes@ct.boxmail.com >+ 17. http://ctorrent.sourceforge.net/ >+ 18. http://sourceforge.net/projects/ctorrent/ >+ 19. http://customctorrent.ifreepages.com/ >+ 20. http://bittorrent.com/ >+ 21. http://wiki.theory.org/CategoryBitTorrent >+ 22. http://www.bittorrent.com/protocol.html >+ 23. http://wiki.theory.org/BitTorrentSpecification >--- btconfig.cpp.orig Wed Sep 8 16:10:51 2004 >+++ btconfig.cpp Mon Jul 11 20:19:00 2005 >@@ -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; >--- btconfig.h.orig Wed Sep 8 16:10:51 2004 >+++ btconfig.h Thu Jul 7 19:38:00 2005 >@@ -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; >--- btcontent.cpp.orig Wed Sep 8 16:10:51 2004 >+++ btcontent.cpp Wed Jul 13 20:18:42 2005 >@@ -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(); >@@ -604,4 +623,14 @@ > if( (*pnow - m_seed_timestamp) >= (cfg_seed_hours * 60 * 60) ) return 1; > } > 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); > } >--- btcontent.h.orig Wed Sep 8 16:10:51 2004 >+++ btcontent.h Thu Jun 2 20:27:00 2005 >@@ -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; >--- btfiles.cpp.orig Wed Sep 8 16:10:51 2004 >+++ btfiles.cpp Thu Jun 2 20:27:00 2005 >@@ -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; >+} >+ >+ >+ >+ >--- btfiles.h.orig Wed Sep 8 16:10:51 2004 >+++ btfiles.h Thu Jun 2 20:27:00 2005 >@@ -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 >--- btrequest.cpp.orig Wed Sep 8 16:10:51 2004 >+++ btrequest.cpp Wed Jul 13 20:19:06 2005 >@@ -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; >+} >+ >--- btrequest.h.orig Wed Sep 8 16:10:51 2004 >+++ btrequest.h Wed Jul 13 20:16:57 2005 >@@ -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; >--- btstream.cpp.orig Wed Sep 8 16:10:51 2004 >+++ btstream.cpp Tue Jun 21 20:48:00 2005 >@@ -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; > } >--- ctorrent.cpp.orig Wed Sep 8 16:10:51 2004 >+++ ctorrent.cpp Thu Jul 7 23:07:00 2005 >@@ -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"); >--- downloader.cpp.orig Wed Sep 8 16:10:51 2004 >+++ downloader.cpp Thu Jun 9 20:26:00 2005 >@@ -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); > } >--- httpencode.cpp.orig Wed Sep 8 16:10:51 2004 >+++ httpencode.cpp Thu Jun 2 20:27:00 2005 >@@ -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; > } >--- httpencode.h.orig Wed Sep 8 16:10:51 2004 >+++ httpencode.h Mon Jun 20 21:16:00 2005 >@@ -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); >--- iplist.cpp.orig Wed Sep 8 16:10:51 2004 >+++ iplist.cpp Tue Jun 21 20:37:00 2005 >@@ -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; > } >--- peer.cpp.orig Wed Sep 8 16:10:51 2004 >+++ peer.cpp Fri Jul 15 19:56:17 2005 >@@ -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() >--- peer.h.orig Wed Sep 8 16:10:51 2004 >+++ peer.h Wed Jul 13 20:17:23 2005 >@@ -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(); >--- peerlist.cpp.orig Wed Sep 8 16:10:51 2004 >+++ peerlist.cpp Fri Jul 15 21:00:39 2005 >@@ -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(); >+ } >+ } >+} >+ >--- peerlist.h.orig Wed Sep 8 16:10:51 2004 >+++ peerlist.h Wed Jul 13 20:17:30 2005 >@@ -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; >--- rate.cpp.orig Wed Sep 8 16:10:51 2004 >+++ rate.cpp Thu Jul 14 21:09:00 2005 >@@ -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 >--- rate.h.orig Wed Sep 8 16:10:51 2004 >+++ rate.h Tue Jun 21 20:14:00 2005 >@@ -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); >--- sigint.cpp.orig Wed Sep 8 16:10:51 2004 >+++ sigint.cpp Thu Jun 2 20:27:00 2005 >@@ -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); > } > } > >--- sigint.h.orig Wed Sep 8 16:10:51 2004 >+++ sigint.h Thu Jun 2 20:27:00 2005 >@@ -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 >--- tracker.cpp.orig Wed Sep 8 16:10:51 2004 >+++ tracker.cpp Fri Jul 15 21:09:00 2005 >@@ -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(); >--- tracker.h.orig Wed Sep 8 16:10:51 2004 >+++ tracker.h Wed Jul 13 20:17:40 2005 >@@ -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;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 112352
: 72782 |
72783