]> pilppa.org Git - familiar-h63xx-build.git/blob - org.handhelds.familiar/packages/ctorrent/files/extended_ctorrent.diff
OE tree imported from monotone branch org.openembedded.oz354fam083 at revision 8b12e3...
[familiar-h63xx-build.git] / org.handhelds.familiar / packages / ctorrent / files / extended_ctorrent.diff
1 Only in ctorrent-1.3.4: README-DNH.TXT
2 diff -u ctorrent-1.3.4.orig/btconfig.cpp ctorrent-1.3.4/btconfig.cpp
3 --- ctorrent-1.3.4.orig/btconfig.cpp    2004-09-09 01:10:51.000000000 +0200
4 +++ ctorrent-1.3.4/btconfig.cpp 2005-08-11 23:45:29.424694440 +0200
5 @@ -1,6 +1,7 @@
6  #include <sys/types.h>
7  
8 -size_t cfg_req_slice_size = 32768;
9 +//size_t cfg_req_slice_size = 32768;
10 +size_t cfg_req_slice_size = 16384;
11  
12  size_t cfg_cache_size = 16;
13  
14 @@ -11,7 +12,8 @@
15  int cfg_max_listen_port = 2706;
16  int cfg_min_listen_port = 2106;
17  
18 -int cfg_max_bandwidth = -1;
19 +int cfg_max_bandwidth_down = -1;
20 +int cfg_max_bandwidth_up = -1;
21  
22  time_t cfg_seed_hours = 72;
23  
24 @@ -25,6 +27,8 @@
25  unsigned char arg_flg_check_only = 0;
26  unsigned char arg_flg_exam_only = 0;
27  unsigned char arg_flg_make_torrent = 0;
28 +unsigned char arg_file_to_download = 0;
29 +unsigned char arg_verbose = 0;
30  
31  size_t arg_piece_length = 262144;
32  char *arg_announce = (char*) 0;
33 diff -u ctorrent-1.3.4.orig/btconfig.h ctorrent-1.3.4/btconfig.h
34 --- ctorrent-1.3.4.orig/btconfig.h      2004-09-09 01:10:51.000000000 +0200
35 +++ ctorrent-1.3.4/btconfig.h   2005-08-11 23:45:29.425694288 +0200
36 @@ -22,6 +22,8 @@
37  extern time_t cfg_seed_hours;
38  
39  extern int cfg_max_bandwidth;
40 +extern int cfg_max_bandwidth_down;
41 +extern int cfg_max_bandwidth_up;
42  
43  // arguments global value
44  extern char *arg_metainfo_file;
45 @@ -33,6 +35,8 @@
46  extern unsigned char arg_flg_check_only;
47  extern unsigned char arg_flg_exam_only;
48  extern unsigned char arg_flg_make_torrent;
49 +extern unsigned char arg_file_to_download;
50 +extern unsigned char arg_verbose;
51  
52  extern size_t arg_piece_length;
53  extern char *arg_announce;
54 diff -u ctorrent-1.3.4.orig/btcontent.cpp ctorrent-1.3.4/btcontent.cpp
55 --- ctorrent-1.3.4.orig/btcontent.cpp   2004-09-09 01:10:51.000000000 +0200
56 +++ ctorrent-1.3.4/btcontent.cpp        2005-08-11 23:45:29.425694288 +0200
57 @@ -23,6 +23,7 @@
58  #include "bencode.h"
59  #include "peer.h"
60  #include "httpencode.h"
61 +#include "tracker.h"
62  
63  #define meta_str(keylist,pstr,pint) decode_query(b,flen,(keylist),(pstr),(pint),QUERY_STR)
64  #define meta_int(keylist,pint) decode_query(b,flen,(keylist),(const char**) 0,(pint),QUERY_INT)
65 @@ -53,6 +54,7 @@
66    m_announce = global_piece_buffer = (char*) 0;
67    m_hash_table = (unsigned char *) 0;
68    pBF = (BitField*) 0;
69 +  pBFilter = (BitField*) 0;
70    m_create_date = m_seed_timestamp = (time_t) 0;
71    time(&m_start_timestamp);
72    m_cache = (BTCACHE*) 0;
73 @@ -226,6 +228,7 @@
74    if( m_btfiles.BuildFromMI(b, flen, saveas) < 0) ERR_RETURN();
75  
76    delete []b;
77 +  b = (char *)0;
78    PrintOut();
79    
80    if( arg_flg_exam_only ) return 0;
81 @@ -242,6 +245,17 @@
82    if( !pBF ) ERR_RETURN();
83  #endif
84  
85 +    //create the file filter
86 +    pBFilter = new BitField(m_npieces);
87 +#ifndef WINDOWS
88 +     if( !pBFilter ) ERR_RETURN();
89 +#endif
90 +  if(arg_file_to_download>0){
91 +    m_btfiles.SetFilter(arg_file_to_download,pBFilter,m_piece_length);
92 +  }
93 +
94 +
95 +
96    m_left_bytes = m_btfiles.GetTotalLength() / m_piece_length;
97    if( m_btfiles.GetTotalLength() % m_piece_length ) m_left_bytes++;
98    if( m_left_bytes != m_npieces ) ERR_RETURN();
99 @@ -309,7 +323,8 @@
100  
101  ssize_t btContent::ReadSlice(char *buf,size_t idx,size_t off,size_t len)
102  {
103 -  u_int64_t offset = idx * m_piece_length + off;
104 +  //changed
105 +  u_int64_t offset = (u_int64_t)idx * (u_int64_t)m_piece_length + (u_int64_t)off;
106  
107    if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 0);
108    else{
109 @@ -405,7 +420,11 @@
110  
111  ssize_t btContent::WriteSlice(char *buf,size_t idx,size_t off,size_t len)
112  {
113 -  u_int64_t offset = (u_int64_t)(idx * m_piece_length + off);
114 +  //u_int64_t offset = (u_int64_t)(idx * m_piece_length + off);
115 +  //changed
116 +  u_int64_t offset = (u_int64_t)idx * (u_int64_t)m_piece_length + (u_int64_t)off;
117 +
118 +  //  printf("\nOffset-write: %lu - Piece:%lu\n",offset,(unsigned long)idx);
119  
120    if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 1);
121    else{
122 @@ -514,9 +533,9 @@
123    if( !percent ) percent = 1;
124  
125    for( ; idx < m_npieces; idx++){
126 -    if( GetHashValue(idx, md) == 0 && memcmp(md, m_hash_table + idx * 20, 20) == 0){
127 -      m_left_bytes -= GetPieceLength(idx);
128 -      pBF->Set(idx);
129 +      if( GetHashValue(idx, md) == 0 && memcmp(md, m_hash_table + idx * 20, 20) == 0){
130 +       m_left_bytes -= GetPieceLength(idx);
131 +       pBF->Set(idx);
132      }
133      if(idx % percent == 0){
134        printf("\rCheck exist: %d/%d",idx,pBF->NBits());
135 @@ -575,7 +594,6 @@
136      fprintf(stderr,"warn,piece %d hash check failed.\n",idx);
137      return 0;
138    }
139 -
140    pBF->Set(idx);
141    m_left_bytes -= GetPieceLength(idx);
142    return 1;
143 @@ -592,6 +610,7 @@
144  {
145    if( pBF->IsFull() ){
146      if( !m_seed_timestamp ){
147 +      Tracker.Reset(15);
148        Self.ResetDLTimer();
149        Self.ResetULTimer();
150        ReleaseHashTable();
151 @@ -605,3 +624,13 @@
152    }
153    return 0;
154  }
155 +
156 +
157 +size_t btContent::getFilePieces(unsigned char nfile){
158 +   return m_btfiles.getFilePieces(nfile);
159 +}
160 +
161 +
162 +void btContent::SetFilter(){
163 +  m_btfiles.SetFilter(arg_file_to_download,pBFilter,m_piece_length);
164 +}
165 diff -u ctorrent-1.3.4.orig/btcontent.h ctorrent-1.3.4/btcontent.h
166 --- ctorrent-1.3.4.orig/btcontent.h     2004-09-09 01:10:51.000000000 +0200
167 +++ ctorrent-1.3.4/btcontent.h  2005-08-11 23:45:29.426694136 +0200
168 @@ -60,6 +60,7 @@
169    
170   public:
171    BitField *pBF;
172 +  BitField *pBFilter;
173    char *global_piece_buffer;
174    
175    btContent();
176 @@ -93,6 +94,11 @@
177  
178    int PrintOut();
179    int SeedTimeout(const time_t *pnow);
180 +
181 +
182 + void SetFilter();
183 + size_t getFilePieces(unsigned char nfile);
184 +
185  };
186  
187  extern btContent BTCONTENT;
188 diff -u ctorrent-1.3.4.orig/btfiles.cpp ctorrent-1.3.4/btfiles.cpp
189 --- ctorrent-1.3.4.orig/btfiles.cpp     2004-09-09 01:10:51.000000000 +0200
190 +++ ctorrent-1.3.4/btfiles.cpp  2005-08-11 23:45:29.426694136 +0200
191 @@ -105,6 +105,7 @@
192    pos = (size_t) (off - (n - pbf->bf_length));
193  
194    for(; len ;){
195 +
196      if( !pbf->bf_flag_opened ){
197        if( _btf_open(pbf) < 0 ) return -1;
198      }
199 @@ -119,6 +120,7 @@
200        if( 1 != fread(buf,nio,1,pbf->bf_fp) ) return -1;
201      }else{
202        if( 1 != fwrite(buf,nio,1,pbf->bf_fp) ) return -1;
203 +      fflush(pbf->bf_fp);
204      }
205  
206      len -= nio;
207 @@ -169,7 +171,7 @@
208    DIR *dp;
209    BTFILE *pbf;
210  
211 -  if( !getwd(full_cur) ) return -1;
212 +  if( !getcwd(full_cur,MAXPATHLEN) ) return -1;
213  
214    if( cur_path ){
215      strcpy(fn, full_cur);
216 @@ -293,7 +295,7 @@
217      m_btfhead = pbf;
218    }else if( S_IFDIR & sb.st_mode ){
219      char wd[MAXPATHLEN];
220 -    if( !getwd(wd) ) return -1;
221 +    if( !getcwd(wd,MAXPATHLEN) ) return -1;
222      m_directory = new char[strlen(pathname) + 1];
223  #ifndef WINDOWS
224      if( !m_directory ) return -1;
225 @@ -488,3 +490,54 @@
226    }
227    return 1;
228  }
229 +
230 +
231 +void btFiles::SetFilter(int nfile, BitField *pFilter,  size_t pieceLength)
232 +{
233 +  //set the filter
234 +
235 +  BTFILE *p = m_btfhead;
236 +  size_t id = 1;
237 +  u_int64_t sizeBuffer=0;
238 +  size_t index;
239 +
240 +
241 +   pFilter->SetAll();
242 +     for( ; p ; p = p->bf_next ){
243 +      if(id++ == nfile){
244 +        size_t start,stop;
245 +        start = sizeBuffer/pieceLength;
246 +        stop  = (sizeBuffer+p->bf_length)/pieceLength;
247 +        printf ("\rDownloading file: <%d> %s        \nPieces: %d - %d (%d)\n",nfile,p->bf_filename,start,stop,stop-start+1);
248 +        p->bf_npieces = stop-start+1;
249 +        for(index=sizeBuffer/pieceLength;index<=(sizeBuffer+p->bf_length)/pieceLength;index++){
250 +         pFilter->UnSet(index);
251 +        }
252 +     }
253 +     sizeBuffer+=(u_int64_t) p->bf_length;
254 +   }
255 +    if(nfile>=id){
256 +      printf("\nEnd of files list. Resuming normal behaviour\n");
257 +      pFilter->Invert();
258 +      arg_file_to_download = 0;
259 +    }
260 +}
261 +
262 +size_t btFiles::getFilePieces(unsigned char nfile)
263 +{
264 +  //returns the pieces of the file already gotten
265 +
266 +  BTFILE *p = m_btfhead;
267 +  size_t id = 1;
268 +
269 +     for( ; p ; p = p->bf_next ){
270 +      if(id++ == nfile){
271 +        return p->bf_npieces;
272 +        }
273 +     }
274 +return 0;
275 +}
276 +
277 +
278 +
279 +
280 diff -u ctorrent-1.3.4.orig/btfiles.h ctorrent-1.3.4/btfiles.h
281 --- ctorrent-1.3.4.orig/btfiles.h       2004-09-09 01:10:51.000000000 +0200
282 +++ ctorrent-1.3.4/btfiles.h    2005-08-11 23:45:29.427693984 +0200
283 @@ -3,6 +3,10 @@
284  
285  #include <sys/types.h>
286  #include <stdio.h>
287 +
288 +#include "bitfield.h"
289 +extern unsigned char arg_file_to_download;
290 +
291  #include "./def.h"
292  
293  typedef struct _btfile{
294 @@ -14,6 +18,8 @@
295  
296    size_t bf_completed;         // already downloaded length
297  
298 +  size_t bf_npieces;  //number of pieces
299 +
300    unsigned char bf_flag_opened:1;
301    unsigned char bf_flag_need:1;
302    unsigned char bf_reserved:6;
303 @@ -53,6 +59,10 @@
304    u_int64_t GetTotalLength() const { return m_total_files_length; }
305    ssize_t IO(char *buf, u_int64_t off, size_t len, const int iotype);
306    size_t FillMetaInfo(FILE* fp);
307 +
308 +  void SetFilter(int nfile, BitField *pFilter,size_t pieceLength);
309 +  size_t getFilePieces(unsigned char nfile);
310 +
311  #ifndef WINDOWS
312    void PrintOut();
313  #endif
314 diff -u ctorrent-1.3.4.orig/btrequest.cpp ctorrent-1.3.4/btrequest.cpp
315 --- ctorrent-1.3.4.orig/btrequest.cpp   2004-09-09 01:10:51.000000000 +0200
316 +++ ctorrent-1.3.4/btrequest.cpp        2005-08-11 23:45:29.427693984 +0200
317 @@ -44,6 +44,58 @@
318    rq.rq_head = (PSLICE) 0;
319  }
320  
321 +int RequestQueue::CopyShuffle(RequestQueue &rq)
322 +{
323 +  PSLICE ps;
324 +
325 +  if( rq_head ) _empty_slice_list(&rq_head);
326 +  
327 +  if( rq.IsEmpty() ) return 0;
328 +  for (ps = rq.GetHead(); ps; ps = ps->next) {
329 +    if (random()&01) {
330 +      if (Add(ps->index, ps->offset, ps->length) < 0) return -1;
331 +    }
332 +    else if (Insert(ps->index, ps->offset, ps->length) < 0) return -1;
333 +  }
334 +  return 0;
335 +}
336 +
337 +size_t RequestQueue::Qsize()
338 +{
339 +  size_t cnt = 0;
340 +  PSLICE n = rq_head;
341 +  PSLICE u = (PSLICE) 0;
342 +
343 +  for( ; n ; u = n,n = u->next) cnt++; // move to end
344 +  return cnt;
345 +}
346 +
347 +int RequestQueue::Insert(size_t idx,size_t off,size_t len)
348 +{
349 +  size_t cnt = 0;
350 +  PSLICE n = rq_head;
351 +  PSLICE u = (PSLICE) 0;
352 +
353 +  for( ; n ; u = n,n = u->next) cnt++; // move to end (count)
354 +
355 +  if( cnt >= cfg_req_queue_length ) return -1; // already full
356 +
357 +  n = new SLICE;
358 +
359 +#ifndef WINDOWS
360 +  if( !n ) return -1;
361 +#endif
362 +
363 +  n->next = rq_head;
364 +  n->index = idx;
365 +  n->offset = off;
366 +  n->length = len;
367 +
368 +  rq_head = n;
369 +
370 +  return 0;
371 +}
372 +
373  int RequestQueue::Add(size_t idx,size_t off,size_t len)
374  {
375    size_t cnt = 0;
376 @@ -231,3 +283,33 @@
377    }
378    return 0;
379  }
380 +
381 +int PendingQueue::Delete(size_t idx)
382 +{
383 +   int i = 0;
384 +  for ( ; i < PENDING_QUEUE_SIZE && pq_count; i++){
385 +    if( (PSLICE) 0 != pending_array[i] && idx == pending_array[i]->index){
386 +      delete pending_array[i];
387 +      pending_array[i] = (PSLICE) 0;
388 +    }
389 +  }
390 +  return 0;
391 +}
392 +
393 +int PendingQueue::DeleteSlice(size_t idx, size_t off, size_t len)
394 +{
395 +   int i = 0;
396 +   RequestQueue rq;
397 +  for ( ; i < PENDING_QUEUE_SIZE && pq_count; i++){
398 +    if( (PSLICE) 0 != pending_array[i] && idx == pending_array[i]->index){
399 +      //check if off & len match any slice
400 +      //remove the slice if so
401 +      rq.SetHead(pending_array[i]);
402 +      if( rq.Remove(idx, off, len) == 0 )
403 +        pending_array[i] = rq.GetHead();
404 +      rq.Release();
405 +    }
406 +  }
407 +  return 0;
408 +}
409 +
410 diff -u ctorrent-1.3.4.orig/btrequest.h ctorrent-1.3.4/btrequest.h
411 --- ctorrent-1.3.4.orig/btrequest.h     2004-09-09 01:10:51.000000000 +0200
412 +++ ctorrent-1.3.4/btrequest.h  2005-08-11 23:45:29.427693984 +0200
413 @@ -31,9 +31,12 @@
414    int IsValidRequest(size_t idx,size_t off,size_t len);
415  
416    void operator=(RequestQueue &rq);
417 +  int CopyShuffle(RequestQueue &rq);
418 +  size_t Qsize();
419  
420    int IsEmpty() const { return rq_head ? 0 : 1; }
421  
422 +  int Insert(size_t idx,size_t off,size_t len);
423    int Add(size_t idx,size_t off,size_t len);
424    int Remove(size_t idx,size_t off,size_t len);
425  
426 @@ -60,6 +63,8 @@
427    int Pending(RequestQueue *prq);
428    int ReAssign(RequestQueue *prq, BitField &bf);
429    int Exist(size_t idx);
430 +  int Delete(size_t idx);
431 +  int DeleteSlice(size_t idx, size_t off, size_t len);
432  };
433  
434  extern PendingQueue PENDINGQUEUE;
435 diff -u ctorrent-1.3.4.orig/btstream.cpp ctorrent-1.3.4/btstream.cpp
436 --- ctorrent-1.3.4.orig/btstream.cpp    2004-09-09 01:10:51.000000000 +0200
437 +++ ctorrent-1.3.4/btstream.cpp 2005-08-11 23:45:29.428693832 +0200
438 @@ -1,5 +1,6 @@
439  #include <arpa/inet.h>
440  #include "btstream.h"
441 +#include "peer.h"
442  #include "msgencode.h"
443  #include "btconfig.h"
444  
445 @@ -11,7 +12,8 @@
446  ssize_t btStream::Send_State(unsigned char state)
447  {
448    char msg[H_BASE_LEN + 4];
449 -  *(size_t*)msg = htonl(H_BASE_LEN);
450 +
451 +  set_nl(msg, H_BASE_LEN);
452    msg[4] = (char)state;
453    return out_buffer.PutFlush(sock,msg,H_BASE_LEN + 4);
454  }
455 @@ -19,12 +21,10 @@
456  ssize_t btStream::Send_Have(size_t idx)
457  {
458    char msg[H_HAVE_LEN + 4];
459 -  size_t *p = (size_t*)msg;
460  
461 -  *p = htonl(H_HAVE_LEN);
462 +  set_nl(msg, H_HAVE_LEN);
463    msg[4] = (char)M_HAVE;
464 -  p = (size_t*)(msg + 5);
465 -  *p = htonl(idx);
466 +  set_nl(msg + 5, idx);
467  
468    return out_buffer.PutFlush(sock,msg,H_HAVE_LEN + 4);
469  }
470 @@ -43,14 +43,12 @@
471  ssize_t btStream::Send_Cancel(size_t idx,size_t off,size_t len)
472  {
473    char msg[H_CANCEL_LEN + 4];
474 -  size_t *p = (size_t*)msg;
475  
476 -  *p = htonl(H_CANCEL_LEN);
477 +  set_nl(msg, H_CANCEL_LEN);
478    msg[4] = M_CANCEL;
479 -  p = (size_t*)(msg + 5);
480 -  *p = htonl(idx); p++;
481 -  *p = htonl(off); p++;
482 -  *p = htonl(len);
483 +  set_nl(msg + 5, idx);
484 +  set_nl(msg + 9, off);
485 +  set_nl(msg + 13, len);
486    return out_buffer.Put(sock,msg,H_CANCEL_LEN + 4);
487  }
488  
489 @@ -72,14 +70,12 @@
490  ssize_t btStream::Send_Request(size_t idx, size_t off,size_t len)
491  {
492    char msg[H_REQUEST_LEN + 4];
493 -  size_t *p = (size_t*) msg;
494  
495 -  *p = htonl(H_REQUEST_LEN);
496 +  set_nl(msg, H_REQUEST_LEN);
497    msg[4] = (char)M_REQUEST;
498 -  p = (size_t*)(msg + 5);
499 -  *p = htonl(idx); p++;
500 -  *p = htonl(off); p++;
501 -  *p = htonl(len);
502 +  set_nl(msg + 5, idx);
503 +  set_nl(msg + 9, off);
504 +  set_nl(msg + 13, len);
505    return out_buffer.Put(sock,msg,H_REQUEST_LEN + 4);
506  }
507  
508 @@ -94,7 +90,7 @@
509    // if message arrived.
510    size_t r;
511    if( 4 <= in_buffer.Count() ){
512 -    r = ntohl(*(size_t*)in_buffer.BasePointer());
513 +    r = get_nl(in_buffer.BasePointer());
514      if( (cfg_max_slice_size + H_PIECE_LEN + 4) < r) return -1; //message too long
515      if( (r + 4) <= in_buffer.Count() ) return 1;
516    }
517 diff -u ctorrent-1.3.4.orig/ctorrent.cpp ctorrent-1.3.4/ctorrent.cpp
518 --- ctorrent-1.3.4.orig/ctorrent.cpp    2004-09-09 01:10:51.000000000 +0200
519 +++ ctorrent-1.3.4/ctorrent.cpp 2005-08-11 23:45:29.428693832 +0200
520 @@ -87,9 +87,13 @@
521         Tracker.Initial();
522  
523         signal(SIGPIPE,SIG_IGN);
524 -    signal(SIGINT,sigint_catch);
525 +    signal(SIGINT,sig_catch);
526 +    signal(SIGTERM,sig_catch);
527      Downloader();
528    }
529 +  if( cfg_cache_size ) BTCONTENT.FlushCache();
530 +  if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file);
531 +  WORLD.CloseAll();
532  
533    exit(0);
534  }
535 @@ -99,7 +103,7 @@
536  int param_check(int argc, char **argv)
537  {
538    int c, l;
539 -  while ( ( c = getopt(argc,argv,"b:B:cC:e:fl:M:m:P:p:s:tu:xhH")) != -1)
540 +  while ( ( c = getopt(argc,argv,"b:cC:D:e:fl:M:m:n:P:p:s:tu:U:vxhH")) != -1)
541      switch( c ){
542      case 'b':
543        arg_bitfield_file = new char[strlen(optarg) + 1];
544 @@ -150,14 +154,23 @@
545        }
546        break;
547  
548 +    case 'n':                  // Which file download
549 +      arg_file_to_download = atoi(optarg);
550 +    break;
551 +
552 +
553      case 'f':                  // force seed mode, skip sha1 check when startup.
554        arg_flg_force_seed_mode = 1;
555        break;
556        
557 -    case 'B':
558 -      cfg_max_bandwidth = atoi(optarg);
559 +    case 'D':
560 +      cfg_max_bandwidth_down = (int)(strtod(optarg, NULL) * 1024);
561        break;
562  
563 +       case 'U':
564 +      cfg_max_bandwidth_up = (int)(strtod(optarg, NULL) * 1024);
565 +         break;
566 +
567      case 'P':
568                 l = strlen(optarg);
569                 if (l > MAX_PF_LEN) {printf("-P arg must be 8 or less characters\n"); exit(1);}
570 @@ -190,6 +203,10 @@
571        arg_flg_exam_only = 1;
572        break;
573  
574 +    case 'v':
575 +      arg_verbose = 1;
576 +      break;
577 +
578      case 'h':
579      case 'H':
580      default:
581 @@ -217,6 +234,7 @@
582    fprintf(stderr,"-h/-H\t\tShow this message.\n");
583    fprintf(stderr,"-x\t\tDecode metainfo(torrent) file only, don't download.\n");
584    fprintf(stderr,"-c\t\tCheck exist only. don't download.\n");
585 +  fprintf(stderr,"-v\t\tVerbose output (for debugging).\n");
586    fprintf(stderr,"\nDownload Options:\n");
587    fprintf(stderr,"-e int\t\tExit while seed <int> hours later. (default 72 hours)\n");
588    fprintf(stderr,"-p port\t\tListen port. (default 2706 -> 2106)\n");
589 @@ -226,7 +244,9 @@
590    fprintf(stderr,"-b bf_filename\tBit field filename. (use it carefully)\n");
591    fprintf(stderr,"-M max_peers\tMax peers count.\n");
592    fprintf(stderr,"-m min_peers\tMin peers count.\n");
593 -  fprintf(stderr,"-B rate\t\tMax bandwidth (unit KB/s)\n");
594 +  fprintf(stderr,"-n file_number\tWhich file download.\n");
595 +  fprintf(stderr,"-D rate\t\tMax bandwidth down (unit KB/s)\n");
596 +  fprintf(stderr,"-U rate\t\tMax bandwidth up (unit KB/s)\n");
597    fprintf(stderr,"-P peer_id\tSet Peer ID ["PEER_PFX"]\n");
598    fprintf(stderr,"\nMake metainfo(torrent) file Options:\n");
599    fprintf(stderr,"-t\t\tWith make torrent. must specify this option.\n");
600 diff -u ctorrent-1.3.4.orig/downloader.cpp ctorrent-1.3.4/downloader.cpp
601 --- ctorrent-1.3.4.orig/downloader.cpp  2004-09-09 01:10:51.000000000 +0200
602 +++ ctorrent-1.3.4/downloader.cpp       2005-08-11 23:45:29.429693680 +0200
603 @@ -29,10 +29,14 @@
604    time_t now;
605    fd_set rfd;
606    fd_set wfd;
607 +  int stopped = 0;
608  
609 -  for(;;){
610 +  do{
611      time(&now);
612 -    if( BTCONTENT.SeedTimeout(&now) ) break;
613 +    if( !stopped && BTCONTENT.SeedTimeout(&now) ) {
614 +       Tracker.SetStoped();
615 +       stopped = 1;
616 +    }
617      
618      FD_ZERO(&rfd); FD_ZERO(&wfd);
619      maxfd = Tracker.IntervalCheck(&now,&rfd, &wfd);
620 @@ -48,5 +52,5 @@
621        if(T_FREE != Tracker.GetStatus()) Tracker.SocketReady(&rfd,&wfd,&nfds);
622           if( nfds ) WORLD.AnyPeerReady(&rfd,&wfd,&nfds);
623         }
624 -  }/* end for(;;) */
625 +  } while(Tracker.GetStatus() != T_FINISHED);
626  }
627 diff -u ctorrent-1.3.4.orig/httpencode.cpp ctorrent-1.3.4/httpencode.cpp
628 --- ctorrent-1.3.4.orig/httpencode.cpp  2004-09-09 01:10:51.000000000 +0200
629 +++ ctorrent-1.3.4/httpencode.cpp       2005-08-11 23:45:29.429693680 +0200
630 @@ -88,7 +88,7 @@
631  
632    /* path */
633    if( *p != '/' ) return -1;
634 -  for( ; *p && *p != '?'; p++,path++) *path = *p;
635 +  for( ; *p; p++,path++) *path = *p;
636    *path = '\0';
637    return 0;
638  }
639 diff -u ctorrent-1.3.4.orig/httpencode.h ctorrent-1.3.4/httpencode.h
640 --- ctorrent-1.3.4.orig/httpencode.h    2004-09-09 01:10:51.000000000 +0200
641 +++ ctorrent-1.3.4/httpencode.h 2005-08-11 23:45:29.429693680 +0200
642 @@ -2,8 +2,11 @@
643  #define HTTPENCODE_H
644  
645  #define REQ_URL_P1_FMT "GET %s?info_hash=%s&peer_id=%s&port=%d"
646 -#define REQ_URL_P2_FMT "%s&uploaded=%d&downloaded=%d&left=%d&event=%s&compact=1 HTTP/1.0"
647 -#define REQ_URL_P3_FMT "%s&uploaded=%d&downloaded=%d&left=%d&compact=1 HTTP/1.0"
648 +//#define REQ_URL_P2_FMT "%s&uploaded=%d&downloaded=%d&left=%d&event=%s&compact=1 HTTP/1.0"
649 +//#define REQ_URL_P3_FMT "%s&uploaded=%d&downloaded=%d&left=%d&compact=1 HTTP/1.0"
650 +#define REQ_URL_P2_FMT "%s&uploaded=%llu&downloaded=%llu&left=%llu&compact=1&event=%s&numwant=%u HTTP/1.0"
651 +#define REQ_URL_P3_FMT "%s&uploaded=%llu&downloaded=%llu&left=%llu&compact=1&numwant=%u HTTP/1.0"
652 +
653  
654  char* Http_url_encode(char *s,char *b,size_t n);
655  int Http_url_analyse(char *url,char *host,int *port,char *path);
656 diff -u ctorrent-1.3.4.orig/iplist.cpp ctorrent-1.3.4/iplist.cpp
657 --- ctorrent-1.3.4.orig/iplist.cpp      2004-09-09 01:10:51.000000000 +0200
658 +++ ctorrent-1.3.4/iplist.cpp   2005-08-11 23:45:29.429693680 +0200
659 @@ -8,8 +8,8 @@
660    IPLIST *node = ipl_head;
661    for(; ipl_head;){
662      node = ipl_head;
663 -    delete ipl_head;
664      ipl_head = node->next;
665 +    delete node;
666    }
667    count = 0;
668  }
669 diff -u ctorrent-1.3.4.orig/peer.cpp ctorrent-1.3.4/peer.cpp
670 --- ctorrent-1.3.4.orig/peer.cpp        2004-09-09 01:10:51.000000000 +0200
671 +++ ctorrent-1.3.4/peer.cpp     2005-08-11 23:45:29.431693376 +0200
672 @@ -2,12 +2,34 @@
673  
674  #include <stdlib.h>
675  #include <string.h>
676 +#include <ctype.h>
677  
678 +#include "btstream.h"
679  #include "./btcontent.h"
680  #include "./msgencode.h"
681  #include "./peerlist.h"
682  #include "./btconfig.h"
683  
684 +size_t get_nl(char *sfrom)
685 +{
686 +  unsigned char *from = (unsigned char *)sfrom;
687 +  size_t t;
688 +  t = (*from++) << 24;
689 +  t |= (*from++) << 16;
690 +  t |= (*from++) << 8;
691 +  t |= *from;
692 +  return t;
693 +}
694 +
695 +void set_nl(char *sto, size_t from)
696 +{
697 +  unsigned char *to = (unsigned char *)sto;
698 +  *to++ = (from >> 24) & 0xff;
699 +  *to++ = (from >> 16) & 0xff;
700 +  *to++ = (from >> 8) & 0xff;
701 +  *to = from & 0xff;
702 +}
703 +
704  btBasic Self;
705  
706  void btBasic::SetIp(struct sockaddr_in addr)
707 @@ -44,11 +66,13 @@
708  
709  int btPeer::Need_Remote_Data()
710  {
711 +
712    if( BTCONTENT.pBF->IsFull()) return 0;
713    else if( bitfield.IsFull() ) return 1;
714    else{
715      BitField tmpBitfield = bitfield;
716      tmpBitfield.Except(*BTCONTENT.pBF);
717 +    tmpBitfield.Except(*BTCONTENT.pBFilter);
718      return tmpBitfield.IsEmpty() ? 0 : 1;
719    }
720    return 0;
721 @@ -65,6 +89,7 @@
722  
723    m_err_count = 0;
724    m_cached_idx = BTCONTENT.GetNPieces();
725 +  m_standby = 0;
726  }
727  
728  int btPeer::SetLocal(unsigned char s)
729 @@ -72,20 +97,30 @@
730    switch(s){
731    case M_CHOKE:
732      if( m_state.local_choked ) return 0;
733 +    time(&m_unchoke_timestamp);
734 +//  if(arg_verbose) fprintf(stderr, "Choking %p\n", this);
735 +    if(arg_verbose) fprintf(stderr, "Choking %p (D=%lluMB@%uK/s)\n", this,
736 +      TotalDL() >> 20, RateDL() >> 10);
737      m_state.local_choked = 1; 
738      break;
739    case M_UNCHOKE: 
740      if( !reponse_q.IsEmpty() ) StartULTimer();
741      if( !m_state.local_choked ) return 0;
742      time(&m_unchoke_timestamp);
743 +//  if(arg_verbose) fprintf(stderr, "Unchoking %p\n", this);
744 +    if(arg_verbose) fprintf(stderr, "Unchoking %p (D=%lluMB@%uK/s)\n", this,
745 +      TotalDL() >> 20, RateDL() >> 10);
746      m_state.local_choked = 0;
747      break;
748    case M_INTERESTED: 
749 +    m_standby = 0;
750      if( m_state.local_interested ) return 0;
751 +    if(arg_verbose) fprintf(stderr, "Interested in %p\n", this);
752      m_state.local_interested = 1;
753      break;
754    case M_NOT_INTERESTED:
755      if( !m_state.local_interested ) return 0;
756 +    if(arg_verbose) fprintf(stderr, "Not interested in %p\n", this);
757      m_state.local_interested = 0; 
758      break;
759    default:
760 @@ -97,12 +132,15 @@
761  int btPeer::RequestPiece()
762  {
763    size_t idx;
764 +  int endgame = 0;
765  
766    PENDINGQUEUE.ReAssign(&request_q,bitfield);
767  
768    if( !request_q.IsEmpty() ) return SendRequest();
769  
770 -  if( m_cached_idx < BTCONTENT.GetNPieces() ){
771 +  if( m_cached_idx < BTCONTENT.GetNPieces() && !BTCONTENT.pBF->IsEmpty() ){
772 +    // A HAVE msg already selected what we want from this peer
773 +    // but ignore it in initial-piece mode.
774      idx = m_cached_idx;
775      m_cached_idx = BTCONTENT.GetNPieces();
776      if( !BTCONTENT.pBF->IsSet(idx) &&
777 @@ -110,39 +148,72 @@
778         !WORLD.AlreadyRequested(idx) ){
779        return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();
780      }
781 -  }else{
782 +  }    // If we didn't want the cached piece, select another.
783 +  if( BTCONTENT.pBF->IsEmpty() ){
784 +    // If we don't have a complete piece yet, try to get one that's already
785 +    // in progress.  (Initial-piece mode)
786 +    btPeer *peer = WORLD.Who_Can_Duplicate(this, BTCONTENT.GetNPieces());
787 +    if(peer){
788 +      if(arg_verbose) fprintf( stderr, "Duping: %p to %p (#%u)\n",
789 +        peer, this, peer->request_q.GetRequestIdx() );
790 +      return (request_q.CopyShuffle(peer->request_q) < 0) ? -1 : SendRequest();
791 +    }
792 +  }    // Doesn't have a piece that's already in progress--choose another.
793      BitField tmpBitField;
794      if( bitfield.IsFull() ){
795 +      // peer is a seed
796        tmpBitField = *BTCONTENT.pBF;
797        tmpBitField.Invert();
798      }else{
799        tmpBitField = bitfield;
800        tmpBitField.Except(*BTCONTENT.pBF);
801      }
802 +    // The filter tells what we don't want.
803 +    tmpBitField.Except(*BTCONTENT.pBFilter);
804 +    // tmpBitField tells what we need from this peer...
805  
806      if( !tmpBitField.IsEmpty() ){
807 -      WORLD.CheckBitField(tmpBitField);
808 -      if(tmpBitField.IsEmpty()){
809 -       
810 -       btPeer *peer = WORLD.Who_Can_Abandon(this);
811 -       if(peer){
812 -         peer->StopDLTimer();
813 -         request_q = peer->request_q;
814 -
815 -         if(peer->CancelRequest(request_q.GetHead()) < 0 ||
816 -            peer->RequestCheck() < 0){
817 -           peer->CloseConnection();
818 -         }
819 -         
820 -         return SendRequest();
821 -       }
822 -       
823 +      BitField tmpBitField2 = tmpBitField;
824 +      WORLD.CheckBitField(tmpBitField2);
825 +      // [tmpBitField2]... that we haven't requested from anyone.
826 +      if(tmpBitField2.IsEmpty()){
827 +        // Everything this peer has that I want, I've already requested.
828 +        endgame = ( WORLD.Pieces_I_Can_Get() - BTCONTENT.pBF->Count() )
829 +            < WORLD.TotalPeers();
830 +        if(endgame){   // OK to duplicate a request.
831 +//       idx = tmpBitField.Random();
832 +         idx = 0;      // flag for Who_Can_Duplicate()
833 +         btPeer *peer = WORLD.Who_Can_Duplicate(this, idx);
834 +         if(arg_verbose) fprintf( stderr, "Duping: %p to %p (#%u)\n",
835 +           peer, this, peer->request_q.GetRequestIdx() );
836 +         return (request_q.CopyShuffle(peer->request_q) < 0) ?
837 +            -1 : SendRequest();
838 +        }else{ // not endgame mode
839 +         btPeer *peer = WORLD.Who_Can_Abandon(this); // slowest choice
840 +         if(peer){
841 +           // Cancel a request to the slowest peer & request it from this one.
842 +           if(arg_verbose) fprintf( stderr, "Reassigning %p to %p (#%u)\n",
843 +             peer, this, peer->request_q.GetRequestIdx() );
844 +           peer->StopDLTimer();
845 +           // RequestQueue class "moves" rather than "copies" in assignment!
846 +           request_q = peer->request_q;
847 +
848 +           if(peer->CancelRequest(request_q.GetHead()) < 0 ||
849 +               peer->RequestCheck() < 0){
850 +             peer->CloseConnection();
851 +           }
852 +           return SendRequest();
853 +         }else m_standby = 1;  // nothing to do at the moment
854 +        }
855        }else{
856 -       idx = tmpBitField.Random();
857 -       return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();
858 +        // Request something that we haven't requested yet (most common case).
859 +        idx = tmpBitField2.Random();
860 +        return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();
861        }
862 +    } else {
863 +      // We don't need anything from the peer.  How'd we get here?
864 +      return SetLocal(M_NOT_INTERESTED);
865      }
866 -  }
867    return 0;
868  }
869  
870 @@ -152,37 +223,46 @@
871  
872    char *msgbuf = stream.in_buffer.BasePointer();
873  
874 -  r = ntohl(*(size_t*) msgbuf);
875 +  r = get_nl(msgbuf);
876  
877 +  // Don't require keepalives if we're receiving other messages.
878 +  time(&m_last_timestamp);
879    if( 0 == r ){
880 -    time(&m_last_timestamp);
881      if( !m_f_keepalive ) if( stream.Send_Keepalive() < 0 ) return -1;
882      m_f_keepalive = 0;
883 -    return (!m_state.remote_choked && request_q.IsEmpty()) ? RequestCheck() : 0;
884 +    return 0;
885    }else{
886      switch(msgbuf[4]){
887      case M_CHOKE:
888        if(H_BASE_LEN != r){ return -1;}
889 +      if(arg_verbose) fprintf(stderr, "%p choked me\n", this);
890        m_state.remote_choked = 1;
891        StopDLTimer();
892        if( !request_q.IsEmpty()){
893         PSLICE ps = request_q.GetHead();
894 -       PENDINGQUEUE.Pending(&request_q);
895 +       if( !PENDINGQUEUE.Exist(request_q.GetRequestIdx()) )
896 +         PENDINGQUEUE.Pending(&request_q);
897         if( CancelRequest(ps) < 0) return -1;
898        }
899        return 0;
900 +
901      case M_UNCHOKE:
902        if(H_BASE_LEN != r){return -1;}
903 +      if(arg_verbose) fprintf(stderr, "%p unchoked me\n", this);
904        m_state.remote_choked = 0;
905 +      if(!request_q.IsEmpty()) // shouldn't happen; maybe peer is confused.
906 +        return SendRequest();
907        return RequestCheck();
908  
909      case M_INTERESTED:
910        if(H_BASE_LEN != r){return -1;}
911 +      if(arg_verbose) fprintf(stderr, "%p is interested\n", this);
912        m_state.remote_interested = 1;
913        break;
914  
915      case M_NOT_INTERESTED:
916        if(r != H_BASE_LEN){return -1;}
917 +      if(arg_verbose) fprintf(stderr, "%p is not interested\n", this);
918  
919        m_state.remote_interested = 0;
920        StopULTimer();
921 @@ -190,10 +270,11 @@
922        /* remove peer's reponse queue */
923        if( !reponse_q.IsEmpty()) reponse_q.Empty();
924        return 0;
925 +
926      case M_HAVE:
927        if(H_HAVE_LEN != r){return -1;}
928  
929 -      idx = ntohl(*(size_t*) (msgbuf + 5));
930 +      idx = get_nl(msgbuf + 5);
931  
932        if( idx >= BTCONTENT.GetNPieces() || bitfield.IsSet(idx)) return -1;
933  
934 @@ -201,19 +282,24 @@
935  
936        if( bitfield.IsFull() && BTCONTENT.pBF->IsFull() ){ return -2; }
937  
938 -      if( !BTCONTENT.pBF->IsSet(idx) ) m_cached_idx = idx;
939 +      if( !BTCONTENT.pBF->IsSet(idx) && !BTCONTENT.pBFilter->IsSet(idx) ){
940 +        m_cached_idx = idx;
941 +        m_standby = 0;
942 +      }
943 +      //      if( !BTCONTENT.pBF->IsSet(idx) ) m_cached_idx = idx;
944        
945 -      return ( !m_state.remote_choked && request_q.IsEmpty() ) ? RequestCheck() : 0;
946 +      // see if we're Interested now
947 +      return request_q.IsEmpty() ? RequestCheck() : 0;
948  
949      case M_REQUEST:
950        if(H_REQUEST_LEN != r || !m_state.remote_interested){ return -1; }
951  
952 -      idx = ntohl(*(size_t*)(msgbuf + 5));
953 +      idx = get_nl(msgbuf + 5);
954        
955        if( !BTCONTENT.pBF->IsSet(idx) ) return -1;
956        
957 -      off = ntohl(*(size_t*)(msgbuf + 9));
958 -      len = ntohl(*(size_t*)(msgbuf + 13));
959 +      off = get_nl(msgbuf + 9);
960 +      len = get_nl(msgbuf + 13);
961  
962        if( !reponse_q.IsValidRequest(idx, off, len) ) return -1;
963        
964 @@ -222,6 +308,8 @@
965      case M_PIECE:
966        if( request_q.IsEmpty() || !m_state.local_interested){
967         m_err_count++;
968 +       if(arg_verbose) fprintf(stderr,"err: %p (%d) Unwanted piece\n",
969 +         this, m_err_count);
970         return 0;
971        }
972        return PieceDeliver(r);
973 @@ -230,22 +318,28 @@
974        if( (r - 1) != bitfield.NBytes() || !bitfield.IsEmpty()) return -1;
975        bitfield.SetReferBuffer(msgbuf + 5);
976        if(bitfield.IsFull() && BTCONTENT.pBF->IsFull()) return -2;
977 -      return 0;
978 +
979 +      //This is needed in order to set our Interested state
980 +      return RequestCheck(); // fixed client stall
981  
982      case M_CANCEL:
983        if(r != H_CANCEL_LEN || !m_state.remote_interested) return -1;
984  
985 -      idx = ntohl(*(size_t*)(msgbuf + 5));
986 -      off = ntohl(*(size_t*)(msgbuf + 9));
987 -      len = ntohl(*(size_t*)(msgbuf + 13));
988 +      idx = get_nl(msgbuf + 5);
989 +      off = get_nl(msgbuf + 9);
990 +      len = get_nl(msgbuf + 13);
991        if( reponse_q.Remove(idx,off,len) < 0 ){
992         m_err_count++;
993 +       if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad cancel\n",
994 +         this, m_err_count);
995         return 0;
996        }
997        if( reponse_q.IsEmpty() ) StopULTimer();
998        return 0;
999      default:
1000 -      return -1;               // unknow message type
1001 +      if(arg_verbose) fprintf(stderr, "Unknown message type %u from peer %p\n",
1002 +        msgbuf[4], this);
1003 +      return 0;        // ignore unknown message & continue (forward compatibility)
1004      }
1005    }
1006    return 0;
1007 @@ -279,8 +373,13 @@
1008  int btPeer::SendRequest()
1009  {
1010    PSLICE ps = request_q.GetHead();
1011 -  for( ; ps ; ps = ps->next )
1012 +  if(arg_verbose) fprintf(stderr, "Requesting #%u from %p:",
1013 +    request_q.GetRequestIdx(), this);
1014 +  for( ; ps ; ps = ps->next ){
1015 +    if(arg_verbose) fprintf(stderr, ".");
1016      if(stream.Send_Request(ps->index,ps->offset,ps->length) < 0){ return -1; }
1017 +  }
1018 +  if(arg_verbose) fprintf(stderr, "\n");
1019  
1020    return stream.Flush();
1021  }
1022 @@ -294,16 +393,56 @@
1023    return stream.Flush();
1024  }
1025  
1026 +int btPeer::CancelSliceRequest(size_t idx, size_t off, size_t len)
1027 +{
1028 +  PSLICE ps;
1029 +
1030 +  for(ps = request_q.GetHead() ; ps; ps = ps->next){
1031 +    if( idx == ps->index && off == ps->offset && len == ps->length ){
1032 +      if( request_q.Remove(idx,off,len) < 0 ){
1033 +        m_err_count++;
1034 +        if(arg_verbose) fprintf(stderr,"err: %p (%d) Bad CS remove\n",
1035 +          this, m_err_count);
1036 +      }
1037 +      if(stream.Send_Cancel(idx,off,len) < 0)
1038 +        return -1;
1039 +      return stream.Flush();
1040 +    }
1041 +  }
1042 +  return 0;
1043 +}
1044 +
1045  int btPeer::ReportComplete(size_t idx)
1046  {
1047    if( BTCONTENT.APieceComplete(idx) ){
1048 +    if(arg_verbose) fprintf(stderr, "Piece #%u completed\n", idx);
1049      WORLD.Tell_World_I_Have(idx);
1050 +    PENDINGQUEUE.Delete(idx);
1051      if( BTCONTENT.pBF->IsFull() ){
1052        ResetDLTimer();
1053        WORLD.CloseAllConnectionToSeed();
1054      }
1055 -  }else
1056 +
1057 +    if( arg_file_to_download ){
1058 +      BitField tmpBitField =  *BTCONTENT.pBF;
1059 +      tmpBitField.Except(*BTCONTENT.pBFilter);
1060 +
1061 +      while( arg_file_to_download &&
1062 +        tmpBitField.Count() >= BTCONTENT.getFilePieces(arg_file_to_download) ){
1063 +        //when the file is complete, we go after the next
1064 +        ++arg_file_to_download;
1065 +        BTCONTENT.FlushCache();
1066 +        BTCONTENT.SetFilter();
1067 +        tmpBitField =  *BTCONTENT.pBF;
1068 +        tmpBitField.Except(*BTCONTENT.pBFilter);
1069 +      }
1070 +      WORLD.CheckInterest();
1071 +    }
1072 +  }else{
1073      m_err_count++;
1074 +    if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad complete\n",
1075 +      this, m_err_count);
1076 +  }
1077    return (P_FAILED == m_status) ? -1 : RequestCheck();
1078  }
1079  
1080 @@ -312,12 +451,14 @@
1081    size_t idx,off,len;
1082    char *msgbuf = stream.in_buffer.BasePointer();
1083  
1084 -  idx = ntohl(*(size_t*) (msgbuf + 5));
1085 -  off = ntohl(*(size_t*) (msgbuf + 9));
1086 +  idx = get_nl(msgbuf + 5);
1087 +  off = get_nl(msgbuf + 9);
1088    len = mlen - 9;
1089  
1090    if( request_q.Remove(idx,off,len) < 0 ){
1091      m_err_count++;
1092 +    if(arg_verbose) fprintf(stderr, "err: %p (%d) Bad remove\n",
1093 +      this, m_err_count);
1094      return 0;
1095    }
1096  
1097 @@ -329,13 +470,21 @@
1098    Self.DataRecved(len);
1099    DataRecved(len);
1100  
1101 +  // Check for & cancel requests for this slice from other peers in initial
1102 +  // and endgame modes.
1103 +  if( BTCONTENT.pBF->Count() < 2 ||
1104 +      WORLD.Pieces_I_Can_Get() - BTCONTENT.pBF->Count() < WORLD.TotalPeers() ){
1105 +    WORLD.CancelSlice(idx, off, len);
1106 +    PENDINGQUEUE.DeleteSlice(idx, off, len);
1107 +  }
1108 +
1109    /* if piece download complete. */
1110    return request_q.IsEmpty() ? ReportComplete(idx) : 0;
1111  }
1112  
1113  int btPeer::RequestCheck()
1114  {
1115 -  if( BandWidthLimit() ) return 0;
1116 +  if( BandWidthLimitDown() ) return 0;
1117    
1118    if( BTCONTENT.pBF->IsFull() ){
1119      if( bitfield.IsFull() ){ return -1; }
1120 @@ -347,7 +496,8 @@
1121      if(request_q.IsEmpty() && !m_state.remote_choked){
1122        if( RequestPiece() < 0 ) return -1;
1123      }
1124 -  }
1125 +  } else
1126 +    if(m_state.local_interested && SetLocal(M_NOT_INTERESTED) < 0) return -1;
1127    
1128    if(!request_q.IsEmpty()) StartDLTimer();
1129    return 0;
1130 @@ -355,6 +505,7 @@
1131  
1132  void btPeer::CloseConnection()
1133  {
1134 +  if(arg_verbose) fprintf(stderr, "%p closed\n", this);
1135    if( P_FAILED != m_status ){
1136      m_status = P_FAILED;
1137      stream.Close();
1138 @@ -364,13 +515,76 @@
1139  int btPeer::HandShake()
1140  {
1141    ssize_t r = stream.Feed();
1142 -  if( r < 0 ) return -1;
1143 +  if( r < 0 ){
1144 +//  if(arg_verbose) fprintf(stderr, "hs: r<0 (%d)\n", r);
1145 +    return -1;
1146 +  }
1147    else if( r < 68 ){
1148 -    if(r && memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),r) != 0) return -1;
1149 +    if(r >= 21){       // Ignore 8 reserved bytes following protocol ID.
1150 +      if( memcmp(stream.in_buffer.BasePointer()+20,
1151 +          BTCONTENT.GetShakeBuffer()+20, (r<28) ? r-20 : 8) != 0 ){
1152 +        if(arg_verbose){
1153 +          if( r>48 ) fprintf( stderr, "\npeer %p gave 0x", this);
1154 +          else fprintf( stderr, "\npeer gave 0x" );
1155 +          for(int i=20; i<r && i<27; i++) fprintf(stderr, "%2.2hx",
1156 +            (u_short)(u_char)(stream.in_buffer.BasePointer()[i]));
1157 +          fprintf( stderr, " as reserved bytes (partial)\n" );
1158 +        }
1159 +        memcpy(stream.in_buffer.BasePointer()+20, BTCONTENT.GetShakeBuffer()+20,
1160 +          (r<28) ? r-20 : 8);
1161 +      }
1162 +    }
1163 +    if(r && memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),
1164 +        (r<48) ? r : 48) != 0){
1165 +      if(arg_verbose){
1166 +        fprintf(stderr, "\nmine: 0x");
1167 +        for(int i=0; i<r && i<48; i++) fprintf(stderr, "%2.2hx",
1168 +          (u_short)(u_char)(BTCONTENT.GetShakeBuffer()[i]));
1169 +        fprintf(stderr, "\npeer: 0x");
1170 +        for(int i=0; i<r && i<48; i++) fprintf(stderr, "%2.2hx",
1171 +          (u_short)(u_char)(stream.in_buffer.BasePointer()[i]));
1172 +        fprintf(stderr, "\n");
1173 +        fprintf(stderr, "peer is %.8s\n", stream.in_buffer.BasePointer()+48);
1174 +      }
1175 +      return -1;
1176 +    }
1177      return 0;
1178    }
1179  
1180 -  if( memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),48) != 0 ) return -1;
1181 +  // If the reserved bytes differ, make them the same.
1182 +  // If they mean anything important, the handshake is likely to fail anyway.
1183 +  if( memcmp(stream.in_buffer.BasePointer()+20, BTCONTENT.GetShakeBuffer()+20,
1184 +      8) != 0 ){
1185 +    if(arg_verbose){
1186 +      fprintf(stderr, "\npeer %p gave 0x", this);
1187 +      for(int i=20; i<27; i++) fprintf(stderr, "%2.2hx",
1188 +        (u_short)(u_char)(stream.in_buffer.BasePointer()[i]));
1189 +      fprintf( stderr, " as reserved bytes\n" );
1190 +    }
1191 +    memcpy(stream.in_buffer.BasePointer()+20, BTCONTENT.GetShakeBuffer()+20, 8);
1192 +  }
1193 +  if( memcmp(stream.in_buffer.BasePointer(),BTCONTENT.GetShakeBuffer(),48) != 0 ){
1194 +    if(arg_verbose){
1195 +      fprintf(stderr, "\nmine: 0x");
1196 +      for(int i=0; i<48; i++) fprintf(stderr, "%2.2hx",
1197 +        (u_short)(u_char)(BTCONTENT.GetShakeBuffer()[i]));
1198 +      fprintf(stderr, "\npeer: 0x");
1199 +      for(int i=0; i<48; i++) fprintf(stderr, "%2.2hx",
1200 +        (u_short)(u_char)(stream.in_buffer.BasePointer()[i]));
1201 +      fprintf(stderr, "\n");
1202 +    }
1203 +    return -1;
1204 +  }
1205 +
1206 +  if(arg_verbose){
1207 +    fprintf(stderr, "Peer %p ID: ", this);
1208 +    for(int i=48; i<60; i++){
1209 +      if( isprint(stream.in_buffer.BasePointer()[i]) )
1210 +        fprintf(stderr, "%c", stream.in_buffer.BasePointer()[i]);
1211 +      else break;
1212 +    }
1213 +    fprintf(stderr, "\n");
1214 +  }
1215  
1216    // ignore peer id verify
1217    if( !BTCONTENT.pBF->IsEmpty()){
1218 @@ -395,10 +609,17 @@
1219    return stream.Send_Buffer((char*)BTCONTENT.GetShakeBuffer(),68);
1220  }
1221  
1222 -int btPeer::BandWidthLimit()
1223 +int btPeer::BandWidthLimitUp()
1224 +{
1225 +  if( cfg_max_bandwidth_up <= 0 ) return 0;
1226 +  return ((Self.RateUL()) >= cfg_max_bandwidth_up) ?
1227 +    1:0;
1228 +}
1229 +
1230 +int btPeer::BandWidthLimitDown()
1231  {
1232 -  if( cfg_max_bandwidth <= 0 ) return 0;
1233 -  return ((Self.RateDL() + Self.RateUL()*2) / 1024 >= cfg_max_bandwidth) ?
1234 +  if( cfg_max_bandwidth_down <= 0 ) return 0;
1235 +  return ((Self.RateDL()) >= cfg_max_bandwidth_down) ?
1236      1:0;
1237  }
1238  
1239 @@ -406,12 +627,23 @@
1240  {
1241    int yn = 0;
1242    if( stream.out_buffer.Count() || // data need send in buffer.
1243 -      (!reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimit()) ||
1244 +      (!reponse_q.IsEmpty() && CouldReponseSlice() && !  BandWidthLimitUp()) ||
1245 +      ( !m_state.remote_choked && request_q.IsEmpty()
1246 +           && m_state.local_interested
1247 +           && !BandWidthLimitDown() && !m_standby ) || // can request a piece.
1248        P_CONNECTING == m_status ) // peer is connecting
1249      yn = 1;
1250    return yn;
1251  }
1252  
1253 +int btPeer::NeedRead()
1254 +{
1255 +  int yn = 1;
1256 +  if( !request_q.IsEmpty() && BandWidthLimitDown() )
1257 +    yn = 0;
1258 +  return yn;
1259 +}
1260 +
1261  int btPeer::CouldReponseSlice()
1262  {
1263    if(!m_state.local_choked &&
1264 @@ -453,15 +685,15 @@
1265  {
1266    if( stream.out_buffer.Count() && stream.Flush() < 0) return -1;
1267  
1268 -  if(! reponse_q.IsEmpty() &&  CouldReponseSlice() ) {
1269 +  if( !reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimitUp() ) {
1270      StartULTimer();
1271      Self.StartULTimer();
1272    }
1273  
1274 -  for(; !reponse_q.IsEmpty() && CouldReponseSlice(); )
1275 +  for(; !reponse_q.IsEmpty() && CouldReponseSlice() && !BandWidthLimitUp(); )
1276      if( ReponseSlice() < 0) return -1;
1277  
1278 -  return 0;
1279 +  return (!m_state.remote_choked && request_q.IsEmpty()) ? RequestCheck() : 0;
1280  }
1281  
1282  void btPeer::dump()
1283 diff -u ctorrent-1.3.4.orig/peer.h ctorrent-1.3.4/peer.h
1284 --- ctorrent-1.3.4.orig/peer.h  2004-09-09 01:10:51.000000000 +0200
1285 +++ ctorrent-1.3.4/peer.h       2005-08-11 23:45:29.432693224 +0200
1286 @@ -34,6 +34,9 @@
1287    unsigned char reserved:4;            /* unused */
1288  }BTSTATUS;
1289  
1290 +size_t get_nl(char *from);
1291 +void set_nl(char *to, size_t from);
1292 +
1293  class btBasic
1294  {
1295  private:
1296 @@ -84,6 +87,7 @@
1297  
1298    size_t m_cached_idx;
1299    size_t m_err_count;
1300 +  int m_standby;
1301    
1302    int PieceDeliver(size_t mlen);
1303    int ReportComplete(size_t idx);
1304 @@ -96,6 +100,8 @@
1305    int CouldReponseSlice();
1306  
1307    int BandWidthLimit();
1308 +  int BandWidthLimitUp();
1309 +  int BandWidthLimitDown();
1310   public:
1311    BitField bitfield;
1312    btStream stream;
1313 @@ -118,10 +124,12 @@
1314    int Is_Local_UnChoked() const { return m_state.local_choked ? 0 : 1; }
1315    int SetLocal(unsigned char s);
1316  
1317 +  int CancelSliceRequest(size_t idx, size_t off, size_t len);
1318    
1319    void SetStatus(unsigned char s){ m_status = s; }
1320    unsigned char GetStatus() const { return m_status; }
1321    int NeedWrite();
1322 +  int NeedRead();
1323  
1324    
1325    void CloseConnection();
1326 diff -u ctorrent-1.3.4.orig/peerlist.cpp ctorrent-1.3.4/peerlist.cpp
1327 --- ctorrent-1.3.4.orig/peerlist.cpp    2004-09-09 01:10:51.000000000 +0200
1328 +++ ctorrent-1.3.4/peerlist.cpp 2005-08-11 23:45:29.433693072 +0200
1329 @@ -21,6 +21,8 @@
1330  #define MAX_UNCHOKE 3
1331  #define UNCHOKE_INTERVAL 10
1332  
1333 +#define OPT_INTERVAL 30
1334 +
1335  #define KEEPALIVE_INTERVAL 117
1336  
1337  #define LISTEN_PORT_MAX 2706
1338 @@ -36,12 +38,13 @@
1339  
1340  PeerList::PeerList()
1341  {
1342 -  m_unchoke_check_timestamp = 
1343 -    m_keepalive_check_timestamp = time((time_t*) 0);
1344 +  m_unchoke_check_timestamp =
1345 +    m_keepalive_check_timestamp =
1346 +    m_opt_timestamp = time((time_t*) 0);
1347  
1348    m_head = (PEERNODE*) 0;
1349    m_listen_sock = INVALID_SOCKET;
1350 -  m_peers_count = 0;
1351 +  m_peers_count = m_seeds_count = 0;
1352    m_live_idx = 0;
1353  }
1354  
1355 @@ -118,6 +121,8 @@
1356      
1357      if( setfd_nonblock(sk) < 0) goto err;
1358  
1359 +    if(arg_verbose) fprintf(stderr, "Connecting to %s:%hu\n",
1360 +        inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
1361      if( -1 == (r = connect_nonb(sk,(struct sockaddr*)&addr)) ) return -1;
1362  
1363      peer = new btPeer;
1364 @@ -182,19 +187,44 @@
1365      if(NewPeer(addr,INVALID_SOCKET) == -4) break;
1366    }
1367  
1368 +
1369    // show status line.
1370    if( m_pre_dlrate.TimeUsed(pnow) ){
1371 -    printf("\r                                                                           ");
1372 -       printf("\r%c %u,[%u/%u/%u],%u,%u | %u,%u  E:%u",
1373 +    char partial[30] = "";
1374 +    if(arg_file_to_download){
1375 +      BitField tmpBitField =  *BTCONTENT.pBF;
1376 +      tmpBitField.Except(*BTCONTENT.pBFilter);
1377 +      sprintf( partial, "P:%u/%u ", 
1378 +       tmpBitField.Count(),
1379 +       BTCONTENT.getFilePieces(arg_file_to_download) );
1380 +    }
1381 +    printf("\r                                                                               ");
1382 +    printf("\r%c %u/%u/%u [%u/%u/%u] %lluMB,%lluMB | %u,%uK/s | %u,%uK E:%u,%u %s%s ",
1383            LIVE_CHAR[m_live_idx],
1384 -          m_peers_count,
1385 +
1386 +          m_seeds_count,
1387 +          m_peers_count - m_seeds_count,
1388 +          Tracker.GetPeersCount(),
1389 +
1390            BTCONTENT.pBF->Count(),
1391            BTCONTENT.pBF->NBits(),
1392            Pieces_I_Can_Get(),
1393 -          Self.RateDL(), Self.RateUL(),
1394 -          m_pre_dlrate.RateMeasure(Self.GetDLRate()),
1395 -          m_pre_ulrate.RateMeasure(Self.GetULRate()),
1396 -          Tracker.GetRefuseClick());
1397 +
1398 +          Self.TotalDL() >> 20, Self.TotalUL() >> 20,
1399 +
1400 +          Self.RateDL() >> 10, Self.RateUL() >> 10,
1401 +
1402 +          m_pre_dlrate.RateMeasure(Self.GetDLRate()) >> 10,
1403 +          m_pre_ulrate.RateMeasure(Self.GetULRate()) >> 10,
1404 +
1405 +          Tracker.GetRefuseClick(),
1406 +          Tracker.GetOkClick(),
1407 +
1408 +          partial,
1409 +
1410 +          (Tracker.GetStatus()==1) ? "Connecting" :
1411 +              ((Tracker.GetStatus()==2) ? "Connected" : "")
1412 +    );
1413      fflush(stdout);
1414      m_pre_dlrate = Self.GetDLRate();
1415      m_pre_ulrate = Self.GetULRate();
1416 @@ -214,8 +244,12 @@
1417      Sort();
1418    }
1419  
1420 -  if( f_unchoke_check ) memset(UNCHOKER, 0, (MAX_UNCHOKE + 1) * sizeof(btPeer*));
1421 +  if( f_unchoke_check ) {
1422 +    memset(UNCHOKER, 0, (MAX_UNCHOKE + 1) * sizeof(btPeer*));
1423 +    if (OPT_INTERVAL <= *pnow - m_opt_timestamp) m_opt_timestamp = 0;
1424 +  }
1425  
1426 +  m_seeds_count = 0;
1427    for(p = m_head; p;){
1428      if( PEER_IS_FAILED(p->peer)){
1429        if( pp ) pp->next = p->next; else m_head = p->next;
1430 @@ -225,9 +259,11 @@
1431        if( pp ) p = pp->next; else p = m_head;
1432        continue;
1433      }else{
1434 +      if (p->peer->bitfield.IsFull()) m_seeds_count++;
1435        if( f_keepalive_check ){
1436  
1437         if(3 * KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp())){
1438 +         if(arg_verbose) fprintf(stderr, "close: keepalive expired\n");
1439           p->peer->CloseConnection();
1440           goto skip_continue;
1441         }
1442 @@ -235,28 +271,26 @@
1443         if(PEER_IS_SUCCESS(p->peer) && 
1444            KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp()) &&
1445            p->peer->AreYouOK() < 0){
1446 +          if(arg_verbose) fprintf(stderr, "close: keepalive death\n");
1447           p->peer->CloseConnection();
1448           goto skip_continue;
1449         }
1450        }
1451  
1452 -      if( f_unchoke_check ){
1453 -
1454 -       if(PEER_IS_SUCCESS(p->peer) && p->peer->Need_Local_Data()){
1455 +      if( f_unchoke_check && PEER_IS_SUCCESS(p->peer) ){
1456  
1457 -         if((time_t) 0 == p->peer->GetLastUnchokeTime()){
1458 -           if(p->peer->SetLocal(M_UNCHOKE) < 0){
1459 -             p->peer->CloseConnection();
1460 -             goto skip_continue;
1461 -           }
1462 -         }else
1463 +       if( p->peer->Is_Remote_Interested() && p->peer->Need_Local_Data() )
1464             UnChokeCheck(p->peer, UNCHOKER);
1465 -       }
1466 +       else if(p->peer->SetLocal(M_CHOKE) < 0){
1467 +         if(arg_verbose) fprintf(stderr, "close: Can't choke peer\n");
1468 +         p->peer->CloseConnection();
1469 +         goto skip_continue;
1470 +        }
1471        }
1472  
1473        sk = p->peer->stream.GetSocket();
1474        if(maxfd < sk) maxfd = sk;
1475 -      FD_SET(sk,rfdp);
1476 +      if( p->peer->NeedRead() ) FD_SET(sk,rfdp);
1477  
1478        if( p->peer->NeedWrite() ) FD_SET(sk,wfdp);
1479      skip_continue: 
1480 @@ -272,13 +306,26 @@
1481    }
1482  
1483    if( f_unchoke_check ){
1484 +//  if (!m_opt_timestamp) m_opt_timestamp = *pnow;
1485 +    if(arg_verbose) fprintf(stderr, "\nUnchoker ");
1486 +    if (!m_opt_timestamp){
1487 +      if(arg_verbose) fprintf(stderr, "(opt) ");
1488 +      m_opt_timestamp = *pnow;
1489 +    }
1490      for( i = 0; i < MAX_UNCHOKE + 1; i++){
1491  
1492        if( (btPeer*) 0 == UNCHOKER[i]) break;
1493  
1494        if( PEER_IS_FAILED(UNCHOKER[i]) ) continue;
1495  
1496 +      if(arg_verbose){
1497 +        fprintf(stderr, "D=%lluMB@%uK/s:U=%lluMB ",
1498 +          UNCHOKER[i]->TotalDL() >> 20, UNCHOKER[i]->RateDL() >> 10,
1499 +          UNCHOKER[i]->TotalUL() >> 20);
1500 +        if( UNCHOKER[i]->bitfield.IsEmpty() ) fprintf(stderr, "(empty) ");
1501 +      }
1502        if( UNCHOKER[i]->SetLocal(M_UNCHOKE) < 0){
1503 +        if(arg_verbose) fprintf(stderr, "close: Can't unchoke peer\n");
1504         UNCHOKER[i]->CloseConnection();
1505         continue;
1506        }
1507 @@ -290,6 +337,7 @@
1508         if( maxfd < sk) maxfd = sk;
1509        }
1510      } // end for
1511 +    if(arg_verbose) fprintf(stderr, "\n");
1512    }
1513    
1514    return maxfd;
1515 @@ -314,6 +362,64 @@
1516    return peer;
1517  }
1518  
1519 +// Duplicating a request queue that's in progress rather than creating a new
1520 +// one helps avoid requesting slices that we already have.
1521 +// This takes an index parameter to facilitate modification of the function to
1522 +// allow targeting of a specific piece.  It's currently only used as a flag to
1523 +// specify endgame or initial-piece mode though.
1524 +btPeer* PeerList::Who_Can_Duplicate(btPeer *proposer, size_t idx)
1525 +{
1526 +  PEERNODE *p;
1527 +  btPeer *peer = (btPeer*) 0;
1528 +  int endgame;
1529 +  size_t qsize, mark, bench;
1530 +  // In endgame mode, select from peers with the longest request queue.
1531 +  // In initial mode, select from peers with the shortest non-empty request
1532 +  // queue.
1533 +
1534 +  endgame = idx < BTCONTENT.GetNPieces();      // else initial-piece mode
1535 +  if(endgame) mark = 0;
1536 +  else mark = cfg_req_queue_length;
1537 +  bench = BTCONTENT.GetNPieces();
1538 +
1539 +  for(p = m_head; p; p = p->next){
1540 +    if(!PEER_IS_SUCCESS(p->peer) || p->peer == proposer ||
1541 +       p->peer->request_q.IsEmpty() ) continue;
1542 +
1543 +    if(proposer->bitfield.IsSet(p->peer->request_q.GetRequestIdx())){
1544 +      qsize = p->peer->request_q.Qsize();
1545 +      if( (endgame && qsize > mark) || (!endgame && qsize && qsize < mark) ){
1546 +        mark = qsize;
1547 +        peer = p->peer;
1548 +      }else if( qsize == mark ){
1549 +        if( bench != p->peer->request_q.GetRequestIdx() && random()&01 ){
1550 +          bench = peer->request_q.GetRequestIdx();
1551 +          peer = p->peer;
1552 +        }
1553 +      }
1554 +    }
1555 +  }
1556 +  return peer;
1557 +}
1558 +
1559 +void PeerList::CancelSlice(size_t idx, size_t off, size_t len)
1560 +{
1561 +  PEERNODE *p;
1562 +  PSLICE ps;
1563 +
1564 +  for( p = m_head; p; p = p->next){
1565 +    
1566 +    if( !PEER_IS_SUCCESS(p->peer) ) continue;
1567 +
1568 +    if( idx == p->peer->request_q.GetRequestIdx() ) {
1569 +      if (p->peer->CancelSliceRequest(idx,off,len) < 0) {
1570 +        if(arg_verbose) fprintf(stderr, "close: CancelSlice\n");
1571 +        p->peer->CloseConnection();
1572 +      }
1573 +    }
1574 +  }
1575 +}
1576 +
1577  void PeerList::Tell_World_I_Have(size_t idx)
1578  {
1579    PEERNODE *p;
1580 @@ -330,7 +436,12 @@
1581      
1582      if( f_seed ){
1583        if( !p->peer->request_q.IsEmpty() ) p->peer->request_q.Empty();
1584 -      if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) p->peer->CloseConnection();
1585 +//    if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) p->peer->CloseConnection();
1586 +      if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) {
1587 +        if(arg_verbose)
1588 +          fprintf(stderr, "close: Can't set self not interested (T_W_I_H)\n");
1589 +        p->peer->CloseConnection();
1590 +      }
1591      }
1592      
1593    } // end for
1594 @@ -474,15 +585,20 @@
1595         FD_CLR(sk,wfdp);
1596  
1597         if(FD_ISSET(sk,rfdp)){  // connect failed.
1598 +         (*nready)--; 
1599           FD_CLR(sk,rfdp);
1600           peer->CloseConnection();
1601         }else{
1602           if(peer->Send_ShakeInfo() < 0){
1603 +           if(arg_verbose) fprintf(stderr, "close: Sending handshake\n");
1604             peer->CloseConnection();
1605           }
1606           else 
1607             peer->SetStatus(P_HANDSHAKE);
1608         }
1609 +      }else if(FD_ISSET(sk,rfdp)){
1610 +       (*nready)--; 
1611 +       peer->CloseConnection();
1612        }
1613      }else{
1614        if(FD_ISSET(sk,rfdp)){
1615 @@ -493,18 +609,29 @@
1616         (*nready)--;
1617         FD_CLR(sk,rfdp);
1618         if(peer->GetStatus() == P_HANDSHAKE){
1619 -         if( peer->HandShake() < 0 ) peer->CloseConnection();
1620 -       }else{
1621 -         if( peer->RecvModule() < 0 ) peer->CloseConnection();
1622 +         if( peer->HandShake() < 0 ) {
1623 +           if(arg_verbose) fprintf(stderr, "close: bad handshake\n");
1624 +           peer->CloseConnection();
1625 +         }
1626 +       } // fixed client stall
1627 +       if(peer->GetStatus() == P_SUCCESS){
1628 +         if( peer->RecvModule() < 0 ) {
1629 +           if(arg_verbose) fprintf(stderr, "close: receive\n");
1630 +           peer->CloseConnection();
1631 +         }
1632         }
1633 -      }else if(PEER_IS_SUCCESS(peer) && FD_ISSET(sk,wfdp)){
1634 +      }
1635 +      if(PEER_IS_SUCCESS(peer) && FD_ISSET(sk,wfdp)){
1636         p->click++;
1637         if( !(p->click) )
1638           for(p2 = m_head; p2; p2=p2->next) p2->click = 0;
1639  
1640         (*nready)--;
1641         FD_CLR(sk,wfdp);
1642 -       if( peer->SendModule() < 0 ) peer->CloseConnection();
1643 +       if( peer->SendModule() < 0 ) {
1644 +         if(arg_verbose) fprintf(stderr, "close: send\n");
1645 +         peer->CloseConnection();
1646 +       }
1647        }
1648      }
1649    }// end for
1650 @@ -514,7 +641,11 @@
1651  {
1652    PEERNODE *p = m_head;
1653    for( ; p; p = p->next)
1654 -    if(p->peer->bitfield.IsFull()) p->peer->CloseConnection();
1655 +//  if(p->peer->bitfield.IsFull()) p->peer->CloseConnection();
1656 +    if(p->peer->bitfield.IsFull()) {
1657 +      if(arg_verbose) fprintf(stderr, "close: seed<->seed\n");
1658 +      p->peer->CloseConnection();
1659 +    }
1660  }
1661  
1662  void PeerList::UnChokeCheck(btPeer* peer, btPeer *peer_array[])
1663 @@ -523,8 +654,15 @@
1664    int cancel_idx = 0;
1665    btPeer *loster = (btPeer*) 0;
1666    int f_seed = BTCONTENT.pBF->IsFull();
1667 +  int no_opt = 0;
1668 +
1669 +  if (m_opt_timestamp) no_opt = 1;
1670  
1671 -  for( cancel_idx = i = 0; i < MAX_UNCHOKE; i++ ){
1672 +// Find my 3 or 4 fastest peers.
1673 +// The MAX_UNCHOKE+1 (4th) slot is for the optimistic unchoke when it happens.
1674 +
1675 +  // Find a slot for the candidate--the slowest peer, or an available slot.
1676 +  for( cancel_idx = i = 0; i < MAX_UNCHOKE+no_opt; i++ ){
1677      if((btPeer*) 0 == peer_array[i] || PEER_IS_FAILED(peer_array[i]) ){        // ÓпÕλ
1678        cancel_idx = i; 
1679        break;
1680 @@ -537,7 +675,13 @@
1681           cancel_idx = i;
1682        }else{
1683         // compare download rate.
1684 -       if(peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL())
1685 +//     if(peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL())
1686 +       if( peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL()
1687 +          //if equal, reciprocate to the peer we've sent less to, proportionally
1688 +          ||(peer_array[cancel_idx]->RateDL() == peer_array[i]->RateDL()
1689 +            && peer_array[cancel_idx]->TotalUL()
1690 +                / (peer_array[cancel_idx]->TotalDL()+.001)
1691 +              < peer_array[i]->TotalUL() / (peer_array[i]->TotalDL()+.001)) )
1692           cancel_idx = i;
1693        }
1694      }
1695 @@ -551,7 +695,13 @@
1696        }else
1697         loster = peer;
1698      }else{
1699 -      if(peer->RateDL() > peer_array[cancel_idx]->RateDL()){
1700 +//    if(peer->RateDL() > peer_array[cancel_idx]->RateDL()){
1701 +      if( peer->RateDL() > peer_array[cancel_idx]->RateDL()
1702 +        // If equal, reciprocate to the peer we've sent less to, proportionally
1703 +        ||(peer_array[cancel_idx]->RateDL() == peer->RateDL()
1704 +          && peer_array[cancel_idx]->TotalUL()
1705 +                / (peer_array[cancel_idx]->TotalDL()+.001)
1706 +            > peer->TotalUL() / (peer->TotalDL()+.001)) ){
1707         loster = peer_array[cancel_idx];
1708         peer_array[cancel_idx] = peer;
1709        }else
1710 @@ -559,15 +709,56 @@
1711      }
1712  
1713      // opt unchoke
1714 -    if((btPeer*) 0 == peer_array[MAX_UNCHOKE] || PEER_IS_FAILED(peer_array[MAX_UNCHOKE]) )
1715 +    if (no_opt) {
1716 +      if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection();
1717 +    }
1718 +    else
1719 +    // The last slot is for the optimistic unchoke.
1720 +    // Bump the loser into it if he's been waiting longer than the occupant.
1721 +    if((btPeer*) 0 == peer_array[MAX_UNCHOKE] || PEER_IS_FAILED(peer_array[MAX_UNCHOKE]))
1722        peer_array[MAX_UNCHOKE] = loster;
1723 -    else{
1724 -      if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime())
1725 -       peer_array[MAX_UNCHOKE] = loster;
1726 -      else{
1727 -       if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection();
1728 +    else {
1729 +//    if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime()) {
1730 +      // if loser is empty and current is not, loser gets 75% chance.
1731 +      if( loster->bitfield.IsEmpty() && !peer_array[MAX_UNCHOKE]->bitfield.IsEmpty()
1732 +            && random()&03 ) {
1733 +        btPeer* tmp = peer_array[MAX_UNCHOKE];
1734 +        peer_array[MAX_UNCHOKE] = loster;
1735 +        loster = tmp;
1736 +      } else // if loser waited longer:
1737 +      if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime()) {
1738 +        // if current is empty and loser is not, loser gets 25% chance;
1739 +        //    else loser wins.
1740 +        // transformed to: if loser is empty or current isn't, or 25% chance,
1741 +        //    then loser wins.
1742 +        if( !peer_array[MAX_UNCHOKE]->bitfield.IsEmpty() || loster->bitfield.IsEmpty()
1743 +            || !random()&03 ) {
1744 +          btPeer* tmp = peer_array[MAX_UNCHOKE];
1745 +          peer_array[MAX_UNCHOKE] = loster;
1746 +          loster = tmp;
1747 +        }
1748        }
1749 +      if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection();
1750      }
1751    }else //else if((btPeer*) 0 != peer_array[cancel_idx].....
1752      peer_array[cancel_idx] = peer;
1753  }
1754 +
1755 +// When we change what we're going after, we need to evaluate & set our
1756 +// interest with each peer appropriately.
1757 +void PeerList::CheckInterest()
1758 +{
1759 +  PEERNODE *p = m_head;
1760 +  for( ; p; p = p->next) {
1761 +    // Don't shortcut by checking Is_Local_Interested(), as we need to let
1762 +    // SetLocal() reset the m_standby flag.
1763 +    if( p->peer->Need_Remote_Data() ) {
1764 +      if( p->peer->SetLocal(M_INTERESTED) < 0 )
1765 +        p->peer->CloseConnection();
1766 +    } else {
1767 +      if( p->peer->SetLocal(M_NOT_INTERESTED) < 0 )
1768 +        p->peer->CloseConnection();
1769 +    }
1770 +  }
1771 +}
1772 +
1773 diff -u ctorrent-1.3.4.orig/peerlist.h ctorrent-1.3.4/peerlist.h
1774 --- ctorrent-1.3.4.orig/peerlist.h      2004-09-09 01:10:51.000000000 +0200
1775 +++ ctorrent-1.3.4/peerlist.h   2005-08-11 23:45:29.434692920 +0200
1776 @@ -18,7 +18,8 @@
1777    SOCKET m_listen_sock;
1778    PEERNODE *m_head;
1779    size_t m_peers_count;
1780 -  time_t m_unchoke_check_timestamp, m_keepalive_check_timestamp, m_last_progress_timestamp;
1781 +  size_t m_seeds_count;
1782 +  time_t m_unchoke_check_timestamp, m_keepalive_check_timestamp, m_last_progress_timestamp, m_opt_timestamp;
1783  
1784    unsigned char m_live_idx:2;
1785    unsigned char m_reserved:6;
1786 @@ -50,9 +51,12 @@
1787    
1788    void Tell_World_I_Have(size_t idx);
1789    btPeer* Who_Can_Abandon(btPeer *proposer);
1790 +  btPeer* Who_Can_Duplicate(btPeer *proposer, size_t idx);
1791 +  void CancelSlice(size_t idx, size_t off, size_t len);
1792    void CheckBitField(BitField &bf);
1793    int AlreadyRequested(size_t idx);
1794    size_t Pieces_I_Can_Get();
1795 +  void CheckInterest();
1796  };
1797  
1798  extern PeerList WORLD;
1799 diff -u ctorrent-1.3.4.orig/rate.cpp ctorrent-1.3.4/rate.cpp
1800 --- ctorrent-1.3.4.orig/rate.cpp        2004-09-09 01:10:51.000000000 +0200
1801 +++ ctorrent-1.3.4/rate.cpp     2005-08-11 23:45:29.434692920 +0200
1802 @@ -1,5 +1,7 @@
1803  #include "rate.h"
1804  
1805 +#define RATE_INTERVAL 20
1806 +
1807  void Rate::StartTimer()
1808  {
1809    if( !m_last_timestamp ) time(&m_last_timestamp);
1810 @@ -7,7 +9,7 @@
1811  
1812  void Rate::StopTimer()
1813  {
1814 -  if( !m_last_timestamp ){
1815 +  if( m_last_timestamp ){
1816      m_total_timeused += (time((time_t*) 0) - m_last_timestamp);
1817      m_last_timestamp = 0;
1818    }
1819 @@ -15,7 +17,27 @@
1820  
1821  void Rate::CountAdd(size_t nbytes)
1822  {
1823 +  time_t now = time((time_t*) 0);
1824 +
1825    m_count_bytes += nbytes;
1826 +
1827 +  // save bandwidth history data
1828 +  for (int i=0; i <= n_samples; i++)
1829 +  {
1830 +    if (i < MAX_SAMPLES)
1831 +    {
1832 +      if (now == m_timestamp_sample[i]) {
1833 +        m_bytes_sample[i] += nbytes;
1834 +        break;
1835 +      }
1836 +      else if (now - RATE_INTERVAL > m_timestamp_sample[i]) {
1837 +        m_timestamp_sample[i] = now;
1838 +        m_bytes_sample[i] = nbytes;
1839 +        if (n_samples < MAX_SAMPLES) n_samples++;
1840 +        break;
1841 +      }
1842 +    }
1843 +  }
1844  }
1845  
1846  void Rate::operator=(const Rate &ra)
1847 @@ -26,17 +48,33 @@
1848  
1849  size_t Rate::RateMeasure() const
1850  {
1851 -  time_t timeused = m_total_timeused;
1852 -  if( m_last_timestamp ) timeused += (time((time_t*) 0) - m_last_timestamp);
1853 +  // calculate rate based on bandwidth history data
1854 +  time_t timestamp = time((time_t*) 0);
1855 +  u_int64_t countbytes = 0;
1856 +  time_t timeused = 0;
1857 +
1858 +  if( !m_last_timestamp ) return 0; // no current rate
1859 +
1860 +  timeused = (TimeUsed(&timestamp) < RATE_INTERVAL) ?
1861 +    TimeUsed(&timestamp) : RATE_INTERVAL;
1862    if( timeused < 1 ) timeused = 1;
1863 -  return (size_t)(m_count_bytes / timeused);
1864 +
1865 +  for (int i=0; i<n_samples; i++)
1866 +  {
1867 +    if (timestamp - m_timestamp_sample[i] <= timeused)
1868 +      countbytes += m_bytes_sample[i];
1869 +  }
1870 +  return (size_t)(countbytes / timeused);
1871  }
1872  
1873  size_t Rate::RateMeasure(const Rate &ra_to) const
1874  {
1875 +  int tmp;
1876    time_t timeused = time((time_t*) 0) - m_last_timestamp;
1877    if( timeused < 1 ) timeused = 1;
1878 -  return (size_t)((ra_to.m_count_bytes - m_count_bytes) / timeused);
1879 +  tmp = (ra_to.m_count_bytes - ra_to.m_recent_base)
1880 +      - (m_count_bytes - m_recent_base);
1881 +  return (size_t)( (tmp>0) ? (tmp/timeused) : 0 );
1882  }
1883  
1884  time_t Rate::TimeUsed(const time_t *pnow) const
1885 diff -u ctorrent-1.3.4.orig/rate.h ctorrent-1.3.4/rate.h
1886 --- ctorrent-1.3.4.orig/rate.h  2004-09-09 01:10:51.000000000 +0200
1887 +++ ctorrent-1.3.4/rate.h       2005-08-11 23:45:29.434692920 +0200
1888 @@ -5,14 +5,29 @@
1889  #include <time.h>
1890  #include "def.h"
1891  
1892 +#define MAX_SAMPLES 20
1893 +
1894  class Rate{
1895   private:
1896    time_t m_last_timestamp;
1897    time_t m_total_timeused;
1898    u_int64_t m_count_bytes;
1899 +  u_int64_t m_recent_base;
1900 +  
1901 +  // bandwidth history data
1902 +  size_t n_samples;
1903 +  time_t m_timestamp_sample[MAX_SAMPLES];
1904 +  u_int64_t m_bytes_sample[MAX_SAMPLES];
1905 +
1906   public:
1907 -  Rate(){ m_last_timestamp = m_total_timeused = (time_t)0; m_count_bytes = 0; }
1908 -  void Reset(){ m_last_timestamp = m_total_timeused = (time_t)0; m_count_bytes = 0;}
1909 +  Rate(){ m_last_timestamp = m_total_timeused = (time_t)0;
1910 +    m_recent_base = m_count_bytes = 0;
1911 +    n_samples=0; for(int i=0;i<MAX_SAMPLES;i++) m_timestamp_sample[i]=0;
1912 +  }
1913 +  void Reset(){ m_last_timestamp = m_total_timeused = (time_t)0;
1914 +    m_recent_base = m_count_bytes;
1915 +    n_samples = 0; for(int i=0;i<MAX_SAMPLES;i++) m_timestamp_sample[i]=0;
1916 +  }
1917    void StartTimer();
1918    void StopTimer();
1919    void CountAdd(size_t nbytes);
1920 diff -u ctorrent-1.3.4.orig/sigint.cpp ctorrent-1.3.4/sigint.cpp
1921 --- ctorrent-1.3.4.orig/sigint.cpp      2004-09-09 01:10:51.000000000 +0200
1922 +++ ctorrent-1.3.4/sigint.cpp   2005-08-11 23:45:29.434692920 +0200
1923 @@ -4,17 +4,27 @@
1924  #include <signal.h>
1925  
1926  #include "btcontent.h"
1927 +#include "tracker.h"
1928  #include "peerlist.h"
1929  #include "btconfig.h"
1930 +#include "sigint.h"
1931  
1932 -void sigint_catch(int sig_no)
1933 +void sig_catch(int sig_no)
1934  {
1935 -  if(SIGINT == sig_no){
1936 +  if(SIGINT == sig_no || SIGTERM == sig_no){
1937 +    Tracker.SetStoped();
1938 +    signal(sig_no,sig_catch2);
1939 +  }
1940 +}
1941 +
1942 +static void sig_catch2(int sig_no)
1943 +{
1944 +  if(SIGINT == sig_no || SIGTERM == sig_no){
1945      if( cfg_cache_size ) BTCONTENT.FlushCache();
1946      if( arg_bitfield_file ) BTCONTENT.pBF->WriteToFile(arg_bitfield_file);
1947      WORLD.CloseAll();
1948 -    signal(SIGINT,SIG_DFL);
1949 -    raise(SIGINT);
1950 +    signal(sig_no,SIG_DFL);
1951 +    raise(sig_no);
1952    }
1953  }
1954  
1955 diff -u ctorrent-1.3.4.orig/sigint.h ctorrent-1.3.4/sigint.h
1956 --- ctorrent-1.3.4.orig/sigint.h        2004-09-09 01:10:51.000000000 +0200
1957 +++ ctorrent-1.3.4/sigint.h     2005-08-11 23:45:29.435692768 +0200
1958 @@ -2,7 +2,8 @@
1959  #define SIGINT_H
1960  
1961  #ifndef WINDOWS
1962 -void sigint_catch(int sig_no);
1963 +void sig_catch(int sig_no);
1964 +static void sig_catch2(int sig_no);
1965  #endif
1966  
1967  #endif
1968 diff -u ctorrent-1.3.4.orig/tracker.cpp ctorrent-1.3.4/tracker.cpp
1969 --- ctorrent-1.3.4.orig/tracker.cpp     2004-09-09 01:10:51.000000000 +0200
1970 +++ ctorrent-1.3.4/tracker.cpp  2005-08-11 23:45:29.435692768 +0200
1971 @@ -31,11 +31,12 @@
1972    m_sock = INVALID_SOCKET;
1973    m_port = 80;
1974    m_status = T_FREE;
1975 -  m_f_started = m_f_stoped = m_f_pause = 0;
1976 +  m_f_started = m_f_stoped = m_f_pause = m_f_completed = 0;
1977    m_interval = 15;
1978  
1979    m_connect_refuse_click = 0;
1980    m_last_timestamp = (time_t) 0;
1981 +  m_prevpeers = 0;
1982  }
1983  
1984  btTracker::~btTracker()
1985 @@ -54,7 +55,8 @@
1986    
1987    m_reponse_buffer.Reset();
1988    time(&m_last_timestamp);
1989 -  m_status = T_FREE;
1990 +  if (m_f_stoped) m_status = T_FINISHED;
1991 +  else m_status = T_FREE;
1992  }
1993  
1994  int btTracker:: _IPsin(char *h, int p, struct sockaddr_in *psin)
1995 @@ -111,6 +113,13 @@
1996  
1997    if(m_interval != (time_t)i) m_interval = (time_t)i;
1998  
1999 +  if(decode_query(buf,bufsiz,"complete",(const char**) 0,&i,QUERY_INT)) {
2000 +    m_peers_count = i;
2001 +  }
2002 +  if(decode_query(buf,bufsiz,"incomplete",(const char**) 0,&i,QUERY_INT)) {
2003 +    m_peers_count += i;
2004 +  }
2005 +
2006    pos = decode_query(buf,bufsiz,"peers",(const char**) 0,(size_t *) 0,QUERY_POS);
2007  
2008    if( !pos ){
2009 @@ -161,7 +170,10 @@
2010      }
2011    }
2012    
2013 -  if( !cnt ) fprintf(stderr,"warn, peers list received from tracker is empty.\n");
2014 +  if(arg_verbose)
2015 +    fprintf(stderr, "\nnew peers=%u; next check in %u sec\n", cnt, m_interval);
2016 +// moved to CheckResponse--this function isn't called if no peer data.
2017 +//  if( !cnt ) fprintf(stderr,"warn, peers list received from tracker is empty.\n");
2018    return 0;
2019  }
2020  
2021 @@ -230,10 +242,14 @@
2022        return 0;
2023    }
2024  
2025 -  if ( !pdata ) return 0;
2026 +  if ( !pdata ){
2027 +    fprintf(stderr,"warn, peers list received from tracker is empty.\n");
2028 +    return 0;
2029 +  }
2030  
2031    if( !m_f_started ) m_f_started = 1;
2032    m_connect_refuse_click = 0;
2033 +  m_ok_click++;
2034  
2035    return _UpdatePeerList(pdata,dlen);
2036  }
2037 @@ -329,30 +345,34 @@
2038  //  fprintf(stdout,"Old Set Self:");
2039  //  fprintf(stdout,"%s\n", inet_ntoa(Self.m_sin.sin_addr));
2040  
2041 -  if( m_f_stoped )     /* stopped */
2042 -    event = str_event[1];
2043 -  else if( BTCONTENT.pBF->IsFull())    /* download complete */
2044 -    event = str_event[2];
2045 -  else if( m_f_started )       /* interval */
2046 -    event = (char*) 0;
2047 -  else
2048 +  if( m_f_stoped )
2049 +    event = str_event[1];      /* stopped */
2050 +  else if( m_f_started == 0 ) {
2051 +    if( BTCONTENT.pBF->IsFull() ) m_f_completed = 1;
2052      event = str_event[0];      /* started */
2053 +  } else if( BTCONTENT.pBF->IsFull() && !m_f_completed){
2054 +    event = str_event[2];      /* download complete */
2055 +    m_f_completed = 1;         /* only send download complete once */
2056 +  } else
2057 +    event = (char*) 0;  /* interval */
2058  
2059    if(event){
2060      if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT,
2061                              m_path,
2062 -                            (size_t)Self.TotalUL(),
2063 -                            (size_t)Self.TotalDL(),
2064 -                            (size_t)BTCONTENT.GetLeftBytes(),
2065 -                            event)){
2066 +                            Self.TotalUL(),
2067 +                            Self.TotalDL(),
2068 +                            BTCONTENT.GetLeftBytes(),
2069 +                            event,
2070 +                            cfg_max_peers)){
2071        return -1;
2072      }
2073    }else{
2074      if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P3_FMT,
2075                              m_path,
2076 -                            (size_t)Self.TotalUL(),
2077 -                            (size_t)Self.TotalDL(),
2078 -                            (size_t)BTCONTENT.GetLeftBytes()
2079 +                            Self.TotalUL(),
2080 +                            Self.TotalDL(),
2081 +                            BTCONTENT.GetLeftBytes(),
2082 +                            cfg_max_peers
2083                              )){
2084        return -1;
2085      }
2086 @@ -380,8 +400,12 @@
2087  {
2088    /* tracker communication */
2089    if( T_FREE == m_status ){
2090 -    if((*pnow - m_last_timestamp >= m_interval) &&
2091 -       (cfg_min_peers > WORLD.TotalPeers())){
2092 +//  if(*pnow - m_last_timestamp >= m_interval){
2093 +    if(*pnow - m_last_timestamp >= m_interval ||
2094 +        // Connect to tracker early if we run out of peers.
2095 +        (!WORLD.TotalPeers() && m_prevpeers &&
2096 +          *pnow - m_last_timestamp >= 15) ){
2097 +      m_prevpeers = WORLD.TotalPeers();
2098     
2099        if(Connect() < 0){ Reset(15); return -1; }
2100      
2101 @@ -396,7 +420,7 @@
2102      if( m_status == T_CONNECTING ){
2103        FD_SET(m_sock, rfdp);
2104        FD_SET(m_sock, wfdp);
2105 -    }else{
2106 +    }else if (INVALID_SOCKET != m_sock){
2107        FD_SET(m_sock, rfdp);
2108      }
2109    }
2110 @@ -425,7 +449,7 @@
2111        if( SendRequest() == 0 ) m_status = T_READY; 
2112        else { Reset(15); return -1; }
2113      }
2114 -  }else if(FD_ISSET(m_sock, rfdp) ){
2115 +  }else if(INVALID_SOCKET != m_sock && FD_ISSET(m_sock, rfdp) ){
2116      (*nfds)--;
2117      FD_CLR(m_sock,rfdp);
2118      CheckReponse();
2119 diff -u ctorrent-1.3.4.orig/tracker.h ctorrent-1.3.4/tracker.h
2120 --- ctorrent-1.3.4.orig/tracker.h       2004-09-09 01:10:51.000000000 +0200
2121 +++ ctorrent-1.3.4/tracker.h    2005-08-11 23:45:29.436692616 +0200
2122 @@ -21,6 +21,7 @@
2123  #define T_FREE                 0
2124  #define T_CONNECTING   1
2125  #define T_READY                2
2126 +#define T_FINISHED     3
2127  
2128  class btTracker
2129  {
2130 @@ -34,15 +35,20 @@
2131    unsigned char m_status:2;
2132    unsigned char m_f_started:1;
2133    unsigned char m_f_stoped:1;
2134 +  unsigned char m_f_completed:1;
2135  
2136    unsigned char m_f_pause:1;
2137 -  unsigned char m_f_reserved:3;
2138 +  unsigned char m_f_reserved:2;
2139  
2140  
2141    time_t m_interval;           // ÓëTrackerͨÐŵÄʱ¼ä¼ä¸ô
2142    time_t m_last_timestamp;     // ×îºóÒ»´Î³É¹¦ÓëTrackerͨÐŵÄʱ¼ä
2143    size_t m_connect_refuse_click;
2144  
2145 +  size_t m_ok_click;   // tracker ok response counter
2146 +  size_t m_peers_count;        // total number of peers
2147 +  size_t m_prevpeers;  // number of peers previously seen
2148 +
2149    SOCKET m_sock;
2150    BufIo m_reponse_buffer;
2151    
2152 @@ -66,6 +72,8 @@
2153    void SetPause() { m_f_pause = 1; }
2154    void ClearPause() { m_f_pause = 0; }
2155  
2156 +  void SetStoped() { Reset(15); m_f_stoped = 1; m_last_timestamp -= 15;}
2157 +
2158    int Connect();
2159    int SendRequest();
2160    int CheckReponse();
2161 @@ -73,6 +81,8 @@
2162    int SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds);
2163  
2164    size_t GetRefuseClick() const { return m_connect_refuse_click; }
2165 +  size_t GetOkClick() const { return m_ok_click; }
2166 +  size_t GetPeersCount() const { return m_peers_count; }
2167  };
2168  
2169  extern btTracker Tracker;