Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 112352 | Differences between
and this patch

Collapse All | Expand All

(-) (+232 lines)
Added Link Here
1
Please see http://www.rahul.net/dholmes/ctorrent/ for the latest version
2
of this information.
3
4
                             Enhanced CTorrent
5
6
      [ [1]Info | [2]Notes | [3]Changes | [4]Download | [5]Resources |
7
                               [6]Contact ] 
8
9
Information
10
11
   [7]CTorrent is a [8]BitTorrent client implemented in C++ to be
12
   lightweight and quick. It has fallen a little behind in updates and
13
   bug fixes though.
14
15
   The files here contain the good work of those who wrote the original
16
   CTorrent base code and a number of patches that provide fixes and
17
   enhancements, as well as additional fixes and enhancements that I am
18
   contributing. I am not the original author, current maintainer, or any
19
   other official representative of CTorrent. The files on this page are
20
   not the original or official CTorrent distribution. I encourage you to
21
   visit the [9]CTorrent project page on SourceForge for further
22
   information.
23
24
Notes
25
26
   Use of the -P option (or changing the peer ID in btconfig.h) is
27
   recommended, as some other clients and trackers assume that Ctorrent
28
   is "buggy" and won't cooperate with it. [Guess what, there are plenty
29
   of others with bugs too.] It isn't necessary to impersonate another
30
   known client; just changing or adding one letter or number should be
31
   sufficient.
32
33
Changes for "dnh1" Release
34
35
   Patches
36
     * Incorporates the following patches. The number is the Request ID
37
       from the [10]SourceForge patches page, which you can reference for
38
       the details of each patch. The name in brackets is the name of the
39
       patch file or a name I chose to refer to the patch. Some of these
40
       names are used below (in brackets) to describe a fix or change to
41
       a particular patch.
42
       1042808 [getcwd] (incorporated in get1file patch)
43
       1084776 [passkey] (incorporated in udlimit patch)
44
       1109266 [align]
45
       1109287 [tracker/tracker2]
46
       1114197 [fmt] (incorporated in get1file patch)
47
       1114364 [resetdl]
48
       1116448 [get1file]
49
       1118597 [crash]
50
       1119467 [stall]
51
       1119492 [rate]
52
       1119497 [flush]
53
       1119519 [opt]
54
       1119689 [status]
55
       1124342 [udlimit]
56
57
   Download performance
58
     * If a peer socket is ready for reading and writing, perform both.
59
       Previously the cases were exclusive, with preference given to
60
       reading.
61
     * Download requests are now made to peers when they are ready for
62
       writing (in addition to the existing event-driven cases). This
63
       fixes peer stalls when a request couldn't be sent in an
64
       event-triggered case due to bandwidth limiting or other
65
       circumstances.
66
     * Additional tests added so that the above request checking doesn't
67
       create hard loops.
68
69
   Bandwidth measurement/management
70
     * [rate] Bandwidth reporting is now not capped. Also, only the time
71
       used for the samples taken is used in the calculation rather than
72
       the maximum interval (this affects rate calculation for individual
73
       peers).
74
     * Additional upload and download bandwidth limit checks added so
75
       that bw management is more accurate.
76
     * Corrected condition inversion bug in Rate::StopTimer(), which
77
       affects peer rate calculations.
78
79
   Peer count
80
     * Request our max number of peers from the tracker each time rather
81
       than just taking the tracker's default, so we can try to fill up.
82
     * The tracker will be contacted early if all peers disconnect so
83
       that we can actively try to establish some more peer connections.
84
       To avoid hammering the tracker, we must have at least one peer for
85
       15 seconds in order for this to be invoked.
86
     * Some clients use nonzero bytes in the "reserved" part of the
87
       handshake. Added code to ignore the reserved bytes if the rest of
88
       the handshake is as expected. This includes Azureus 2300 thru 2304
89
       (latest) which gives 0x80 as the first reserved byte and BitComet
90
       which gives 0x6578 ("ex") as the first two bytes.
91
     * Update peer's timestamp on any message, not just keepalives. Any
92
       receipt of data from a peer now resets its timeout, preventing
93
       early disconnect.
94
95
   Parallel requests
96
     * Initial-piece and endgame cases have been improved so that pieces
97
       will be requested from multiple peers. Cancels are sent as slices
98
       (subpieces) are received. This endgame strategy is described in
99
       the BitTorrent online spec. The startup strategy is also described
100
       in posts and facilitates obtaining a single piece more rapidly in
101
       order to obtain some trade value. In initial mode, the piece of
102
       which we need the least parts is targeted. In endgame mode, the
103
       piece of which we need the most parts is targeted. Slices that are
104
       cancelled are also removed from the "pending" queue, as are pieces
105
       that are completed.
106
     * When duplicating a piece request, the slice request order is also
107
       shuffled in order to minimize duplication of effort.
108
109
   Tracker info
110
     * [status] Seems to be missing tracker.cpp diff. Added code to get
111
       tracker's total peers, but not all trackers report these fields in
112
       the normal response. Also added code to count successful updates
113
       from the tracker.
114
     * Added tracker connection state to status line (when
115
       connecting/connected).
116
117
   Tracker contact
118
     * When interrupting (ctrl-C), connect to the tracker immediately
119
       rather than waiting 15 seconds.
120
     * Contact tracker "soon" after transitioning to seeder state.
121
122
   Peer interaction
123
     * Manage our interested state for each peer dynamically as content
124
       changes.
125
     * Unchoking
126
          + Use the peer's interested state (confirming via the bitfield
127
            that it needs our data) to consider unchoking. Using only the
128
            bitfield could cause us to waste an upload slot on a peer
129
            that doesn't have all content but isn't interested (like a
130
            single-file downloader).
131
          + Choke peers that become uninterested or don't need our data.
132
          + Try unchoking new peers only as slots open or the optimistic
133
            unchoke rotates. Unchoking too many peers can temporarily
134
            reduce per-peer upload rates, which would make uploading to
135
            us unappealing for good peers.
136
          + In a tie for download speed, prefer to unchoke the peer to
137
            whom we've uploaded the least data relative to what we've
138
            downloaded from him.
139
     * Optimistic unchoking
140
          + Fixed condition inversion bug causing opt unchoking to occur
141
            too often.
142
          + A peer who has no pieces is now preferred 75% vs. a peer who
143
            already has at least one piece, in order to help the new peer
144
            become productive. This is documented in the online spec.
145
          + Set peer's last-unchoke-time when choking the peer to get
146
            better rotation of the optimistic unchoke. The value is now
147
            the last time that a peer was in the unchoked state rather
148
            than the time of the last unchoke event.
149
150
   Miscellaneous items
151
     * [tracker] Fixed normal program end (stop) process, which was
152
       crashing.
153
     * [get1file] Restore compact tracker response support.
154
     * [get1file] Made display of the status line info dependent on
155
       whether the option is in use.
156
     * [get1file] Apply the filter when checking for what we need from a
157
       peer instead of when recording what the peer has; this prevents
158
       stalls when we move on to the next file. Update interested state
159
       for each peer when we begin a new file. Also move the file-done
160
       check into the piece completion code and check whether the next
161
       file(s) has also been completed.
162
     * Reduced the slice size from 32K to 16K (same as BT & Azureus).
163
       This provides more precise DL rate measurement, and helps insure
164
       that we receive a productive amount of data (i.e. a complete
165
       slice) even if we are unchoked by a peer for only one cycle. See
166
       [11]http://groups.yahoo.com/group/BitTorrent/message/1260 for more
167
       discussion/analysis on this.
168
     * Added -v (verbose) option for additional debugging output.
169
170
Download
171
172
   [12]FreeBSD patch file
173
   A patch file of changes to the CTorrent 1.3.4 base, including the
174
   patches from the FreeBSD ports tree.
175
176
   [13]Patch file
177
   A patch file of changes to the CTorrent 1.3.4 base.
178
179
   [14]FreeBSD patched source
180
   This includes the patches from the FreeBSD ports tree.
181
182
   [15]Linux/Windows/Other patched source
183
   Please [16]let me know if you encounter any portability issues, as I
184
   don't have a test environment set up for these platforms.
185
186
Resources
187
188
   [17]CTorrent Home Page 
189
   Outdated, but you may find some useful info (particularly the FAQ).
190
191
   [18]CTorrent SourceForge Project 
192
   Hosts the CTorrent codebase, bug reports, patches, and forum.
193
194
   [19]Custom CTorrent 
195
   A page by the author of the "get1file" patch and other fixes. It
196
   contains a custom version and a GUI for CTorrent.
197
198
   [20]BitTorrent 
199
   The official BitTorrent home page.
200
201
   [21]BitTorrent wiki 
202
   Various documentation.
203
204
   [22]BitTorrent protocol specification (official version)
205
206
   [23]BitTorrent protocol specification (wiki version)
207
208
References
209
210
   1. http://www.rahul.net/dholmes/ctorrent/index.html#info
211
   2. http://www.rahul.net/dholmes/ctorrent/index.html#notes
212
   3. http://www.rahul.net/dholmes/ctorrent/index.html#changes
213
   4. http://www.rahul.net/dholmes/ctorrent/index.html#download
214
   5. http://www.rahul.net/dholmes/ctorrent/index.html#resources
215
   6. mailto:dholmes@ct.boxmail.com
216
   7. http://ctorrent.sourceforge.net/
217
   8. http://www.bittorrent.com/
218
   9. http://sourceforge.net/projects/ctorrent/
219
  10. http://sourceforge.net/tracker/?atid=598034&group_id=91688&func=browse
220
  11. http://groups.yahoo.com/group/BitTorrent/message/1260
221
  12. http://www.rahul.net/dholmes/ctorrent/ctorrent-dnh1-fbsd.diff
222
  13. http://www.rahul.net/dholmes/ctorrent/ctorrent-dnh1.diff
223
  14. http://www.rahul.net/dholmes/ctorrent/ctorrent-dnh1-fbsd.tar.gz
224
  15. http://www.rahul.net/dholmes/ctorrent/ctorrent-dnh1.tar.gz
225
  16. mailto:dholmes@ct.boxmail.com
226
  17. http://ctorrent.sourceforge.net/
227
  18. http://sourceforge.net/projects/ctorrent/
228
  19. http://customctorrent.ifreepages.com/
229
  20. http://bittorrent.com/
230
  21. http://wiki.theory.org/CategoryBitTorrent
231
  22. http://www.bittorrent.com/protocol.html
232
  23. http://wiki.theory.org/BitTorrentSpecification
(-)btconfig.cpp.orig (-2 / +6 lines)
Lines 1-6 Link Here
1
#include <sys/types.h>
1
#include <sys/types.h>
2
2
3
size_t cfg_req_slice_size = 32768;
3
//size_t cfg_req_slice_size = 32768;
4
size_t cfg_req_slice_size = 16384;
4
5
5
size_t cfg_cache_size = 16;
6
size_t cfg_cache_size = 16;
6
7
Lines 11-17 Link Here
11
int cfg_max_listen_port = 2706;
12
int cfg_max_listen_port = 2706;
12
int cfg_min_listen_port = 2106;
13
int cfg_min_listen_port = 2106;
13
14
14
int cfg_max_bandwidth = -1;
15
int cfg_max_bandwidth_down = -1;
16
int cfg_max_bandwidth_up = -1;
15
17
16
time_t cfg_seed_hours = 72;
18
time_t cfg_seed_hours = 72;
17
19
Lines 25-30 Link Here
25
unsigned char arg_flg_check_only = 0;
27
unsigned char arg_flg_check_only = 0;
26
unsigned char arg_flg_exam_only = 0;
28
unsigned char arg_flg_exam_only = 0;
27
unsigned char arg_flg_make_torrent = 0;
29
unsigned char arg_flg_make_torrent = 0;
30
unsigned char arg_file_to_download = 0;
31
unsigned char arg_verbose = 0;
28
32
29
size_t arg_piece_length = 262144;
33
size_t arg_piece_length = 262144;
30
char *arg_announce = (char*) 0;
34
char *arg_announce = (char*) 0;
(-)btconfig.h.orig (+4 lines)
Lines 22-27 Link Here
22
extern time_t cfg_seed_hours;
22
extern time_t cfg_seed_hours;
23
23
24
extern int cfg_max_bandwidth;
24
extern int cfg_max_bandwidth;
25
extern int cfg_max_bandwidth_down;
26
extern int cfg_max_bandwidth_up;
25
27
26
// arguments global value
28
// arguments global value
27
extern char *arg_metainfo_file;
29
extern char *arg_metainfo_file;
Lines 33-38 Link Here
33
extern unsigned char arg_flg_check_only;
35
extern unsigned char arg_flg_check_only;
34
extern unsigned char arg_flg_exam_only;
36
extern unsigned char arg_flg_exam_only;
35
extern unsigned char arg_flg_make_torrent;
37
extern unsigned char arg_flg_make_torrent;
38
extern unsigned char arg_file_to_download;
39
extern unsigned char arg_verbose;
36
40
37
extern size_t arg_piece_length;
41
extern size_t arg_piece_length;
38
extern char *arg_announce;
42
extern char *arg_announce;
(-)btcontent.cpp.orig (-6 / +35 lines)
Lines 23-28 Link Here
23
#include "bencode.h"
23
#include "bencode.h"
24
#include "peer.h"
24
#include "peer.h"
25
#include "httpencode.h"
25
#include "httpencode.h"
26
#include "tracker.h"
26
27
27
#define meta_str(keylist,pstr,pint) decode_query(b,flen,(keylist),(pstr),(pint),QUERY_STR)
28
#define meta_str(keylist,pstr,pint) decode_query(b,flen,(keylist),(pstr),(pint),QUERY_STR)
28
#define meta_int(keylist,pint) decode_query(b,flen,(keylist),(const char**) 0,(pint),QUERY_INT)
29
#define meta_int(keylist,pint) decode_query(b,flen,(keylist),(const char**) 0,(pint),QUERY_INT)
Lines 53-58 Link Here
53
  m_announce = global_piece_buffer = (char*) 0;
54
  m_announce = global_piece_buffer = (char*) 0;
54
  m_hash_table = (unsigned char *) 0;
55
  m_hash_table = (unsigned char *) 0;
55
  pBF = (BitField*) 0;
56
  pBF = (BitField*) 0;
57
  pBFilter = (BitField*) 0;
56
  m_create_date = m_seed_timestamp = (time_t) 0;
58
  m_create_date = m_seed_timestamp = (time_t) 0;
57
  time(&m_start_timestamp);
59
  time(&m_start_timestamp);
58
  m_cache = (BTCACHE*) 0;
60
  m_cache = (BTCACHE*) 0;
Lines 226-231 Link Here
226
  if( m_btfiles.BuildFromMI(b, flen, saveas) < 0) ERR_RETURN();
228
  if( m_btfiles.BuildFromMI(b, flen, saveas) < 0) ERR_RETURN();
227
229
228
  delete []b;
230
  delete []b;
231
  b = (char *)0;
229
  PrintOut();
232
  PrintOut();
230
  
233
  
231
  if( arg_flg_exam_only ) return 0;
234
  if( arg_flg_exam_only ) return 0;
Lines 242-247 Link Here
242
  if( !pBF ) ERR_RETURN();
245
  if( !pBF ) ERR_RETURN();
243
#endif
246
#endif
244
247
248
    //create the file filter
249
    pBFilter = new BitField(m_npieces);
250
#ifndef WINDOWS
251
     if( !pBFilter ) ERR_RETURN();
252
#endif
253
  if(arg_file_to_download>0){
254
    m_btfiles.SetFilter(arg_file_to_download,pBFilter,m_piece_length);
255
  }
256
257
258
245
  m_left_bytes = m_btfiles.GetTotalLength() / m_piece_length;
259
  m_left_bytes = m_btfiles.GetTotalLength() / m_piece_length;
246
  if( m_btfiles.GetTotalLength() % m_piece_length ) m_left_bytes++;
260
  if( m_btfiles.GetTotalLength() % m_piece_length ) m_left_bytes++;
247
  if( m_left_bytes != m_npieces ) ERR_RETURN();
261
  if( m_left_bytes != m_npieces ) ERR_RETURN();
Lines 309-315 Link Here
309
323
310
ssize_t btContent::ReadSlice(char *buf,size_t idx,size_t off,size_t len)
324
ssize_t btContent::ReadSlice(char *buf,size_t idx,size_t off,size_t len)
311
{
325
{
312
  u_int64_t offset = idx * m_piece_length + off;
326
  //changed
327
  u_int64_t offset = (u_int64_t)idx * (u_int64_t)m_piece_length + (u_int64_t)off;
313
328
314
  if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 0);
329
  if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 0);
315
  else{
330
  else{
Lines 405-411 Link Here
405
420
406
ssize_t btContent::WriteSlice(char *buf,size_t idx,size_t off,size_t len)
421
ssize_t btContent::WriteSlice(char *buf,size_t idx,size_t off,size_t len)
407
{
422
{
408
  u_int64_t offset = (u_int64_t)(idx * m_piece_length + off);
423
  //u_int64_t offset = (u_int64_t)(idx * m_piece_length + off);
424
  //changed
425
  u_int64_t offset = (u_int64_t)idx * (u_int64_t)m_piece_length + (u_int64_t)off;
426
427
  //  printf("\nOffset-write: %lu - Piece:%lu\n",offset,(unsigned long)idx);
409
428
410
  if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 1);
429
  if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 1);
411
  else{
430
  else{
Lines 514-522 Link Here
514
  if( !percent ) percent = 1;
533
  if( !percent ) percent = 1;
515
534
516
  for( ; idx < m_npieces; idx++){
535
  for( ; idx < m_npieces; idx++){
517
    if( GetHashValue(idx, md) == 0 && memcmp(md, m_hash_table + idx * 20, 20) == 0){
536
      if( GetHashValue(idx, md) == 0 && memcmp(md, m_hash_table + idx * 20, 20) == 0){
518
      m_left_bytes -= GetPieceLength(idx);
537
       m_left_bytes -= GetPieceLength(idx);
519
      pBF->Set(idx);
538
       pBF->Set(idx);
520
    }
539
    }
521
    if(idx % percent == 0){
540
    if(idx % percent == 0){
522
      printf("\rCheck exist: %d/%d",idx,pBF->NBits());
541
      printf("\rCheck exist: %d/%d",idx,pBF->NBits());
Lines 575-581 Link Here
575
    fprintf(stderr,"warn,piece %d hash check failed.\n",idx);
594
    fprintf(stderr,"warn,piece %d hash check failed.\n",idx);
576
    return 0;
595
    return 0;
577
  }
596
  }
578
579
  pBF->Set(idx);
597
  pBF->Set(idx);
580
  m_left_bytes -= GetPieceLength(idx);
598
  m_left_bytes -= GetPieceLength(idx);
581
  return 1;
599
  return 1;
Lines 592-597 Link Here
592
{
610
{
593
  if( pBF->IsFull() ){
611
  if( pBF->IsFull() ){
594
    if( !m_seed_timestamp ){
612
    if( !m_seed_timestamp ){
613
      Tracker.Reset(15);
595
      Self.ResetDLTimer();
614
      Self.ResetDLTimer();
596
      Self.ResetULTimer();
615
      Self.ResetULTimer();
597
      ReleaseHashTable();
616
      ReleaseHashTable();
Lines 604-607 Link Here
604
    if( (*pnow - m_seed_timestamp) >= (cfg_seed_hours * 60 * 60) ) return 1;
623
    if( (*pnow - m_seed_timestamp) >= (cfg_seed_hours * 60 * 60) ) return 1;
605
  }
624
  }
606
  return 0;
625
  return 0;
626
}
627
628
629
size_t btContent::getFilePieces(unsigned char nfile){
630
   return m_btfiles.getFilePieces(nfile);
631
}
632
633
634
void btContent::SetFilter(){
635
  m_btfiles.SetFilter(arg_file_to_download,pBFilter,m_piece_length);
607
}
636
}
(-)btcontent.h.orig (+6 lines)
Lines 60-65 Link Here
60
  
60
  
61
 public:
61
 public:
62
  BitField *pBF;
62
  BitField *pBF;
63
  BitField *pBFilter;
63
  char *global_piece_buffer;
64
  char *global_piece_buffer;
64
  
65
  
65
  btContent();
66
  btContent();
Lines 93-98 Link Here
93
94
94
  int PrintOut();
95
  int PrintOut();
95
  int SeedTimeout(const time_t *pnow);
96
  int SeedTimeout(const time_t *pnow);
97
98
99
 void SetFilter();
100
 size_t getFilePieces(unsigned char nfile);
101
96
};
102
};
97
103
98
extern btContent BTCONTENT;
104
extern btContent BTCONTENT;
(-)btfiles.cpp.orig (-2 / +55 lines)
Lines 105-110 Link Here
105
  pos = (size_t) (off - (n - pbf->bf_length));
105
  pos = (size_t) (off - (n - pbf->bf_length));
106
106
107
  for(; len ;){
107
  for(; len ;){
108
108
    if( !pbf->bf_flag_opened ){
109
    if( !pbf->bf_flag_opened ){
109
      if( _btf_open(pbf) < 0 ) return -1;
110
      if( _btf_open(pbf) < 0 ) return -1;
110
    }
111
    }
Lines 119-124 Link Here
119
      if( 1 != fread(buf,nio,1,pbf->bf_fp) ) return -1;
120
      if( 1 != fread(buf,nio,1,pbf->bf_fp) ) return -1;
120
    }else{
121
    }else{
121
      if( 1 != fwrite(buf,nio,1,pbf->bf_fp) ) return -1;
122
      if( 1 != fwrite(buf,nio,1,pbf->bf_fp) ) return -1;
123
      fflush(pbf->bf_fp);
122
    }
124
    }
123
125
124
    len -= nio;
126
    len -= nio;
Lines 169-175 Link Here
169
  DIR *dp;
171
  DIR *dp;
170
  BTFILE *pbf;
172
  BTFILE *pbf;
171
173
172
  if( !getwd(full_cur) ) return -1;
174
  if( !getcwd(full_cur,MAXPATHLEN) ) return -1;
173
175
174
  if( cur_path ){
176
  if( cur_path ){
175
    strcpy(fn, full_cur);
177
    strcpy(fn, full_cur);
Lines 293-299 Link Here
293
    m_btfhead = pbf;
295
    m_btfhead = pbf;
294
  }else if( S_IFDIR & sb.st_mode ){
296
  }else if( S_IFDIR & sb.st_mode ){
295
    char wd[MAXPATHLEN];
297
    char wd[MAXPATHLEN];
296
    if( !getwd(wd) ) return -1;
298
    if( !getcwd(wd,MAXPATHLEN) ) return -1;
297
    m_directory = new char[strlen(pathname) + 1];
299
    m_directory = new char[strlen(pathname) + 1];
298
#ifndef WINDOWS
300
#ifndef WINDOWS
299
    if( !m_directory ) return -1;
301
    if( !m_directory ) return -1;
Lines 488-490 Link Here
488
  }
490
  }
489
  return 1;
491
  return 1;
490
}
492
}
493
494
495
void btFiles::SetFilter(int nfile, BitField *pFilter,  size_t pieceLength)
496
{
497
  //set the filter
498
499
  BTFILE *p = m_btfhead;
500
  size_t id = 1;
501
  u_int64_t sizeBuffer=0;
502
  size_t index;
503
504
505
   pFilter->SetAll();
506
     for( ; p ; p = p->bf_next ){
507
      if(id++ == nfile){
508
        size_t start,stop;
509
        start = sizeBuffer/pieceLength;
510
        stop  = (sizeBuffer+p->bf_length)/pieceLength;
511
        printf ("\rDownloading file: <%d> %s        \nPieces: %d - %d (%d)\n",nfile,p->bf_filename,start,stop,stop-start+1);
512
        p->bf_npieces = stop-start+1;
513
        for(index=sizeBuffer/pieceLength;index<=(sizeBuffer+p->bf_length)/pieceLength;index++){
514
	  pFilter->UnSet(index);
515
        }
516
     }
517
     sizeBuffer+=(u_int64_t) p->bf_length;
518
   }
519
    if(nfile>=id){
520
      printf("\nEnd of files list. Resuming normal behaviour\n");
521
      pFilter->Invert();
522
      arg_file_to_download = 0;
523
    }
524
}
525
526
size_t btFiles::getFilePieces(unsigned char nfile)
527
{
528
  //returns the pieces of the file already gotten
529
530
  BTFILE *p = m_btfhead;
531
  size_t id = 1;
532
533
     for( ; p ; p = p->bf_next ){
534
      if(id++ == nfile){
535
        return p->bf_npieces;
536
        }
537
     }
538
return 0;
539
}
540
541
542
543
(-)btfiles.h.orig (+10 lines)
Lines 3-8 Link Here
3
3
4
#include <sys/types.h>
4
#include <sys/types.h>
5
#include <stdio.h>
5
#include <stdio.h>
6
7
#include "bitfield.h"
8
extern unsigned char arg_file_to_download;
9
6
#include "./def.h"
10
#include "./def.h"
7
11
8
typedef struct _btfile{
12
typedef struct _btfile{
Lines 14-19 Link Here
14
18
15
  size_t bf_completed;		// already downloaded length
19
  size_t bf_completed;		// already downloaded length
16
20
21
  size_t bf_npieces;  //number of pieces
22
17
  unsigned char bf_flag_opened:1;
23
  unsigned char bf_flag_opened:1;
18
  unsigned char bf_flag_need:1;
24
  unsigned char bf_flag_need:1;
19
  unsigned char bf_reserved:6;
25
  unsigned char bf_reserved:6;
Lines 53-58 Link Here
53
  u_int64_t GetTotalLength() const { return m_total_files_length; }
59
  u_int64_t GetTotalLength() const { return m_total_files_length; }
54
  ssize_t IO(char *buf, u_int64_t off, size_t len, const int iotype);
60
  ssize_t IO(char *buf, u_int64_t off, size_t len, const int iotype);
55
  size_t FillMetaInfo(FILE* fp);
61
  size_t FillMetaInfo(FILE* fp);
62
63
  void SetFilter(int nfile, BitField *pFilter,size_t pieceLength);
64
  size_t getFilePieces(unsigned char nfile);
65
56
#ifndef WINDOWS
66
#ifndef WINDOWS
57
  void PrintOut();
67
  void PrintOut();
58
#endif
68
#endif
(-)btrequest.cpp.orig (+82 lines)
Lines 44-49 Link Here
44
  rq.rq_head = (PSLICE) 0;
44
  rq.rq_head = (PSLICE) 0;
45
}
45
}
46
46
47
int RequestQueue::CopyShuffle(RequestQueue &rq)
48
{
49
  PSLICE ps;
50
51
  if( rq_head ) _empty_slice_list(&rq_head);
52
  
53
  if( rq.IsEmpty() ) return 0;
54
  for (ps = rq.GetHead(); ps; ps = ps->next) {
55
    if (random()&01) {
56
      if (Add(ps->index, ps->offset, ps->length) < 0) return -1;
57
    }
58
    else if (Insert(ps->index, ps->offset, ps->length) < 0) return -1;
59
  }
60
  return 0;
61
}
62
63
size_t RequestQueue::Qsize()
64
{
65
  size_t cnt = 0;
66
  PSLICE n = rq_head;
67
  PSLICE u = (PSLICE) 0;
68
69
  for( ; n ; u = n,n = u->next) cnt++; // move to end
70
  return cnt;
71
}
72
73
int RequestQueue::Insert(size_t idx,size_t off,size_t len)
74
{
75
  size_t cnt = 0;
76
  PSLICE n = rq_head;
77
  PSLICE u = (PSLICE) 0;
78
79
  for( ; n ; u = n,n = u->next) cnt++; // move to end (count)
80
81
  if( cnt >= cfg_req_queue_length ) return -1;	// already full
82
83
  n = new SLICE;
84
85
#ifndef WINDOWS
86
  if( !n ) return -1;
87
#endif
88
89
  n->next = rq_head;
90
  n->index = idx;
91
  n->offset = off;
92
  n->length = len;
93
94
  rq_head = n;
95
96
  return 0;
97
}
98
47
int RequestQueue::Add(size_t idx,size_t off,size_t len)
99
int RequestQueue::Add(size_t idx,size_t off,size_t len)
48
{
100
{
49
  size_t cnt = 0;
101
  size_t cnt = 0;
Lines 231-233 Link Here
231
  }
283
  }
232
  return 0;
284
  return 0;
233
}
285
}
286
287
int PendingQueue::Delete(size_t idx)
288
{
289
   int i = 0;
290
  for ( ; i < PENDING_QUEUE_SIZE && pq_count; i++){
291
    if( (PSLICE) 0 != pending_array[i] && idx == pending_array[i]->index){
292
      delete pending_array[i];
293
      pending_array[i] = (PSLICE) 0;
294
    }
295
  }
296
  return 0;
297
}
298
299
int PendingQueue::DeleteSlice(size_t idx, size_t off, size_t len)
300
{
301
   int i = 0;
302
   RequestQueue rq;
303
  for ( ; i < PENDING_QUEUE_SIZE && pq_count; i++){
304
    if( (PSLICE) 0 != pending_array[i] && idx == pending_array[i]->index){
305
      //check if off & len match any slice
306
      //remove the slice if so
307
      rq.SetHead(pending_array[i]);
308
      if( rq.Remove(idx, off, len) == 0 )
309
        pending_array[i] = rq.GetHead();
310
      rq.Release();
311
    }
312
  }
313
  return 0;
314
}
315
(-)btrequest.h.orig (+5 lines)
Lines 31-39 Link Here
31
  int IsValidRequest(size_t idx,size_t off,size_t len);
31
  int IsValidRequest(size_t idx,size_t off,size_t len);
32
32
33
  void operator=(RequestQueue &rq);
33
  void operator=(RequestQueue &rq);
34
  int CopyShuffle(RequestQueue &rq);
35
  size_t Qsize();
34
36
35
  int IsEmpty() const { return rq_head ? 0 : 1; }
37
  int IsEmpty() const { return rq_head ? 0 : 1; }
36
38
39
  int Insert(size_t idx,size_t off,size_t len);
37
  int Add(size_t idx,size_t off,size_t len);
40
  int Add(size_t idx,size_t off,size_t len);
38
  int Remove(size_t idx,size_t off,size_t len);
41
  int Remove(size_t idx,size_t off,size_t len);
39
42
Lines 60-65 Link Here
60
  int Pending(RequestQueue *prq);
63
  int Pending(RequestQueue *prq);
61
  int ReAssign(RequestQueue *prq, BitField &bf);
64
  int ReAssign(RequestQueue *prq, BitField &bf);
62
  int Exist(size_t idx);
65
  int Exist(size_t idx);
66
  int Delete(size_t idx);
67
  int DeleteSlice(size_t idx, size_t off, size_t len);
63
};
68
};
64
69
65
extern PendingQueue PENDINGQUEUE;
70
extern PendingQueue PENDINGQUEUE;
(-)btstream.cpp.orig (-18 / +14 lines)
Lines 1-5 Link Here
1
#include <arpa/inet.h>
1
#include <arpa/inet.h>
2
#include "btstream.h"
2
#include "btstream.h"
3
#include "peer.h"
3
#include "msgencode.h"
4
#include "msgencode.h"
4
#include "btconfig.h"
5
#include "btconfig.h"
5
6
Lines 11-17 Link Here
11
ssize_t btStream::Send_State(unsigned char state)
12
ssize_t btStream::Send_State(unsigned char state)
12
{
13
{
13
  char msg[H_BASE_LEN + 4];
14
  char msg[H_BASE_LEN + 4];
14
  *(size_t*)msg = htonl(H_BASE_LEN);
15
16
  set_nl(msg, H_BASE_LEN);
15
  msg[4] = (char)state;
17
  msg[4] = (char)state;
16
  return out_buffer.PutFlush(sock,msg,H_BASE_LEN + 4);
18
  return out_buffer.PutFlush(sock,msg,H_BASE_LEN + 4);
17
}
19
}
Lines 19-30 Link Here
19
ssize_t btStream::Send_Have(size_t idx)
21
ssize_t btStream::Send_Have(size_t idx)
20
{
22
{
21
  char msg[H_HAVE_LEN + 4];
23
  char msg[H_HAVE_LEN + 4];
22
  size_t *p = (size_t*)msg;
23
24
24
  *p = htonl(H_HAVE_LEN);
25
  set_nl(msg, H_HAVE_LEN);
25
  msg[4] = (char)M_HAVE;
26
  msg[4] = (char)M_HAVE;
26
  p = (size_t*)(msg + 5);
27
  set_nl(msg + 5, idx);
27
  *p = htonl(idx);
28
28
29
  return out_buffer.PutFlush(sock,msg,H_HAVE_LEN + 4);
29
  return out_buffer.PutFlush(sock,msg,H_HAVE_LEN + 4);
30
}
30
}
Lines 43-56 Link Here
43
ssize_t btStream::Send_Cancel(size_t idx,size_t off,size_t len)
43
ssize_t btStream::Send_Cancel(size_t idx,size_t off,size_t len)
44
{
44
{
45
  char msg[H_CANCEL_LEN + 4];
45
  char msg[H_CANCEL_LEN + 4];
46
  size_t *p = (size_t*)msg;
47
46
48
  *p = htonl(H_CANCEL_LEN);
47
  set_nl(msg, H_CANCEL_LEN);
49
  msg[4] = M_CANCEL;
48
  msg[4] = M_CANCEL;
50
  p = (size_t*)(msg + 5);
49
  set_nl(msg + 5, idx);
51
  *p = htonl(idx); p++;
50
  set_nl(msg + 9, off);
52
  *p = htonl(off); p++;
51
  set_nl(msg + 13, len);
53
  *p = htonl(len);
54
  return out_buffer.Put(sock,msg,H_CANCEL_LEN + 4);
52
  return out_buffer.Put(sock,msg,H_CANCEL_LEN + 4);
55
}
53
}
56
54
Lines 72-85 Link Here
72
ssize_t btStream::Send_Request(size_t idx, size_t off,size_t len)
70
ssize_t btStream::Send_Request(size_t idx, size_t off,size_t len)
73
{
71
{
74
  char msg[H_REQUEST_LEN + 4];
72
  char msg[H_REQUEST_LEN + 4];
75
  size_t *p = (size_t*) msg;
76
73
77
  *p = htonl(H_REQUEST_LEN);
74
  set_nl(msg, H_REQUEST_LEN);
78
  msg[4] = (char)M_REQUEST;
75
  msg[4] = (char)M_REQUEST;
79
  p = (size_t*)(msg + 5);
76
  set_nl(msg + 5, idx);
80
  *p = htonl(idx); p++;
77
  set_nl(msg + 9, off);
81
  *p = htonl(off); p++;
78
  set_nl(msg + 13, len);
82
  *p = htonl(len);
83
  return out_buffer.Put(sock,msg,H_REQUEST_LEN + 4);
79
  return out_buffer.Put(sock,msg,H_REQUEST_LEN + 4);
84
}
80
}
85
81
Lines 94-100 Link Here
94
  // if message arrived.
90
  // if message arrived.
95
  size_t r;
91
  size_t r;
96
  if( 4 <= in_buffer.Count() ){
92
  if( 4 <= in_buffer.Count() ){
97
    r = ntohl(*(size_t*)in_buffer.BasePointer());
93
    r = get_nl(in_buffer.BasePointer());
98
    if( (cfg_max_slice_size + H_PIECE_LEN + 4) < r) return -1; //message too long
94
    if( (cfg_max_slice_size + H_PIECE_LEN + 4) < r) return -1; //message too long
99
    if( (r + 4) <= in_buffer.Count() ) return 1;
95
    if( (r + 4) <= in_buffer.Count() ) return 1;
100
  }
96
  }
(-)ctorrent.cpp.orig (-5 / +25 lines)
Lines 87-95 Link Here
87
	Tracker.Initial();
87
	Tracker.Initial();
88
88
89
	signal(SIGPIPE,SIG_IGN);
89
	signal(SIGPIPE,SIG_IGN);
90
    signal(SIGINT,sigint_catch);
90
    signal(SIGINT,sig_catch);
91
    signal(SIGTERM,sig_catch);
91
    Downloader();
92
    Downloader();
92
  }
93
  }
94
  if( cfg_cache_size ) BTCONTENT.FlushCache();
95
  if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file);
96
  WORLD.CloseAll();
93
97
94
  exit(0);
98
  exit(0);
95
}
99
}
Lines 99-105 Link Here
99
int param_check(int argc, char **argv)
103
int param_check(int argc, char **argv)
100
{
104
{
101
  int c, l;
105
  int c, l;
102
  while ( ( c = getopt(argc,argv,"b:B:cC:e:fl:M:m:P:p:s:tu:xhH")) != -1)
106
  while ( ( c = getopt(argc,argv,"b:cC:D:e:fl:M:m:n:P:p:s:tu:U:vxhH")) != -1)
103
    switch( c ){
107
    switch( c ){
104
    case 'b':
108
    case 'b':
105
      arg_bitfield_file = new char[strlen(optarg) + 1];
109
      arg_bitfield_file = new char[strlen(optarg) + 1];
Lines 150-163 Link Here
150
      }
154
      }
151
      break;
155
      break;
152
156
157
    case 'n':                  // Which file download
158
      arg_file_to_download = atoi(optarg);
159
    break;
160
161
153
    case 'f':			// force seed mode, skip sha1 check when startup.
162
    case 'f':			// force seed mode, skip sha1 check when startup.
154
      arg_flg_force_seed_mode = 1;
163
      arg_flg_force_seed_mode = 1;
155
      break;
164
      break;
156
      
165
      
157
    case 'B':
166
    case 'D':
158
      cfg_max_bandwidth = atoi(optarg);
167
      cfg_max_bandwidth_down = (int)(strtod(optarg, NULL) * 1024);
159
      break;
168
      break;
160
169
170
       case 'U':
171
      cfg_max_bandwidth_up = (int)(strtod(optarg, NULL) * 1024);
172
         break;
173
161
    case 'P':
174
    case 'P':
162
		l = strlen(optarg);
175
		l = strlen(optarg);
163
		if (l > MAX_PF_LEN) {printf("-P arg must be 8 or less characters\n"); exit(1);}
176
		if (l > MAX_PF_LEN) {printf("-P arg must be 8 or less characters\n"); exit(1);}
Lines 190-195 Link Here
190
      arg_flg_exam_only = 1;
203
      arg_flg_exam_only = 1;
191
      break;
204
      break;
192
205
206
    case 'v':
207
      arg_verbose = 1;
208
      break;
209
193
    case 'h':
210
    case 'h':
194
    case 'H':
211
    case 'H':
195
    default:
212
    default:
Lines 217-222 Link Here
217
  fprintf(stderr,"-h/-H\t\tShow this message.\n");
234
  fprintf(stderr,"-h/-H\t\tShow this message.\n");
218
  fprintf(stderr,"-x\t\tDecode metainfo(torrent) file only, don't download.\n");
235
  fprintf(stderr,"-x\t\tDecode metainfo(torrent) file only, don't download.\n");
219
  fprintf(stderr,"-c\t\tCheck exist only. don't download.\n");
236
  fprintf(stderr,"-c\t\tCheck exist only. don't download.\n");
237
  fprintf(stderr,"-v\t\tVerbose output (for debugging).\n");
220
  fprintf(stderr,"\nDownload Options:\n");
238
  fprintf(stderr,"\nDownload Options:\n");
221
  fprintf(stderr,"-e int\t\tExit while seed <int> hours later. (default 72 hours)\n");
239
  fprintf(stderr,"-e int\t\tExit while seed <int> hours later. (default 72 hours)\n");
222
  fprintf(stderr,"-p port\t\tListen port. (default 2706 -> 2106)\n");
240
  fprintf(stderr,"-p port\t\tListen port. (default 2706 -> 2106)\n");
Lines 226-232 Link Here
226
  fprintf(stderr,"-b bf_filename\tBit field filename. (use it carefully)\n");
244
  fprintf(stderr,"-b bf_filename\tBit field filename. (use it carefully)\n");
227
  fprintf(stderr,"-M max_peers\tMax peers count.\n");
245
  fprintf(stderr,"-M max_peers\tMax peers count.\n");
228
  fprintf(stderr,"-m min_peers\tMin peers count.\n");
246
  fprintf(stderr,"-m min_peers\tMin peers count.\n");
229
  fprintf(stderr,"-B rate\t\tMax bandwidth (unit KB/s)\n");
247
  fprintf(stderr,"-n file_number\tWhich file download.\n");
248
  fprintf(stderr,"-D rate\t\tMax bandwidth down (unit KB/s)\n");
249
  fprintf(stderr,"-U rate\t\tMax bandwidth up (unit KB/s)\n");
230
  fprintf(stderr,"-P peer_id\tSet Peer ID ["PEER_PFX"]\n");
250
  fprintf(stderr,"-P peer_id\tSet Peer ID ["PEER_PFX"]\n");
231
  fprintf(stderr,"\nMake metainfo(torrent) file Options:\n");
251
  fprintf(stderr,"\nMake metainfo(torrent) file Options:\n");
232
  fprintf(stderr,"-t\t\tWith make torrent. must specify this option.\n");
252
  fprintf(stderr,"-t\t\tWith make torrent. must specify this option.\n");
(-)downloader.cpp.orig (-3 / +7 lines)
Lines 29-38 Link Here
29
  time_t now;
29
  time_t now;
30
  fd_set rfd;
30
  fd_set rfd;
31
  fd_set wfd;
31
  fd_set wfd;
32
  int stopped = 0;
32
33
33
  for(;;){
34
  do{
34
    time(&now);
35
    time(&now);
35
    if( BTCONTENT.SeedTimeout(&now) ) break;
36
    if( !stopped && BTCONTENT.SeedTimeout(&now) ) {
37
	Tracker.SetStoped();
38
	stopped = 1;
39
    }
36
    
40
    
37
    FD_ZERO(&rfd); FD_ZERO(&wfd);
41
    FD_ZERO(&rfd); FD_ZERO(&wfd);
38
    maxfd = Tracker.IntervalCheck(&now,&rfd, &wfd);
42
    maxfd = Tracker.IntervalCheck(&now,&rfd, &wfd);
Lines 48-52 Link Here
48
      if(T_FREE != Tracker.GetStatus()) Tracker.SocketReady(&rfd,&wfd,&nfds);
52
      if(T_FREE != Tracker.GetStatus()) Tracker.SocketReady(&rfd,&wfd,&nfds);
49
	  if( nfds ) WORLD.AnyPeerReady(&rfd,&wfd,&nfds);
53
	  if( nfds ) WORLD.AnyPeerReady(&rfd,&wfd,&nfds);
50
	}
54
	}
51
  }/* end for(;;) */
55
  } while(Tracker.GetStatus() != T_FINISHED);
52
}
56
}
(-)httpencode.cpp.orig (-1 / +1 lines)
Lines 88-94 Link Here
88
88
89
  /* path */
89
  /* path */
90
  if( *p != '/' ) return -1;
90
  if( *p != '/' ) return -1;
91
  for( ; *p && *p != '?'; p++,path++) *path = *p;
91
  for( ; *p; p++,path++) *path = *p;
92
  *path = '\0';
92
  *path = '\0';
93
  return 0;
93
  return 0;
94
}
94
}
(-)httpencode.h.orig (-2 / +5 lines)
Lines 2-9 Link Here
2
#define HTTPENCODE_H
2
#define HTTPENCODE_H
3
3
4
#define REQ_URL_P1_FMT "GET %s?info_hash=%s&peer_id=%s&port=%d"
4
#define REQ_URL_P1_FMT "GET %s?info_hash=%s&peer_id=%s&port=%d"
5
#define REQ_URL_P2_FMT "%s&uploaded=%d&downloaded=%d&left=%d&event=%s&compact=1 HTTP/1.0"
5
//#define REQ_URL_P2_FMT "%s&uploaded=%d&downloaded=%d&left=%d&event=%s&compact=1 HTTP/1.0"
6
#define REQ_URL_P3_FMT "%s&uploaded=%d&downloaded=%d&left=%d&compact=1 HTTP/1.0"
6
//#define REQ_URL_P3_FMT "%s&uploaded=%d&downloaded=%d&left=%d&compact=1 HTTP/1.0"
7
#define REQ_URL_P2_FMT "%s&uploaded=%llu&downloaded=%llu&left=%llu&compact=1&event=%s&numwant=%u HTTP/1.0"
8
#define REQ_URL_P3_FMT "%s&uploaded=%llu&downloaded=%llu&left=%llu&compact=1&numwant=%u HTTP/1.0"
9
7
10
8
char* Http_url_encode(char *s,char *b,size_t n);
11
char* Http_url_encode(char *s,char *b,size_t n);
9
int Http_url_analyse(char *url,char *host,int *port,char *path);
12
int Http_url_analyse(char *url,char *host,int *port,char *path);
(-)iplist.cpp.orig (-1 / +1 lines)
Lines 8-15 Link Here
8
  IPLIST *node = ipl_head;
8
  IPLIST *node = ipl_head;
9
  for(; ipl_head;){
9
  for(; ipl_head;){
10
    node = ipl_head;
10
    node = ipl_head;
11
    delete ipl_head;
12
    ipl_head = node->next;
11
    ipl_head = node->next;
12
    delete node;
13
  }
13
  }
14
  count = 0;
14
  count = 0;
15
}
15
}
(-)peer.cpp.orig (-52 / +284 lines)
Lines 2-13 Link Here
2
2
3
#include <stdlib.h>
3
#include <stdlib.h>
4
#include <string.h>
4
#include <string.h>
5
#include <ctype.h>
5
6
7
#include "btstream.h"
6
#include "./btcontent.h"
8
#include "./btcontent.h"
7
#include "./msgencode.h"
9
#include "./msgencode.h"
8
#include "./peerlist.h"
10
#include "./peerlist.h"
9
#include "./btconfig.h"
11
#include "./btconfig.h"
10
12
13
size_t get_nl(char *sfrom)
14
{
15
  unsigned char *from = (unsigned char *)sfrom;
16
  size_t t;
17
  t = (*from++) << 24;
18
  t |= (*from++) << 16;
19
  t |= (*from++) << 8;
20
  t |= *from;
21
  return t;
22
}
23
24
void set_nl(char *sto, size_t from)
25
{
26
  unsigned char *to = (unsigned char *)sto;
27
  *to++ = (from >> 24) & 0xff;
28
  *to++ = (from >> 16) & 0xff;
29
  *to++ = (from >> 8) & 0xff;
30
  *to = from & 0xff;
31
}
32
11
btBasic Self;
33
btBasic Self;
12
34
13
void btBasic::SetIp(struct sockaddr_in addr)
35
void btBasic::SetIp(struct sockaddr_in addr)
Lines 44-54 Link Here
44
66
45
int btPeer::Need_Remote_Data()
67
int btPeer::Need_Remote_Data()
46
{
68
{
69
47
  if( BTCONTENT.pBF->IsFull()) return 0;
70
  if( BTCONTENT.pBF->IsFull()) return 0;
48
  else if( bitfield.IsFull() ) return 1;
71
  else if( bitfield.IsFull() ) return 1;
49
  else{
72
  else{
50
    BitField tmpBitfield = bitfield;
73
    BitField tmpBitfield = bitfield;
51
    tmpBitfield.Except(*BTCONTENT.pBF);
74
    tmpBitfield.Except(*BTCONTENT.pBF);
75
    tmpBitfield.Except(*BTCONTENT.pBFilter);
52
    return tmpBitfield.IsEmpty() ? 0 : 1;
76
    return tmpBitfield.IsEmpty() ? 0 : 1;
53
  }
77
  }
54
  return 0;
78
  return 0;
Lines 65-70 Link Here
65
89
66
  m_err_count = 0;
90
  m_err_count = 0;
67
  m_cached_idx = BTCONTENT.GetNPieces();
91
  m_cached_idx = BTCONTENT.GetNPieces();
92
  m_standby = 0;
68
}
93
}
69
94
70
int btPeer::SetLocal(unsigned char s)
95
int btPeer::SetLocal(unsigned char s)
Lines 72-91 Link Here
72
  switch(s){
97
  switch(s){
73
  case M_CHOKE:
98
  case M_CHOKE:
74
    if( m_state.local_choked ) return 0;
99
    if( m_state.local_choked ) return 0;
100
    time(&m_unchoke_timestamp);
101
//  if(arg_verbose) fprintf(stderr, "Choking %p\n", this);
102
    if(arg_verbose) fprintf(stderr, "Choking %p (D=%lluMB@%uK/s)\n", this,
103
      TotalDL() >> 20, RateDL() >> 10);
75
    m_state.local_choked = 1; 
104
    m_state.local_choked = 1; 
76
    break;
105
    break;
77
  case M_UNCHOKE: 
106
  case M_UNCHOKE: 
78
    if( !reponse_q.IsEmpty() ) StartULTimer();
107
    if( !reponse_q.IsEmpty() ) StartULTimer();
79
    if( !m_state.local_choked ) return 0;
108
    if( !m_state.local_choked ) return 0;
80
    time(&m_unchoke_timestamp);
109
    time(&m_unchoke_timestamp);
110
//  if(arg_verbose) fprintf(stderr, "Unchoking %p\n", this);
111
    if(arg_verbose) fprintf(stderr, "Unchoking %p (D=%lluMB@%uK/s)\n", this,
112
      TotalDL() >> 20, RateDL() >> 10);
81
    m_state.local_choked = 0;
113
    m_state.local_choked = 0;
82
    break;
114
    break;
83
  case M_INTERESTED: 
115
  case M_INTERESTED: 
116
    m_standby = 0;
84
    if( m_state.local_interested ) return 0;
117
    if( m_state.local_interested ) return 0;
118
    if(arg_verbose) fprintf(stderr, "Interested in %p\n", this);
85
    m_state.local_interested = 1;
119
    m_state.local_interested = 1;
86
    break;
120
    break;
87
  case M_NOT_INTERESTED:
121
  case M_NOT_INTERESTED:
88
    if( !m_state.local_interested ) return 0;
122
    if( !m_state.local_interested ) return 0;
123
    if(arg_verbose) fprintf(stderr, "Not interested in %p\n", this);
89
    m_state.local_interested = 0; 
124
    m_state.local_interested = 0; 
90
    break;
125
    break;
91
  default:
126
  default:
Lines 97-108 Link Here
97
int btPeer::RequestPiece()
132
int btPeer::RequestPiece()
98
{
133
{
99
  size_t idx;
134
  size_t idx;
135
  int endgame = 0;
100
136
101
  PENDINGQUEUE.ReAssign(&request_q,bitfield);
137
  PENDINGQUEUE.ReAssign(&request_q,bitfield);
102
138
103
  if( !request_q.IsEmpty() ) return SendRequest();
139
  if( !request_q.IsEmpty() ) return SendRequest();
104
140
105
  if( m_cached_idx < BTCONTENT.GetNPieces() ){
141
  if( m_cached_idx < BTCONTENT.GetNPieces() && !BTCONTENT.pBF->IsEmpty() ){
142
    // A HAVE msg already selected what we want from this peer
143
    // but ignore it in initial-piece mode.
106
    idx = m_cached_idx;
144
    idx = m_cached_idx;
107
    m_cached_idx = BTCONTENT.GetNPieces();
145
    m_cached_idx = BTCONTENT.GetNPieces();
108
    if( !BTCONTENT.pBF->IsSet(idx) &&
146
    if( !BTCONTENT.pBF->IsSet(idx) &&
Lines 110-148 Link Here
110
	!WORLD.AlreadyRequested(idx) ){
148
	!WORLD.AlreadyRequested(idx) ){
111
      return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();
149
      return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();
112
    }
150
    }
113
  }else{
151
  }	// If we didn't want the cached piece, select another.
152
  if( BTCONTENT.pBF->IsEmpty() ){
153
    // If we don't have a complete piece yet, try to get one that's already
154
    // in progress.  (Initial-piece mode)
155
    btPeer *peer = WORLD.Who_Can_Duplicate(this, BTCONTENT.GetNPieces());
156
    if(peer){
157
      if(arg_verbose) fprintf( stderr, "Duping: %p to %p (#%u)\n",
158
        peer, this, peer->request_q.GetRequestIdx() );
159
      return (request_q.CopyShuffle(peer->request_q) < 0) ? -1 : SendRequest();
160
    }
161
  }	// Doesn't have a piece that's already in progress--choose another.
114
    BitField tmpBitField;
162
    BitField tmpBitField;
115
    if( bitfield.IsFull() ){
163
    if( bitfield.IsFull() ){
164
      // peer is a seed
116
      tmpBitField = *BTCONTENT.pBF;
165
      tmpBitField = *BTCONTENT.pBF;
117
      tmpBitField.Invert();
166
      tmpBitField.Invert();
118
    }else{
167
    }else{
119
      tmpBitField = bitfield;
168
      tmpBitField = bitfield;
120
      tmpBitField.Except(*BTCONTENT.pBF);
169
      tmpBitField.Except(*BTCONTENT.pBF);
121
    }
170
    }
171
    // The filter tells what we don't want.
172
    tmpBitField.Except(*BTCONTENT.pBFilter);
173
    // tmpBitField tells what we need from this peer...
122
174
123
    if( !tmpBitField.IsEmpty() ){
175
    if( !tmpBitField.IsEmpty() ){
124
      WORLD.CheckBitField(tmpBitField);
176
      BitField tmpBitField2 = tmpBitField;
125
      if(tmpBitField.IsEmpty()){
177
      WORLD.CheckBitField(tmpBitField2);
126
	
178
      // [tmpBitField2]... that we haven't requested from anyone.
127
	btPeer *peer = WORLD.Who_Can_Abandon(this);
179
      if(tmpBitField2.IsEmpty()){
128
	if(peer){
180
        // Everything this peer has that I want, I've already requested.
129
	  peer->StopDLTimer();
181
        endgame = ( WORLD.Pieces_I_Can_Get() - BTCONTENT.pBF->Count() )
130
	  request_q = peer->request_q;
182
            < WORLD.TotalPeers();
131
183
        if(endgame){	// OK to duplicate a request.
132
	  if(peer->CancelRequest(request_q.GetHead()) < 0 ||
184
//	  idx = tmpBitField.Random();
133
	     peer->RequestCheck() < 0){
185
	  idx = 0;	// flag for Who_Can_Duplicate()
134
	    peer->CloseConnection();
186
	  btPeer *peer = WORLD.Who_Can_Duplicate(this, idx);
135
	  }
187
	  if(arg_verbose) fprintf( stderr, "Duping: %p to %p (#%u)\n",
136
	  
188
	    peer, this, peer->request_q.GetRequestIdx() );
137
	  return SendRequest();
189
	  return (request_q.CopyShuffle(peer->request_q) < 0) ?
138
	}
190
	     -1 : SendRequest();
139
	
191
        }else{	// not endgame mode
192
	  btPeer *peer = WORLD.Who_Can_Abandon(this); // slowest choice
193
	  if(peer){
194
	    // Cancel a request to the slowest peer & request it from this one.
195
	    if(arg_verbose) fprintf( stderr, "Reassigning %p to %p (#%u)\n",
196
	      peer, this, peer->request_q.GetRequestIdx() );
197
	    peer->StopDLTimer();
198
	    // RequestQueue class "moves" rather than "copies" in assignment!
199
	    request_q = peer->request_q;
200
201
	    if(peer->CancelRequest(request_q.GetHead()) < 0 ||
202
	        peer->RequestCheck() < 0){
203
	      peer->CloseConnection();
204
	    }
205
	    return SendRequest();
206
	  }else m_standby = 1;	// nothing to do at the moment
207
        }
140
      }else{
208
      }else{
141
	idx = tmpBitField.Random();
209
        // Request something that we haven't requested yet (most common case).
142
	return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();
210
        idx = tmpBitField2.Random();
211
        return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();
143
      }
212
      }
213
    } else {
214
      // We don't need anything from the peer.  How'd we get here?
215
      return SetLocal(M_NOT_INTERESTED);
144
    }
216
    }
145
  }
146
  return 0;
217
  return 0;
147
}
218
}
148
219
Lines 152-188 Link Here
152
223
153
  char *msgbuf = stream.in_buffer.BasePointer();
224
  char *msgbuf = stream.in_buffer.BasePointer();
154
225
155
  r = ntohl(*(size_t*) msgbuf);
226
  r = get_nl(msgbuf);
156
227
228
  // Don't require keepalives if we're receiving other messages.
229
  time(&m_last_timestamp);
157
  if( 0 == r ){
230
  if( 0 == r ){
158
    time(&m_last_timestamp);
159
    if( !m_f_keepalive ) if( stream.Send_Keepalive() < 0 ) return -1;
231
    if( !m_f_keepalive ) if( stream.Send_Keepalive() < 0 ) return -1;
160
    m_f_keepalive = 0;
232
    m_f_keepalive = 0;
161
    return (!m_state.remote_choked && request_q.IsEmpty()) ? RequestCheck() : 0;
233
    return 0;
162
  }else{
234
  }else{
163
    switch(msgbuf[4]){
235
    switch(msgbuf[4]){
164
    case M_CHOKE:
236
    case M_CHOKE:
165
      if(H_BASE_LEN != r){ return -1;}
237
      if(H_BASE_LEN != r){ return -1;}
238
      if(arg_verbose) fprintf(stderr, "%p choked me\n", this);
166
      m_state.remote_choked = 1;
239
      m_state.remote_choked = 1;
167
      StopDLTimer();
240
      StopDLTimer();
168
      if( !request_q.IsEmpty()){
241
      if( !request_q.IsEmpty()){
169
	PSLICE ps = request_q.GetHead();
242
	PSLICE ps = request_q.GetHead();
170
	PENDINGQUEUE.Pending(&request_q);
243
	if( !PENDINGQUEUE.Exist(request_q.GetRequestIdx()) )
244
	  PENDINGQUEUE.Pending(&request_q);
171
	if( CancelRequest(ps) < 0) return -1;
245
	if( CancelRequest(ps) < 0) return -1;
172
      }
246
      }
173
      return 0;
247
      return 0;
248
174
    case M_UNCHOKE:
249
    case M_UNCHOKE:
175
      if(H_BASE_LEN != r){return -1;}
250
      if(H_BASE_LEN != r){return -1;}
251
      if(arg_verbose) fprintf(stderr, "%p unchoked me\n", this);
176
      m_state.remote_choked = 0;
252
      m_state.remote_choked = 0;
253
      if(!request_q.IsEmpty())	// shouldn't happen; maybe peer is confused.
254
        return SendRequest();
177
      return RequestCheck();
255
      return RequestCheck();
178
256
179
    case M_INTERESTED:
257
    case M_INTERESTED:
180
      if(H_BASE_LEN != r){return -1;}
258
      if(H_BASE_LEN != r){return -1;}
259
      if(arg_verbose) fprintf(stderr, "%p is interested\n", this);
181
      m_state.remote_interested = 1;
260
      m_state.remote_interested = 1;
182
      break;
261
      break;
183
262
184
    case M_NOT_INTERESTED:
263
    case M_NOT_INTERESTED:
185
      if(r != H_BASE_LEN){return -1;}
264
      if(r != H_BASE_LEN){return -1;}
265
      if(arg_verbose) fprintf(stderr, "%p is not interested\n", this);
186
266
187
      m_state.remote_interested = 0;
267
      m_state.remote_interested = 0;
188
      StopULTimer();
268
      StopULTimer();
Lines 190-199 Link Here
190
      /* remove peer's reponse queue */
270
      /* remove peer's reponse queue */
191
      if( !reponse_q.IsEmpty()) reponse_q.Empty();
271
      if( !reponse_q.IsEmpty()) reponse_q.Empty();
192
      return 0;
272
      return 0;
273
193
    case M_HAVE:
274
    case M_HAVE:
194
      if(H_HAVE_LEN != r){return -1;}
275
      if(H_HAVE_LEN != r){return -1;}
195
276
196
      idx = ntohl(*(size_t*) (msgbuf + 5));
277
      idx = get_nl(msgbuf + 5);
197
278
198
      if( idx >= BTCONTENT.GetNPieces() || bitfield.IsSet(idx)) return -1;
279
      if( idx >= BTCONTENT.GetNPieces() || bitfield.IsSet(idx)) return -1;
199
280
Lines 201-219 Link Here
201
282
202
      if( bitfield.IsFull() && BTCONTENT.pBF->IsFull() ){ return -2; }
283
      if( bitfield.IsFull() && BTCONTENT.pBF->IsFull() ){ return -2; }
203
284
204
      if( !BTCONTENT.pBF->IsSet(idx) ) m_cached_idx = idx;
285
      if( !BTCONTENT.pBF->IsSet(idx) && !BTCONTENT.pBFilter->IsSet(idx) ){
286
        m_cached_idx = idx;
287
        m_standby = 0;
288
      }
289
      //      if( !BTCONTENT.pBF->IsSet(idx) ) m_cached_idx = idx;
205
      
290
      
206
      return ( !m_state.remote_choked && request_q.IsEmpty() ) ? RequestCheck() : 0;
291
      // see if we're Interested now
292
      return request_q.IsEmpty() ? RequestCheck() : 0;
207
293
208
    case M_REQUEST:
294
    case M_REQUEST:
209
      if(H_REQUEST_LEN != r || !m_state.remote_interested){ return -1; }
295
      if(H_REQUEST_LEN != r || !m_state.remote_interested){ return -1; }
210
296
211
      idx = ntohl(*(size_t*)(msgbuf + 5));
297
      idx = get_nl(msgbuf + 5);
212
      
298
      
213
      if( !BTCONTENT.pBF->IsSet(idx) ) return -1;
299
      if( !BTCONTENT.pBF->IsSet(idx) ) return -1;
214
      
300
      
215
      off = ntohl(*(size_t*)(msgbuf + 9));
301
      off = get_nl(msgbuf + 9);
216
      len = ntohl(*(size_t*)(msgbuf + 13));
302
      len = get_nl(msgbuf + 13);
217
303
218
      if( !reponse_q.IsValidRequest(idx, off, len) ) return -1;
304
      if( !reponse_q.IsValidRequest(idx, off, len) ) return -1;
219
      
305
      
Lines 222-227 Link Here
222
    case M_PIECE:
308
    case M_PIECE:
223
      if( request_q.IsEmpty() || !m_state.local_interested){
309
      if( request_q.IsEmpty() || !m_state.local_interested){
224
	m_err_count++;
310
	m_err_count++;
311
	if(arg_verbose) fprintf(stderr,"err: %p (%d) Unwanted piece\n",
312
	  this, m_err_count);
225
	return 0;
313
	return 0;
226
      }
314
      }
227
      return PieceDeliver(r);
315
      return PieceDeliver(r);
Lines 230-251 Link Here
230
      if( (r - 1) != bitfield.NBytes() || !bitfield.IsEmpty()) return -1;
318
      if( (r - 1) != bitfield.NBytes() || !bitfield.IsEmpty()) return -1;
231
      bitfield.SetReferBuffer(msgbuf + 5);
319
      bitfield.SetReferBuffer(msgbuf + 5);
232
      if(bitfield.IsFull() && BTCONTENT.pBF->IsFull()) return -2;
320
      if(bitfield.IsFull() && BTCONTENT.pBF->IsFull()) return -2;
233
      return 0;
321
322
      //This is needed in order to set our Interested state
323
      return RequestCheck(); // fixed client stall
234
324
235
    case M_CANCEL:
325
    case M_CANCEL:
236
      if(r != H_CANCEL_LEN || !m_state.remote_interested) return -1;
326
      if(r != H_CANCEL_LEN || !m_state.remote_interested) return -1;
237
327
238
      idx = ntohl(*(size_t*)(msgbuf + 5));
328
      idx = get_nl(msgbuf + 5);
239
      off = ntohl(*(size_t*)(msgbuf + 9));
329
      off = get_nl(msgbuf + 9);
240
      len = ntohl(*(size_t*)(msgbuf + 13));
330
      len = get_nl(msgbuf + 13);
241
      if( reponse_q.Remove(idx,off,len) < 0 ){
331
      if( reponse_q.Remove(idx,off,len) < 0 ){
242
	m_err_count++;
332
	m_err_count++;
333
	if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad cancel\n",
334
	  this, m_err_count);
243
	return 0;
335
	return 0;
244
      }
336
      }
245
      if( reponse_q.IsEmpty() ) StopULTimer();
337
      if( reponse_q.IsEmpty() ) StopULTimer();
246
      return 0;
338
      return 0;
247
    default:
339
    default:
248
      return -1;		// unknow message type
340
      if(arg_verbose) fprintf(stderr, "Unknown message type %u from peer %p\n",
341
        msgbuf[4], this);
342
      return 0;	// ignore unknown message & continue (forward compatibility)
249
    }
343
    }
250
  }
344
  }
251
  return 0;
345
  return 0;
Lines 279-286 Link Here
279
int btPeer::SendRequest()
373
int btPeer::SendRequest()
280
{
374
{
281
  PSLICE ps = request_q.GetHead();
375
  PSLICE ps = request_q.GetHead();
282
  for( ; ps ; ps = ps->next )
376
  if(arg_verbose) fprintf(stderr, "Requesting #%u from %p:",
377
    request_q.GetRequestIdx(), this);
378
  for( ; ps ; ps = ps->next ){
379
    if(arg_verbose) fprintf(stderr, ".");
283
    if(stream.Send_Request(ps->index,ps->offset,ps->length) < 0){ return -1; }
380
    if(stream.Send_Request(ps->index,ps->offset,ps->length) < 0){ return -1; }
381
  }
382
  if(arg_verbose) fprintf(stderr, "\n");
284
383
285
  return stream.Flush();
384
  return stream.Flush();
286
}
385
}
Lines 294-309 Link Here
294
  return stream.Flush();
393
  return stream.Flush();
295
}
394
}
296
395
396
int btPeer::CancelSliceRequest(size_t idx, size_t off, size_t len)
397
{
398
  PSLICE ps;
399
400
  for(ps = request_q.GetHead() ; ps; ps = ps->next){
401
    if( idx == ps->index && off == ps->offset && len == ps->length ){
402
      if( request_q.Remove(idx,off,len) < 0 ){
403
        m_err_count++;
404
        if(arg_verbose) fprintf(stderr,"err: %p (%d) Bad CS remove\n",
405
          this, m_err_count);
406
      }
407
      if(stream.Send_Cancel(idx,off,len) < 0)
408
        return -1;
409
      return stream.Flush();
410
    }
411
  }
412
  return 0;
413
}
414
297
int btPeer::ReportComplete(size_t idx)
415
int btPeer::ReportComplete(size_t idx)
298
{
416
{
299
  if( BTCONTENT.APieceComplete(idx) ){
417
  if( BTCONTENT.APieceComplete(idx) ){
418
    if(arg_verbose) fprintf(stderr, "Piece #%u completed\n", idx);
300
    WORLD.Tell_World_I_Have(idx);
419
    WORLD.Tell_World_I_Have(idx);
420
    PENDINGQUEUE.Delete(idx);
301
    if( BTCONTENT.pBF->IsFull() ){
421
    if( BTCONTENT.pBF->IsFull() ){
302
      ResetDLTimer();
422
      ResetDLTimer();
303
      WORLD.CloseAllConnectionToSeed();
423
      WORLD.CloseAllConnectionToSeed();
304
    }
424
    }
305
  }else
425
426
    if( arg_file_to_download ){
427
      BitField tmpBitField =  *BTCONTENT.pBF;
428
      tmpBitField.Except(*BTCONTENT.pBFilter);
429
430
      while( arg_file_to_download &&
431
        tmpBitField.Count() >= BTCONTENT.getFilePieces(arg_file_to_download) ){
432
        //when the file is complete, we go after the next
433
        ++arg_file_to_download;
434
        BTCONTENT.FlushCache();
435
        BTCONTENT.SetFilter();
436
        tmpBitField =  *BTCONTENT.pBF;
437
        tmpBitField.Except(*BTCONTENT.pBFilter);
438
      }
439
      WORLD.CheckInterest();
440
    }
441
  }else{
306
    m_err_count++;
442
    m_err_count++;
443
    if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad complete\n",
444
      this, m_err_count);
445
  }
307
  return (P_FAILED == m_status) ? -1 : RequestCheck();
446
  return (P_FAILED == m_status) ? -1 : RequestCheck();
308
}
447
}
309
448
Lines 312-323 Link Here
312
  size_t idx,off,len;
451
  size_t idx,off,len;
313
  char *msgbuf = stream.in_buffer.BasePointer();
452
  char *msgbuf = stream.in_buffer.BasePointer();
314
453
315
  idx = ntohl(*(size_t*) (msgbuf + 5));
454
  idx = get_nl(msgbuf + 5);
316
  off = ntohl(*(size_t*) (msgbuf + 9));
455
  off = get_nl(msgbuf + 9);
317
  len = mlen - 9;
456
  len = mlen - 9;
318
457
319
  if( request_q.Remove(idx,off,len) < 0 ){
458
  if( request_q.Remove(idx,off,len) < 0 ){
320
    m_err_count++;
459
    m_err_count++;
460
    if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad remove\n",
461
      this, m_err_count);
321
    return 0;
462
    return 0;
322
  }
463
  }
323
464
Lines 329-341 Link Here
329
  Self.DataRecved(len);
470
  Self.DataRecved(len);
330
  DataRecved(len);
471
  DataRecved(len);
331
472
473
  // Check for & cancel requests for this slice from other peers in initial
474
  // and endgame modes.
475
  if( BTCONTENT.pBF->Count() < 2 ||
476
      WORLD.Pieces_I_Can_Get() - BTCONTENT.pBF->Count() < WORLD.TotalPeers() ){
477
    WORLD.CancelSlice(idx, off, len);
478
    PENDINGQUEUE.DeleteSlice(idx, off, len);
479
  }
480
332
  /* if piece download complete. */
481
  /* if piece download complete. */
333
  return request_q.IsEmpty() ? ReportComplete(idx) : 0;
482
  return request_q.IsEmpty() ? ReportComplete(idx) : 0;
334
}
483
}
335
484
336
int btPeer::RequestCheck()
485
int btPeer::RequestCheck()
337
{
486
{
338
  if( BandWidthLimit() ) return 0;
487
  if( BandWidthLimitDown() ) return 0;
339
  
488
  
340
  if( BTCONTENT.pBF->IsFull() ){
489
  if( BTCONTENT.pBF->IsFull() ){
341
    if( bitfield.IsFull() ){ return -1; }
490
    if( bitfield.IsFull() ){ return -1; }
Lines 347-353 Link Here
347
    if(request_q.IsEmpty() && !m_state.remote_choked){
496
    if(request_q.IsEmpty() && !m_state.remote_choked){
348
      if( RequestPiece() < 0 ) return -1;
497
      if( RequestPiece() < 0 ) return -1;
349
    }
498
    }
350
  }
499
  } else
500
    if(m_state.local_interested && SetLocal(M_NOT_INTERESTED) < 0) return -1;
351
  
501
  
352
  if(!request_q.IsEmpty()) StartDLTimer();
502
  if(!request_q.IsEmpty()) StartDLTimer();
353
  return 0;
503
  return 0;
Lines 355-360 Link Here
355
505
356
void btPeer::CloseConnection()
506
void btPeer::CloseConnection()
357
{
507
{
508
  if(arg_verbose) fprintf(stderr, "%p closed\n", this);
358
  if( P_FAILED != m_status ){
509
  if( P_FAILED != m_status ){
359
    m_status = P_FAILED;
510
    m_status = P_FAILED;
360
    stream.Close();
511
    stream.Close();
Lines 364-376 Link Here
364
int btPeer::HandShake()
515
int btPeer::HandShake()
365
{
516
{
366
  ssize_t r = stream.Feed();
517
  ssize_t r = stream.Feed();
367
  if( r < 0 ) return -1;
518
  if( r < 0 ){
519
//  if(arg_verbose) fprintf(stderr, "hs: r<0 (%d)\n", r);
520
    return -1;
521
  }
368
  else if( r < 68 ){
522
  else if( r < 68 ){
369
    if(r && memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),r) != 0) return -1;
523
    if(r >= 21){	// Ignore 8 reserved bytes following protocol ID.
524
      if( memcmp(stream.in_buffer.BasePointer()+20,
525
          BTCONTENT.GetShakeBuffer()+20, (r<28) ? r-20 : 8) != 0 ){
526
        if(arg_verbose){
527
          if( r>48 ) fprintf( stderr, "\npeer %p gave 0x", this);
528
          else fprintf( stderr, "\npeer gave 0x" );
529
          for(int i=20; i<r && i<27; i++) fprintf(stderr, "%2.2hx",
530
            (u_short)(u_char)(stream.in_buffer.BasePointer()[i]));
531
          fprintf( stderr, " as reserved bytes (partial)\n" );
532
        }
533
        memcpy(stream.in_buffer.BasePointer()+20, BTCONTENT.GetShakeBuffer()+20,
534
          (r<28) ? r-20 : 8);
535
      }
536
    }
537
    if(r && memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),
538
        (r<48) ? r : 48) != 0){
539
      if(arg_verbose){
540
        fprintf(stderr, "\nmine: 0x");
541
        for(int i=0; i<r && i<48; i++) fprintf(stderr, "%2.2hx",
542
          (u_short)(u_char)(BTCONTENT.GetShakeBuffer()[i]));
543
        fprintf(stderr, "\npeer: 0x");
544
        for(int i=0; i<r && i<48; i++) fprintf(stderr, "%2.2hx",
545
          (u_short)(u_char)(stream.in_buffer.BasePointer()[i]));
546
        fprintf(stderr, "\n");
547
        fprintf(stderr, "peer is %.8s\n", stream.in_buffer.BasePointer()+48);
548
      }
549
      return -1;
550
    }
370
    return 0;
551
    return 0;
371
  }
552
  }
372
553
373
  if( memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),48) != 0 ) return -1;
554
  // If the reserved bytes differ, make them the same.
555
  // If they mean anything important, the handshake is likely to fail anyway.
556
  if( memcmp(stream.in_buffer.BasePointer()+20, BTCONTENT.GetShakeBuffer()+20,
557
      8) != 0 ){
558
    if(arg_verbose){
559
      fprintf(stderr, "\npeer %p gave 0x", this);
560
      for(int i=20; i<27; i++) fprintf(stderr, "%2.2hx",
561
        (u_short)(u_char)(stream.in_buffer.BasePointer()[i]));
562
      fprintf( stderr, " as reserved bytes\n" );
563
    }
564
    memcpy(stream.in_buffer.BasePointer()+20, BTCONTENT.GetShakeBuffer()+20, 8);
565
  }
566
  if( memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),48) != 0 ){
567
    if(arg_verbose){
568
      fprintf(stderr, "\nmine: 0x");
569
      for(int i=0; i<48; i++) fprintf(stderr, "%2.2hx",
570
        (u_short)(u_char)(BTCONTENT.GetShakeBuffer()[i]));
571
      fprintf(stderr, "\npeer: 0x");
572
      for(int i=0; i<48; i++) fprintf(stderr, "%2.2hx",
573
        (u_short)(u_char)(stream.in_buffer.BasePointer()[i]));
574
      fprintf(stderr, "\n");
575
    }
576
    return -1;
577
  }
578
579
  if(arg_verbose){
580
    fprintf(stderr, "Peer %p ID: ", this);
581
    for(int i=48; i<60; i++){
582
      if( isprint(stream.in_buffer.BasePointer()[i]) )
583
        fprintf(stderr, "%c", stream.in_buffer.BasePointer()[i]);
584
      else break;
585
    }
586
    fprintf(stderr, "\n");
587
  }
374
588
375
  // ignore peer id verify
589
  // ignore peer id verify
376
  if( !BTCONTENT.pBF->IsEmpty()){
590
  if( !BTCONTENT.pBF->IsEmpty()){
Lines 395-404 Link Here
395
  return stream.Send_Buffer((char*)BTCONTENT.GetShakeBuffer(),68);
609
  return stream.Send_Buffer((char*)BTCONTENT.GetShakeBuffer(),68);
396
}
610
}
397
611
398
int btPeer::BandWidthLimit()
612
int btPeer::BandWidthLimitUp()
613
{
614
  if( cfg_max_bandwidth_up <= 0 ) return 0;
615
  return ((Self.RateUL()) >= cfg_max_bandwidth_up) ?
616
    1:0;
617
}
618
619
int btPeer::BandWidthLimitDown()
399
{
620
{
400
  if( cfg_max_bandwidth <= 0 ) return 0;
621
  if( cfg_max_bandwidth_down <= 0 ) return 0;
401
  return ((Self.RateDL() + Self.RateUL()*2) / 1024 >= cfg_max_bandwidth) ?
622
  return ((Self.RateDL()) >= cfg_max_bandwidth_down) ?
402
    1:0;
623
    1:0;
403
}
624
}
404
625
Lines 406-417 Link Here
406
{
627
{
407
  int yn = 0;
628
  int yn = 0;
408
  if( stream.out_buffer.Count() || // data need send in buffer.
629
  if( stream.out_buffer.Count() || // data need send in buffer.
409
      (!reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimit()) ||
630
      (!reponse_q.IsEmpty() && CouldReponseSlice() && !  BandWidthLimitUp()) ||
631
      ( !m_state.remote_choked && request_q.IsEmpty()
632
	    && m_state.local_interested
633
	    && !BandWidthLimitDown() && !m_standby ) ||	// can request a piece.
410
      P_CONNECTING == m_status ) // peer is connecting
634
      P_CONNECTING == m_status ) // peer is connecting
411
    yn = 1;
635
    yn = 1;
412
  return yn;
636
  return yn;
413
}
637
}
414
638
639
int btPeer::NeedRead()
640
{
641
  int yn = 1;
642
  if( !request_q.IsEmpty() && BandWidthLimitDown() )
643
    yn = 0;
644
  return yn;
645
}
646
415
int btPeer::CouldReponseSlice()
647
int btPeer::CouldReponseSlice()
416
{
648
{
417
  if(!m_state.local_choked &&
649
  if(!m_state.local_choked &&
Lines 453-467 Link Here
453
{
685
{
454
  if( stream.out_buffer.Count() && stream.Flush() < 0) return -1;
686
  if( stream.out_buffer.Count() && stream.Flush() < 0) return -1;
455
687
456
  if(! reponse_q.IsEmpty() &&  CouldReponseSlice() ) {
688
  if( !reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimitUp() ) {
457
    StartULTimer();
689
    StartULTimer();
458
    Self.StartULTimer();
690
    Self.StartULTimer();
459
  }
691
  }
460
692
461
  for(; !reponse_q.IsEmpty() && CouldReponseSlice(); )
693
  for(; !reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimitUp(); )
462
    if( ReponseSlice() < 0) return -1;
694
    if( ReponseSlice() < 0) return -1;
463
695
464
  return 0;
696
  return (!m_state.remote_choked && request_q.IsEmpty()) ? RequestCheck() : 0;
465
}
697
}
466
698
467
void btPeer::dump()
699
void btPeer::dump()
(-)peer.h.orig (+8 lines)
Lines 34-39 Link Here
34
  unsigned char reserved:4;		/* unused */
34
  unsigned char reserved:4;		/* unused */
35
}BTSTATUS;
35
}BTSTATUS;
36
36
37
size_t get_nl(char *from);
38
void set_nl(char *to, size_t from);
39
37
class btBasic
40
class btBasic
38
{
41
{
39
private:
42
private:
Lines 84-89 Link Here
84
87
85
  size_t m_cached_idx;
88
  size_t m_cached_idx;
86
  size_t m_err_count;
89
  size_t m_err_count;
90
  int m_standby;
87
  
91
  
88
  int PieceDeliver(size_t mlen);
92
  int PieceDeliver(size_t mlen);
89
  int ReportComplete(size_t idx);
93
  int ReportComplete(size_t idx);
Lines 96-101 Link Here
96
  int CouldReponseSlice();
100
  int CouldReponseSlice();
97
101
98
  int BandWidthLimit();
102
  int BandWidthLimit();
103
  int BandWidthLimitUp();
104
  int BandWidthLimitDown();
99
 public:
105
 public:
100
  BitField bitfield;
106
  BitField bitfield;
101
  btStream stream;
107
  btStream stream;
Lines 118-127 Link Here
118
  int Is_Local_UnChoked() const { return m_state.local_choked ? 0 : 1; }
124
  int Is_Local_UnChoked() const { return m_state.local_choked ? 0 : 1; }
119
  int SetLocal(unsigned char s);
125
  int SetLocal(unsigned char s);
120
126
127
  int CancelSliceRequest(size_t idx, size_t off, size_t len);
121
  
128
  
122
  void SetStatus(unsigned char s){ m_status = s; }
129
  void SetStatus(unsigned char s){ m_status = s; }
123
  unsigned char GetStatus() const { return m_status; }
130
  unsigned char GetStatus() const { return m_status; }
124
  int NeedWrite();
131
  int NeedWrite();
132
  int NeedRead();
125
133
126
  
134
  
127
  void CloseConnection();
135
  void CloseConnection();
(-)peerlist.cpp.orig (-38 / +229 lines)
Lines 21-26 Link Here
21
#define MAX_UNCHOKE 3
21
#define MAX_UNCHOKE 3
22
#define UNCHOKE_INTERVAL 10
22
#define UNCHOKE_INTERVAL 10
23
23
24
#define OPT_INTERVAL 30
25
24
#define KEEPALIVE_INTERVAL 117
26
#define KEEPALIVE_INTERVAL 117
25
27
26
#define LISTEN_PORT_MAX 2706
28
#define LISTEN_PORT_MAX 2706
Lines 36-47 Link Here
36
38
37
PeerList::PeerList()
39
PeerList::PeerList()
38
{
40
{
39
  m_unchoke_check_timestamp = 
41
  m_unchoke_check_timestamp =
40
    m_keepalive_check_timestamp = time((time_t*) 0);
42
    m_keepalive_check_timestamp =
43
    m_opt_timestamp = time((time_t*) 0);
41
44
42
  m_head = (PEERNODE*) 0;
45
  m_head = (PEERNODE*) 0;
43
  m_listen_sock = INVALID_SOCKET;
46
  m_listen_sock = INVALID_SOCKET;
44
  m_peers_count = 0;
47
  m_peers_count = m_seeds_count = 0;
45
  m_live_idx = 0;
48
  m_live_idx = 0;
46
}
49
}
47
50
Lines 118-123 Link Here
118
    
121
    
119
    if( setfd_nonblock(sk) < 0) goto err;
122
    if( setfd_nonblock(sk) < 0) goto err;
120
123
124
    if(arg_verbose) fprintf(stderr, "Connecting to %s:%hu\n",
125
        inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
121
    if( -1 == (r = connect_nonb(sk,(struct sockaddr*)&addr)) ) return -1;
126
    if( -1 == (r = connect_nonb(sk,(struct sockaddr*)&addr)) ) return -1;
122
127
123
    peer = new btPeer;
128
    peer = new btPeer;
Lines 182-200 Link Here
182
    if(NewPeer(addr,INVALID_SOCKET) == -4) break;
187
    if(NewPeer(addr,INVALID_SOCKET) == -4) break;
183
  }
188
  }
184
189
190
185
  // show status line.
191
  // show status line.
186
  if( m_pre_dlrate.TimeUsed(pnow) ){
192
  if( m_pre_dlrate.TimeUsed(pnow) ){
187
    printf("\r                                                                           ");
193
    char partial[30] = "";
188
	printf("\r%c %u,[%u/%u/%u],%u,%u | %u,%u  E:%u",
194
    if(arg_file_to_download){
195
      BitField tmpBitField =  *BTCONTENT.pBF;
196
      tmpBitField.Except(*BTCONTENT.pBFilter);
197
      sprintf( partial, "P:%u/%u ", 
198
	tmpBitField.Count(),
199
	BTCONTENT.getFilePieces(arg_file_to_download) );
200
    }
201
    printf("\r                                                                               ");
202
    printf("\r%c %u/%u/%u [%u/%u/%u] %lluMB,%lluMB | %u,%uK/s | %u,%uK E:%u,%u %s%s ",
189
	   LIVE_CHAR[m_live_idx],
203
	   LIVE_CHAR[m_live_idx],
190
	   m_peers_count,
204
205
	   m_seeds_count,
206
	   m_peers_count - m_seeds_count,
207
	   Tracker.GetPeersCount(),
208
191
	   BTCONTENT.pBF->Count(),
209
	   BTCONTENT.pBF->Count(),
192
	   BTCONTENT.pBF->NBits(),
210
	   BTCONTENT.pBF->NBits(),
193
	   Pieces_I_Can_Get(),
211
	   Pieces_I_Can_Get(),
194
	   Self.RateDL(), Self.RateUL(),
212
195
	   m_pre_dlrate.RateMeasure(Self.GetDLRate()),
213
 	   Self.TotalDL() >> 20, Self.TotalUL() >> 20,
196
	   m_pre_ulrate.RateMeasure(Self.GetULRate()),
214
197
	   Tracker.GetRefuseClick());
215
	   Self.RateDL() >> 10, Self.RateUL() >> 10,
216
217
	   m_pre_dlrate.RateMeasure(Self.GetDLRate()) >> 10,
218
	   m_pre_ulrate.RateMeasure(Self.GetULRate()) >> 10,
219
220
	   Tracker.GetRefuseClick(),
221
	   Tracker.GetOkClick(),
222
223
	   partial,
224
225
	   (Tracker.GetStatus()==1) ? "Connecting" :
226
	       ((Tracker.GetStatus()==2) ? "Connected" : "")
227
    );
198
    fflush(stdout);
228
    fflush(stdout);
199
    m_pre_dlrate = Self.GetDLRate();
229
    m_pre_dlrate = Self.GetDLRate();
200
    m_pre_ulrate = Self.GetULRate();
230
    m_pre_ulrate = Self.GetULRate();
Lines 214-221 Link Here
214
    Sort();
244
    Sort();
215
  }
245
  }
216
246
217
  if( f_unchoke_check ) memset(UNCHOKER, 0, (MAX_UNCHOKE + 1) * sizeof(btPeer*));
247
  if( f_unchoke_check ) {
248
    memset(UNCHOKER, 0, (MAX_UNCHOKE + 1) * sizeof(btPeer*));
249
    if (OPT_INTERVAL <= *pnow - m_opt_timestamp) m_opt_timestamp = 0;
250
  }
218
251
252
  m_seeds_count = 0;
219
  for(p = m_head; p;){
253
  for(p = m_head; p;){
220
    if( PEER_IS_FAILED(p->peer)){
254
    if( PEER_IS_FAILED(p->peer)){
221
      if( pp ) pp->next = p->next; else m_head = p->next;
255
      if( pp ) pp->next = p->next; else m_head = p->next;
Lines 225-233 Link Here
225
      if( pp ) p = pp->next; else p = m_head;
259
      if( pp ) p = pp->next; else p = m_head;
226
      continue;
260
      continue;
227
    }else{
261
    }else{
262
      if (p->peer->bitfield.IsFull()) m_seeds_count++;
228
      if( f_keepalive_check ){
263
      if( f_keepalive_check ){
229
264
230
	if(3 * KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp())){
265
	if(3 * KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp())){
266
	  if(arg_verbose) fprintf(stderr, "close: keepalive expired\n");
231
	  p->peer->CloseConnection();
267
	  p->peer->CloseConnection();
232
	  goto skip_continue;
268
	  goto skip_continue;
233
	}
269
	}
Lines 235-262 Link Here
235
	if(PEER_IS_SUCCESS(p->peer) && 
271
	if(PEER_IS_SUCCESS(p->peer) && 
236
	   KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp()) &&
272
	   KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp()) &&
237
	   p->peer->AreYouOK() < 0){
273
	   p->peer->AreYouOK() < 0){
274
	   if(arg_verbose) fprintf(stderr, "close: keepalive death\n");
238
	  p->peer->CloseConnection();
275
	  p->peer->CloseConnection();
239
	  goto skip_continue;
276
	  goto skip_continue;
240
	}
277
	}
241
      }
278
      }
242
279
243
      if( f_unchoke_check ){
280
      if( f_unchoke_check && PEER_IS_SUCCESS(p->peer) ){
244
245
	if(PEER_IS_SUCCESS(p->peer) && p->peer->Need_Local_Data()){
246
281
247
	  if((time_t) 0 == p->peer->GetLastUnchokeTime()){
282
	if( p->peer->Is_Remote_Interested() && p->peer->Need_Local_Data() )
248
	    if(p->peer->SetLocal(M_UNCHOKE) < 0){
249
	      p->peer->CloseConnection();
250
	      goto skip_continue;
251
	    }
252
	  }else
253
	    UnChokeCheck(p->peer, UNCHOKER);
283
	    UnChokeCheck(p->peer, UNCHOKER);
254
	}
284
	else if(p->peer->SetLocal(M_CHOKE) < 0){
285
	  if(arg_verbose) fprintf(stderr, "close: Can't choke peer\n");
286
	  p->peer->CloseConnection();
287
	  goto skip_continue;
288
        }
255
      }
289
      }
256
290
257
      sk = p->peer->stream.GetSocket();
291
      sk = p->peer->stream.GetSocket();
258
      if(maxfd < sk) maxfd = sk;
292
      if(maxfd < sk) maxfd = sk;
259
      FD_SET(sk,rfdp);
293
      if( p->peer->NeedRead() ) FD_SET(sk,rfdp);
260
294
261
      if( p->peer->NeedWrite() ) FD_SET(sk,wfdp);
295
      if( p->peer->NeedWrite() ) FD_SET(sk,wfdp);
262
    skip_continue: 
296
    skip_continue: 
Lines 272-284 Link Here
272
  }
306
  }
273
307
274
  if( f_unchoke_check ){
308
  if( f_unchoke_check ){
309
//  if (!m_opt_timestamp) m_opt_timestamp = *pnow;
310
    if(arg_verbose) fprintf(stderr, "\nUnchoker ");
311
    if (!m_opt_timestamp){
312
      if(arg_verbose) fprintf(stderr, "(opt) ");
313
      m_opt_timestamp = *pnow;
314
    }
275
    for( i = 0; i < MAX_UNCHOKE + 1; i++){
315
    for( i = 0; i < MAX_UNCHOKE + 1; i++){
276
316
277
      if( (btPeer*) 0 == UNCHOKER[i]) break;
317
      if( (btPeer*) 0 == UNCHOKER[i]) break;
278
318
279
      if( PEER_IS_FAILED(UNCHOKER[i]) ) continue;
319
      if( PEER_IS_FAILED(UNCHOKER[i]) ) continue;
280
320
321
      if(arg_verbose){
322
        fprintf(stderr, "D=%lluMB@%uK/s:U=%lluMB ",
323
          UNCHOKER[i]->TotalDL() >> 20, UNCHOKER[i]->RateDL() >> 10,
324
          UNCHOKER[i]->TotalUL() >> 20);
325
        if( UNCHOKER[i]->bitfield.IsEmpty() ) fprintf(stderr, "(empty) ");
326
      }
281
      if( UNCHOKER[i]->SetLocal(M_UNCHOKE) < 0){
327
      if( UNCHOKER[i]->SetLocal(M_UNCHOKE) < 0){
328
        if(arg_verbose) fprintf(stderr, "close: Can't unchoke peer\n");
282
	UNCHOKER[i]->CloseConnection();
329
	UNCHOKER[i]->CloseConnection();
283
	continue;
330
	continue;
284
      }
331
      }
Lines 290-295 Link Here
290
	if( maxfd < sk) maxfd = sk;
337
	if( maxfd < sk) maxfd = sk;
291
      }
338
      }
292
    } // end for
339
    } // end for
340
    if(arg_verbose) fprintf(stderr, "\n");
293
  }
341
  }
294
  
342
  
295
  return maxfd;
343
  return maxfd;
Lines 314-319 Link Here
314
  return peer;
362
  return peer;
315
}
363
}
316
364
365
// Duplicating a request queue that's in progress rather than creating a new
366
// one helps avoid requesting slices that we already have.
367
// This takes an index parameter to facilitate modification of the function to
368
// allow targeting of a specific piece.  It's currently only used as a flag to
369
// specify endgame or initial-piece mode though.
370
btPeer* PeerList::Who_Can_Duplicate(btPeer *proposer, size_t idx)
371
{
372
  PEERNODE *p;
373
  btPeer *peer = (btPeer*) 0;
374
  int endgame;
375
  size_t qsize, mark, bench;
376
  // In endgame mode, select from peers with the longest request queue.
377
  // In initial mode, select from peers with the shortest non-empty request
378
  // queue.
379
380
  endgame = idx < BTCONTENT.GetNPieces();	// else initial-piece mode
381
  if(endgame) mark = 0;
382
  else mark = cfg_req_queue_length;
383
  bench = BTCONTENT.GetNPieces();
384
385
  for(p = m_head; p; p = p->next){
386
    if(!PEER_IS_SUCCESS(p->peer) || p->peer == proposer ||
387
       p->peer->request_q.IsEmpty() ) continue;
388
389
    if(proposer->bitfield.IsSet(p->peer->request_q.GetRequestIdx())){
390
      qsize = p->peer->request_q.Qsize();
391
      if( (endgame && qsize > mark) || (!endgame && qsize && qsize < mark) ){
392
        mark = qsize;
393
        peer = p->peer;
394
      }else if( qsize == mark ){
395
        if( bench != p->peer->request_q.GetRequestIdx() && random()&01 ){
396
          bench = peer->request_q.GetRequestIdx();
397
          peer = p->peer;
398
        }
399
      }
400
    }
401
  }
402
  return peer;
403
}
404
405
void PeerList::CancelSlice(size_t idx, size_t off, size_t len)
406
{
407
  PEERNODE *p;
408
  PSLICE ps;
409
410
  for( p = m_head; p; p = p->next){
411
    
412
    if( !PEER_IS_SUCCESS(p->peer) ) continue;
413
414
    if( idx == p->peer->request_q.GetRequestIdx() ) {
415
      if (p->peer->CancelSliceRequest(idx,off,len) < 0) {
416
        if(arg_verbose) fprintf(stderr, "close: CancelSlice\n");
417
        p->peer->CloseConnection();
418
      }
419
    }
420
  }
421
}
422
317
void PeerList::Tell_World_I_Have(size_t idx)
423
void PeerList::Tell_World_I_Have(size_t idx)
318
{
424
{
319
  PEERNODE *p;
425
  PEERNODE *p;
Lines 330-336 Link Here
330
    
436
    
331
    if( f_seed ){
437
    if( f_seed ){
332
      if( !p->peer->request_q.IsEmpty() ) p->peer->request_q.Empty();
438
      if( !p->peer->request_q.IsEmpty() ) p->peer->request_q.Empty();
333
      if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) p->peer->CloseConnection();
439
//    if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) p->peer->CloseConnection();
440
      if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) {
441
        if(arg_verbose)
442
          fprintf(stderr, "close: Can't set self not interested (T_W_I_H)\n");
443
        p->peer->CloseConnection();
444
      }
334
    }
445
    }
335
    
446
    
336
  } // end for
447
  } // end for
Lines 474-488 Link Here
474
	FD_CLR(sk,wfdp);
585
	FD_CLR(sk,wfdp);
475
586
476
	if(FD_ISSET(sk,rfdp)){	// connect failed.
587
	if(FD_ISSET(sk,rfdp)){	// connect failed.
588
	  (*nready)--; 
477
	  FD_CLR(sk,rfdp);
589
	  FD_CLR(sk,rfdp);
478
	  peer->CloseConnection();
590
	  peer->CloseConnection();
479
	}else{
591
	}else{
480
	  if(peer->Send_ShakeInfo() < 0){
592
	  if(peer->Send_ShakeInfo() < 0){
593
	    if(arg_verbose) fprintf(stderr, "close: Sending handshake\n");
481
	    peer->CloseConnection();
594
	    peer->CloseConnection();
482
	  }
595
	  }
483
	  else 
596
	  else 
484
	    peer->SetStatus(P_HANDSHAKE);
597
	    peer->SetStatus(P_HANDSHAKE);
485
	}
598
	}
599
      }else if(FD_ISSET(sk,rfdp)){
600
	(*nready)--; 
601
	peer->CloseConnection();
486
      }
602
      }
487
    }else{
603
    }else{
488
      if(FD_ISSET(sk,rfdp)){
604
      if(FD_ISSET(sk,rfdp)){
Lines 493-510 Link Here
493
	(*nready)--;
609
	(*nready)--;
494
	FD_CLR(sk,rfdp);
610
	FD_CLR(sk,rfdp);
495
	if(peer->GetStatus() == P_HANDSHAKE){
611
	if(peer->GetStatus() == P_HANDSHAKE){
496
	  if( peer->HandShake() < 0 ) peer->CloseConnection();
612
	  if( peer->HandShake() < 0 ) {
497
	}else{
613
	    if(arg_verbose) fprintf(stderr, "close: bad handshake\n");
498
	  if( peer->RecvModule() < 0 ) peer->CloseConnection();
614
	    peer->CloseConnection();
615
	  }
616
	} // fixed client stall
617
	if(peer->GetStatus() == P_SUCCESS){
618
	  if( peer->RecvModule() < 0 ) {
619
	    if(arg_verbose) fprintf(stderr, "close: receive\n");
620
	    peer->CloseConnection();
621
	  }
499
	}
622
	}
500
      }else if(PEER_IS_SUCCESS(peer) && FD_ISSET(sk,wfdp)){
623
      }
624
      if(PEER_IS_SUCCESS(peer) && FD_ISSET(sk,wfdp)){
501
	p->click++;
625
	p->click++;
502
	if( !(p->click) )
626
	if( !(p->click) )
503
	  for(p2 = m_head; p2; p2=p2->next) p2->click = 0;
627
	  for(p2 = m_head; p2; p2=p2->next) p2->click = 0;
504
628
505
	(*nready)--;
629
	(*nready)--;
506
	FD_CLR(sk,wfdp);
630
	FD_CLR(sk,wfdp);
507
	if( peer->SendModule() < 0 ) peer->CloseConnection();
631
	if( peer->SendModule() < 0 ) {
632
	  if(arg_verbose) fprintf(stderr, "close: send\n");
633
	  peer->CloseConnection();
634
	}
508
      }
635
      }
509
    }
636
    }
510
  }// end for
637
  }// end for
Lines 514-520 Link Here
514
{
641
{
515
  PEERNODE *p = m_head;
642
  PEERNODE *p = m_head;
516
  for( ; p; p = p->next)
643
  for( ; p; p = p->next)
517
    if(p->peer->bitfield.IsFull()) p->peer->CloseConnection();
644
//  if(p->peer->bitfield.IsFull()) p->peer->CloseConnection();
645
    if(p->peer->bitfield.IsFull()) {
646
      if(arg_verbose) fprintf(stderr, "close: seed<->seed\n");
647
      p->peer->CloseConnection();
648
    }
518
}
649
}
519
650
520
void PeerList::UnChokeCheck(btPeer* peer, btPeer *peer_array[])
651
void PeerList::UnChokeCheck(btPeer* peer, btPeer *peer_array[])
Lines 523-530 Link Here
523
  int cancel_idx = 0;
654
  int cancel_idx = 0;
524
  btPeer *loster = (btPeer*) 0;
655
  btPeer *loster = (btPeer*) 0;
525
  int f_seed = BTCONTENT.pBF->IsFull();
656
  int f_seed = BTCONTENT.pBF->IsFull();
657
  int no_opt = 0;
658
659
  if (m_opt_timestamp) no_opt = 1;
526
660
527
  for( cancel_idx = i = 0; i < MAX_UNCHOKE; i++ ){
661
// Find my 3 or 4 fastest peers.
662
// The MAX_UNCHOKE+1 (4th) slot is for the optimistic unchoke when it happens.
663
664
  // Find a slot for the candidate--the slowest peer, or an available slot.
665
  for( cancel_idx = i = 0; i < MAX_UNCHOKE+no_opt; i++ ){
528
    if((btPeer*) 0 == peer_array[i] || PEER_IS_FAILED(peer_array[i]) ){	// ÓпÕλ
666
    if((btPeer*) 0 == peer_array[i] || PEER_IS_FAILED(peer_array[i]) ){	// ÓпÕλ
529
      cancel_idx = i; 
667
      cancel_idx = i; 
530
      break;
668
      break;
Lines 537-543 Link Here
537
	  cancel_idx = i;
675
	  cancel_idx = i;
538
      }else{
676
      }else{
539
	// compare download rate.
677
	// compare download rate.
540
	if(peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL())
678
//	if(peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL())
679
	if( peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL()
680
          //if equal, reciprocate to the peer we've sent less to, proportionally
681
          ||(peer_array[cancel_idx]->RateDL() == peer_array[i]->RateDL()
682
            && peer_array[cancel_idx]->TotalUL()
683
                / (peer_array[cancel_idx]->TotalDL()+.001)
684
              < peer_array[i]->TotalUL() / (peer_array[i]->TotalDL()+.001)) )
541
	  cancel_idx = i;
685
	  cancel_idx = i;
542
      }
686
      }
543
    }
687
    }
Lines 551-557 Link Here
551
      }else
695
      }else
552
	loster = peer;
696
	loster = peer;
553
    }else{
697
    }else{
554
      if(peer->RateDL() > peer_array[cancel_idx]->RateDL()){
698
//    if(peer->RateDL() > peer_array[cancel_idx]->RateDL()){
699
      if( peer->RateDL() > peer_array[cancel_idx]->RateDL()
700
        // If equal, reciprocate to the peer we've sent less to, proportionally
701
        ||(peer_array[cancel_idx]->RateDL() == peer->RateDL()
702
          && peer_array[cancel_idx]->TotalUL()
703
                / (peer_array[cancel_idx]->TotalDL()+.001)
704
            > peer->TotalUL() / (peer->TotalDL()+.001)) ){
555
	loster = peer_array[cancel_idx];
705
	loster = peer_array[cancel_idx];
556
	peer_array[cancel_idx] = peer;
706
	peer_array[cancel_idx] = peer;
557
      }else
707
      }else
Lines 559-573 Link Here
559
    }
709
    }
560
710
561
    // opt unchoke
711
    // opt unchoke
562
    if((btPeer*) 0 == peer_array[MAX_UNCHOKE] || PEER_IS_FAILED(peer_array[MAX_UNCHOKE]) )
712
    if (no_opt) {
713
      if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection();
714
    }
715
    else
716
    // The last slot is for the optimistic unchoke.
717
    // Bump the loser into it if he's been waiting longer than the occupant.
718
    if((btPeer*) 0 == peer_array[MAX_UNCHOKE] || PEER_IS_FAILED(peer_array[MAX_UNCHOKE]))
563
      peer_array[MAX_UNCHOKE] = loster;
719
      peer_array[MAX_UNCHOKE] = loster;
564
    else{
720
    else {
565
      if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime())
721
//    if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime()) {
566
	peer_array[MAX_UNCHOKE] = loster;
722
      // if loser is empty and current is not, loser gets 75% chance.
567
      else{
723
      if( loster->bitfield.IsEmpty() && !peer_array[MAX_UNCHOKE]->bitfield.IsEmpty()
568
	if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection();
724
            && random()&03 ) {
725
        btPeer* tmp = peer_array[MAX_UNCHOKE];
726
        peer_array[MAX_UNCHOKE] = loster;
727
        loster = tmp;
728
      } else // if loser waited longer:
729
      if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime()) {
730
        // if current is empty and loser is not, loser gets 25% chance;
731
        //    else loser wins.
732
        // transformed to: if loser is empty or current isn't, or 25% chance,
733
        //    then loser wins.
734
        if( !peer_array[MAX_UNCHOKE]->bitfield.IsEmpty() || loster->bitfield.IsEmpty()
735
            || !random()&03 ) {
736
          btPeer* tmp = peer_array[MAX_UNCHOKE];
737
          peer_array[MAX_UNCHOKE] = loster;
738
          loster = tmp;
739
        }
569
      }
740
      }
741
      if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection();
570
    }
742
    }
571
  }else //else if((btPeer*) 0 != peer_array[cancel_idx].....
743
  }else //else if((btPeer*) 0 != peer_array[cancel_idx].....
572
    peer_array[cancel_idx] = peer;
744
    peer_array[cancel_idx] = peer;
573
}
745
}
746
747
// When we change what we're going after, we need to evaluate & set our
748
// interest with each peer appropriately.
749
void PeerList::CheckInterest()
750
{
751
  PEERNODE *p = m_head;
752
  for( ; p; p = p->next) {
753
    // Don't shortcut by checking Is_Local_Interested(), as we need to let
754
    // SetLocal() reset the m_standby flag.
755
    if( p->peer->Need_Remote_Data() ) {
756
      if( p->peer->SetLocal(M_INTERESTED) < 0 )
757
        p->peer->CloseConnection();
758
    } else {
759
      if( p->peer->SetLocal(M_NOT_INTERESTED) < 0 )
760
        p->peer->CloseConnection();
761
    }
762
  }
763
}
764
(-)peerlist.h.orig (-1 / +5 lines)
Lines 18-24 Link Here
18
  SOCKET m_listen_sock;
18
  SOCKET m_listen_sock;
19
  PEERNODE *m_head;
19
  PEERNODE *m_head;
20
  size_t m_peers_count;
20
  size_t m_peers_count;
21
  time_t m_unchoke_check_timestamp, m_keepalive_check_timestamp, m_last_progress_timestamp;
21
  size_t m_seeds_count;
22
  time_t m_unchoke_check_timestamp, m_keepalive_check_timestamp, m_last_progress_timestamp, m_opt_timestamp;
22
23
23
  unsigned char m_live_idx:2;
24
  unsigned char m_live_idx:2;
24
  unsigned char m_reserved:6;
25
  unsigned char m_reserved:6;
Lines 50-58 Link Here
50
  
51
  
51
  void Tell_World_I_Have(size_t idx);
52
  void Tell_World_I_Have(size_t idx);
52
  btPeer* Who_Can_Abandon(btPeer *proposer);
53
  btPeer* Who_Can_Abandon(btPeer *proposer);
54
  btPeer* Who_Can_Duplicate(btPeer *proposer, size_t idx);
55
  void CancelSlice(size_t idx, size_t off, size_t len);
53
  void CheckBitField(BitField &bf);
56
  void CheckBitField(BitField &bf);
54
  int AlreadyRequested(size_t idx);
57
  int AlreadyRequested(size_t idx);
55
  size_t Pieces_I_Can_Get();
58
  size_t Pieces_I_Can_Get();
59
  void CheckInterest();
56
};
60
};
57
61
58
extern PeerList WORLD;
62
extern PeerList WORLD;
(-)rate.cpp.orig (-5 / +43 lines)
Lines 1-5 Link Here
1
#include "rate.h"
1
#include "rate.h"
2
2
3
#define RATE_INTERVAL 20
4
3
void Rate::StartTimer()
5
void Rate::StartTimer()
4
{
6
{
5
  if( !m_last_timestamp ) time(&m_last_timestamp);
7
  if( !m_last_timestamp ) time(&m_last_timestamp);
Lines 7-13 Link Here
7
9
8
void Rate::StopTimer()
10
void Rate::StopTimer()
9
{
11
{
10
  if( !m_last_timestamp ){
12
  if( m_last_timestamp ){
11
    m_total_timeused += (time((time_t*) 0) - m_last_timestamp);
13
    m_total_timeused += (time((time_t*) 0) - m_last_timestamp);
12
    m_last_timestamp = 0;
14
    m_last_timestamp = 0;
13
  }
15
  }
Lines 15-21 Link Here
15
17
16
void Rate::CountAdd(size_t nbytes)
18
void Rate::CountAdd(size_t nbytes)
17
{
19
{
20
  time_t now = time((time_t*) 0);
21
18
  m_count_bytes += nbytes;
22
  m_count_bytes += nbytes;
23
24
  // save bandwidth history data
25
  for (int i=0; i <= n_samples; i++)
26
  {
27
    if (i < MAX_SAMPLES)
28
    {
29
      if (now == m_timestamp_sample[i]) {
30
        m_bytes_sample[i] += nbytes;
31
        break;
32
      }
33
      else if (now - RATE_INTERVAL > m_timestamp_sample[i]) {
34
        m_timestamp_sample[i] = now;
35
        m_bytes_sample[i] = nbytes;
36
        if (n_samples < MAX_SAMPLES) n_samples++;
37
        break;
38
      }
39
    }
40
  }
19
}
41
}
20
42
21
void Rate::operator=(const Rate &ra)
43
void Rate::operator=(const Rate &ra)
Lines 26-42 Link Here
26
48
27
size_t Rate::RateMeasure() const
49
size_t Rate::RateMeasure() const
28
{
50
{
29
  time_t timeused = m_total_timeused;
51
  // calculate rate based on bandwidth history data
30
  if( m_last_timestamp ) timeused += (time((time_t*) 0) - m_last_timestamp);
52
  time_t timestamp = time((time_t*) 0);
53
  u_int64_t countbytes = 0;
54
  time_t timeused = 0;
55
56
  if( !m_last_timestamp ) return 0; // no current rate
57
58
  timeused = (TimeUsed(&timestamp) < RATE_INTERVAL) ?
59
    TimeUsed(&timestamp) : RATE_INTERVAL;
31
  if( timeused < 1 ) timeused = 1;
60
  if( timeused < 1 ) timeused = 1;
32
  return (size_t)(m_count_bytes / timeused);
61
62
  for (int i=0; i<n_samples; i++)
63
  {
64
    if (timestamp - m_timestamp_sample[i] <= timeused)
65
      countbytes += m_bytes_sample[i];
66
  }
67
  return (size_t)(countbytes / timeused);
33
}
68
}
34
69
35
size_t Rate::RateMeasure(const Rate &ra_to) const
70
size_t Rate::RateMeasure(const Rate &ra_to) const
36
{
71
{
72
  int tmp;
37
  time_t timeused = time((time_t*) 0) - m_last_timestamp;
73
  time_t timeused = time((time_t*) 0) - m_last_timestamp;
38
  if( timeused < 1 ) timeused = 1;
74
  if( timeused < 1 ) timeused = 1;
39
  return (size_t)((ra_to.m_count_bytes - m_count_bytes) / timeused);
75
  tmp = (ra_to.m_count_bytes - ra_to.m_recent_base)
76
      - (m_count_bytes - m_recent_base);
77
  return (size_t)( (tmp>0) ? (tmp/timeused) : 0 );
40
}
78
}
41
79
42
time_t Rate::TimeUsed(const time_t *pnow) const
80
time_t Rate::TimeUsed(const time_t *pnow) const
(-)rate.h.orig (-2 / +17 lines)
Lines 5-18 Link Here
5
#include <time.h>
5
#include <time.h>
6
#include "def.h"
6
#include "def.h"
7
7
8
#define MAX_SAMPLES 20
9
8
class Rate{
10
class Rate{
9
 private:
11
 private:
10
  time_t m_last_timestamp;
12
  time_t m_last_timestamp;
11
  time_t m_total_timeused;
13
  time_t m_total_timeused;
12
  u_int64_t m_count_bytes;
14
  u_int64_t m_count_bytes;
15
  u_int64_t m_recent_base;
16
  
17
  // bandwidth history data
18
  size_t n_samples;
19
  time_t m_timestamp_sample[MAX_SAMPLES];
20
  u_int64_t m_bytes_sample[MAX_SAMPLES];
21
13
 public:
22
 public:
14
  Rate(){ m_last_timestamp = m_total_timeused = (time_t)0; m_count_bytes = 0; }
23
  Rate(){ m_last_timestamp = m_total_timeused = (time_t)0;
15
  void Reset(){ m_last_timestamp = m_total_timeused = (time_t)0; m_count_bytes = 0;}
24
    m_recent_base = m_count_bytes = 0;
25
    n_samples=0; for(int i=0;i<MAX_SAMPLES;i++) m_timestamp_sample[i]=0;
26
  }
27
  void Reset(){ m_last_timestamp = m_total_timeused = (time_t)0;
28
    m_recent_base = m_count_bytes;
29
    n_samples = 0; for(int i=0;i<MAX_SAMPLES;i++) m_timestamp_sample[i]=0;
30
  }
16
  void StartTimer();
31
  void StartTimer();
17
  void StopTimer();
32
  void StopTimer();
18
  void CountAdd(size_t nbytes);
33
  void CountAdd(size_t nbytes);
(-)sigint.cpp.orig (-4 / +14 lines)
Lines 4-20 Link Here
4
#include <signal.h>
4
#include <signal.h>
5
5
6
#include "btcontent.h"
6
#include "btcontent.h"
7
#include "tracker.h"
7
#include "peerlist.h"
8
#include "peerlist.h"
8
#include "btconfig.h"
9
#include "btconfig.h"
10
#include "sigint.h"
9
11
10
void sigint_catch(int sig_no)
12
void sig_catch(int sig_no)
11
{
13
{
12
  if(SIGINT == sig_no){
14
  if(SIGINT == sig_no || SIGTERM == sig_no){
15
    Tracker.SetStoped();
16
    signal(sig_no,sig_catch2);
17
  }
18
}
19
20
static void sig_catch2(int sig_no)
21
{
22
  if(SIGINT == sig_no || SIGTERM == sig_no){
13
    if( cfg_cache_size ) BTCONTENT.FlushCache();
23
    if( cfg_cache_size ) BTCONTENT.FlushCache();
14
    if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file);
24
    if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file);
15
    WORLD.CloseAll();
25
    WORLD.CloseAll();
16
    signal(SIGINT,SIG_DFL);
26
    signal(sig_no,SIG_DFL);
17
    raise(SIGINT);
27
    raise(sig_no);
18
  }
28
  }
19
}
29
}
20
30
(-)sigint.h.orig (-1 / +2 lines)
Lines 2-8 Link Here
2
#define SIGINT_H
2
#define SIGINT_H
3
3
4
#ifndef WINDOWS
4
#ifndef WINDOWS
5
void sigint_catch(int sig_no);
5
void sig_catch(int sig_no);
6
static void sig_catch2(int sig_no);
6
#endif
7
#endif
7
8
8
#endif
9
#endif
(-)tracker.cpp.orig (-22 / +46 lines)
Lines 31-41 Link Here
31
  m_sock = INVALID_SOCKET;
31
  m_sock = INVALID_SOCKET;
32
  m_port = 80;
32
  m_port = 80;
33
  m_status = T_FREE;
33
  m_status = T_FREE;
34
  m_f_started = m_f_stoped = m_f_pause = 0;
34
  m_f_started = m_f_stoped = m_f_pause = m_f_completed = 0;
35
  m_interval = 15;
35
  m_interval = 15;
36
36
37
  m_connect_refuse_click = 0;
37
  m_connect_refuse_click = 0;
38
  m_last_timestamp = (time_t) 0;
38
  m_last_timestamp = (time_t) 0;
39
  m_prevpeers = 0;
39
}
40
}
40
41
41
btTracker::~btTracker()
42
btTracker::~btTracker()
Lines 54-60 Link Here
54
  
55
  
55
  m_reponse_buffer.Reset();
56
  m_reponse_buffer.Reset();
56
  time(&m_last_timestamp);
57
  time(&m_last_timestamp);
57
  m_status = T_FREE;
58
  if (m_f_stoped) m_status = T_FINISHED;
59
  else m_status = T_FREE;
58
}
60
}
59
61
60
int btTracker:: _IPsin(char *h, int p, struct sockaddr_in *psin)
62
int btTracker:: _IPsin(char *h, int p, struct sockaddr_in *psin)
Lines 111-116 Link Here
111
113
112
  if(m_interval != (time_t)i) m_interval = (time_t)i;
114
  if(m_interval != (time_t)i) m_interval = (time_t)i;
113
115
116
  if(decode_query(buf,bufsiz,"complete",(const char**) 0,&i,QUERY_INT)) {
117
    m_peers_count = i;
118
  }
119
  if(decode_query(buf,bufsiz,"incomplete",(const char**) 0,&i,QUERY_INT)) {
120
    m_peers_count += i;
121
  }
122
114
  pos = decode_query(buf,bufsiz,"peers",(const char**) 0,(size_t *) 0,QUERY_POS);
123
  pos = decode_query(buf,bufsiz,"peers",(const char**) 0,(size_t *) 0,QUERY_POS);
115
124
116
  if( !pos ){
125
  if( !pos ){
Lines 161-167 Link Here
161
    }
170
    }
162
  }
171
  }
163
  
172
  
164
  if( !cnt ) fprintf(stderr,"warn, peers list received from tracker is empty.\n");
173
  if(arg_verbose)
174
    fprintf(stderr, "\nnew peers=%u; next check in %u sec\n", cnt, m_interval);
175
// moved to CheckResponse--this function isn't called if no peer data.
176
//  if( !cnt ) fprintf(stderr,"warn, peers list received from tracker is empty.\n");
165
  return 0;
177
  return 0;
166
}
178
}
167
179
Lines 230-239 Link Here
230
      return 0;
242
      return 0;
231
  }
243
  }
232
244
233
  if ( !pdata ) return 0;
245
  if ( !pdata ){
246
    fprintf(stderr,"warn, peers list received from tracker is empty.\n");
247
    return 0;
248
  }
234
249
235
  if( !m_f_started ) m_f_started = 1;
250
  if( !m_f_started ) m_f_started = 1;
236
  m_connect_refuse_click = 0;
251
  m_connect_refuse_click = 0;
252
  m_ok_click++;
237
253
238
  return _UpdatePeerList(pdata,dlen);
254
  return _UpdatePeerList(pdata,dlen);
239
}
255
}
Lines 329-358 Link Here
329
//  fprintf(stdout,"Old Set Self:");
345
//  fprintf(stdout,"Old Set Self:");
330
//  fprintf(stdout,"%s\n", inet_ntoa(Self.m_sin.sin_addr));
346
//  fprintf(stdout,"%s\n", inet_ntoa(Self.m_sin.sin_addr));
331
347
332
  if( m_f_stoped )	/* stopped */
348
  if( m_f_stoped )
333
    event = str_event[1];
349
    event = str_event[1];	/* stopped */
334
  else if( BTCONTENT.pBF->IsFull())	/* download complete */
350
  else if( m_f_started == 0 ) {
335
    event = str_event[2];
351
    if( BTCONTENT.pBF->IsFull() ) m_f_completed = 1;
336
  else if( m_f_started ) 	/* interval */
337
    event = (char*) 0;
338
  else
339
    event = str_event[0];	/* started */
352
    event = str_event[0];	/* started */
353
  } else if( BTCONTENT.pBF->IsFull() && !m_f_completed){
354
    event = str_event[2];	/* download complete */
355
    m_f_completed = 1;		/* only send download complete once */
356
  } else
357
    event = (char*) 0;  /* interval */
340
358
341
  if(event){
359
  if(event){
342
    if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT,
360
    if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT,
343
			     m_path,
361
			     m_path,
344
			     (size_t)Self.TotalUL(),
362
			     Self.TotalUL(),
345
			     (size_t)Self.TotalDL(),
363
			     Self.TotalDL(),
346
			     (size_t)BTCONTENT.GetLeftBytes(),
364
			     BTCONTENT.GetLeftBytes(),
347
			     event)){
365
			     event,
366
			     cfg_max_peers)){
348
      return -1;
367
      return -1;
349
    }
368
    }
350
  }else{
369
  }else{
351
    if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P3_FMT,
370
    if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P3_FMT,
352
			     m_path,
371
			     m_path,
353
			     (size_t)Self.TotalUL(),
372
			     Self.TotalUL(),
354
			     (size_t)Self.TotalDL(),
373
			     Self.TotalDL(),
355
			     (size_t)BTCONTENT.GetLeftBytes()
374
			     BTCONTENT.GetLeftBytes(),
375
			     cfg_max_peers
356
			     )){
376
			     )){
357
      return -1;
377
      return -1;
358
    }
378
    }
Lines 380-387 Link Here
380
{
400
{
381
  /* tracker communication */
401
  /* tracker communication */
382
  if( T_FREE == m_status ){
402
  if( T_FREE == m_status ){
383
    if((*pnow - m_last_timestamp >= m_interval) &&
403
//  if(*pnow - m_last_timestamp >= m_interval){
384
       (cfg_min_peers > WORLD.TotalPeers())){
404
    if(*pnow - m_last_timestamp >= m_interval ||
405
        // Connect to tracker early if we run out of peers.
406
        (!WORLD.TotalPeers() && m_prevpeers &&
407
          *pnow - m_last_timestamp >= 15) ){
408
      m_prevpeers = WORLD.TotalPeers();
385
   
409
   
386
      if(Connect() < 0){ Reset(15); return -1; }
410
      if(Connect() < 0){ Reset(15); return -1; }
387
    
411
    
Lines 396-402 Link Here
396
    if( m_status == T_CONNECTING ){
420
    if( m_status == T_CONNECTING ){
397
      FD_SET(m_sock, rfdp);
421
      FD_SET(m_sock, rfdp);
398
      FD_SET(m_sock, wfdp);
422
      FD_SET(m_sock, wfdp);
399
    }else{
423
    }else if (INVALID_SOCKET != m_sock){
400
      FD_SET(m_sock, rfdp);
424
      FD_SET(m_sock, rfdp);
401
    }
425
    }
402
  }
426
  }
Lines 425-431 Link Here
425
      if( SendRequest() == 0 ) m_status = T_READY; 
449
      if( SendRequest() == 0 ) m_status = T_READY; 
426
      else { Reset(15); return -1; }
450
      else { Reset(15); return -1; }
427
    }
451
    }
428
  }else if(FD_ISSET(m_sock, rfdp) ){
452
  }else if(INVALID_SOCKET != m_sock && FD_ISSET(m_sock, rfdp) ){
429
    (*nfds)--;
453
    (*nfds)--;
430
    FD_CLR(m_sock,rfdp);
454
    FD_CLR(m_sock,rfdp);
431
    CheckReponse();
455
    CheckReponse();
(-)tracker.h.orig (-1 / +11 lines)
Lines 21-26 Link Here
21
#define T_FREE 		0
21
#define T_FREE 		0
22
#define T_CONNECTING	1
22
#define T_CONNECTING	1
23
#define T_READY		2
23
#define T_READY		2
24
#define T_FINISHED	3
24
25
25
class btTracker
26
class btTracker
26
{
27
{
Lines 34-48 Link Here
34
  unsigned char m_status:2;
35
  unsigned char m_status:2;
35
  unsigned char m_f_started:1;
36
  unsigned char m_f_started:1;
36
  unsigned char m_f_stoped:1;
37
  unsigned char m_f_stoped:1;
38
  unsigned char m_f_completed:1;
37
39
38
  unsigned char m_f_pause:1;
40
  unsigned char m_f_pause:1;
39
  unsigned char m_f_reserved:3;
41
  unsigned char m_f_reserved:2;
40
42
41
43
42
  time_t m_interval;		// ÓëTrackerͨÐŵÄʱ¼ä¼ä¸ô
44
  time_t m_interval;		// ÓëTrackerͨÐŵÄʱ¼ä¼ä¸ô
43
  time_t m_last_timestamp;	// ×îºóÒ»´Î³É¹¦ÓëTrackerͨÐŵÄʱ¼ä
45
  time_t m_last_timestamp;	// ×îºóÒ»´Î³É¹¦ÓëTrackerͨÐŵÄʱ¼ä
44
  size_t m_connect_refuse_click;
46
  size_t m_connect_refuse_click;
45
47
48
  size_t m_ok_click;	// tracker ok response counter
49
  size_t m_peers_count;	// total number of peers
50
  size_t m_prevpeers;	// number of peers previously seen
51
46
  SOCKET m_sock;
52
  SOCKET m_sock;
47
  BufIo m_reponse_buffer;
53
  BufIo m_reponse_buffer;
48
  
54
  
Lines 66-71 Link Here
66
  void SetPause() { m_f_pause = 1; }
72
  void SetPause() { m_f_pause = 1; }
67
  void ClearPause() { m_f_pause = 0; }
73
  void ClearPause() { m_f_pause = 0; }
68
74
75
  void SetStoped() { Reset(15); m_f_stoped = 1; m_last_timestamp -= 15;}
76
69
  int Connect();
77
  int Connect();
70
  int SendRequest();
78
  int SendRequest();
71
  int CheckReponse();
79
  int CheckReponse();
Lines 73-78 Link Here
73
  int SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds);
81
  int SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds);
74
82
75
  size_t GetRefuseClick() const { return m_connect_refuse_click; }
83
  size_t GetRefuseClick() const { return m_connect_refuse_click; }
84
  size_t GetOkClick() const { return m_ok_click; }
85
  size_t GetPeersCount() const { return m_peers_count; }
76
};
86
};
77
87
78
extern btTracker Tracker;
88
extern btTracker Tracker;

Return to bug 112352