1 #include "btcontent.h"
2 
3 #ifdef WINDOWS
4 #include <direct.h>
5 #include <io.h>
6 #include <memory.h>
7 // include windows sha1 header here.
8 
9 #else
10 #include <unistd.h>
11 #include <sys/param.h>
12 
13 #if defined(USE_STANDALONE_SHA1)
14 #include "sha1.h"
15 #elif defined(HAVE_OPENSSL_SHA_H)
16 #include <openssl/sha.h>
17 #elif defined(HAVE_SSL_SHA_H)
18 #include <ssl/sha.h>
19 #elif defined(HAVE_SHA_H)
20 #include <sha.h>
21 #endif
22 
23 #endif
24 
25 #include <stdio.h>
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <ctype.h>
32 
33 #include "btconfig.h"
34 #include "bencode.h"
35 #include "peer.h"
36 #include "httpencode.h"
37 #include "tracker.h"
38 #include "peerlist.h"
39 #include "ctcs.h"
40 #include "console.h"
41 #include "bttime.h"
42 
43 #ifndef HAVE_RANDOM
44 #include "compat.h"
45 #endif
46 
47 #define meta_str(keylist,pstr,pint) decode_query(b,flen,(keylist),(pstr),(pint),(int64_t*) 0,QUERY_STR)
48 #define meta_int(keylist,pint) decode_query(b,flen,(keylist),(const char**) 0,(pint),(int64_t*) 0,QUERY_INT)
49 #define meta_pos(keylist) decode_query(b,flen,(keylist),(const char**) 0,(size_t*) 0,(int64_t*) 0,QUERY_POS)
50 
51 // Does "ca" overlap the data that lies from roff to rlen?
52 #define CACHE_FIT(ca,roff,rlen)	\
53 (max_uint64_t((ca)->bc_off,(roff)) <= \
54  min_uint64_t(((ca)->bc_off + (ca)->bc_len - 1),(roff + rlen - 1)))
55 
56 
57 btContent BTCONTENT;
58 
Sha1(char * ptr,size_t len,unsigned char * dm)59 static void Sha1(char *ptr,size_t len,unsigned char *dm)
60 {
61 #if defined(USE_STANDALONE_SHA1)
62   SHA1_CTX context;
63   SHA1Init(&context);
64   SHA1Update(&context,(unsigned char*)ptr,len);
65   SHA1Final(dm,&context);
66 #else
67 #ifdef WINDOWS
68   ;
69 #else
70   SHA_CTX context;
71   SHA1_Init(&context);
72   SHA1_Update(&context,(unsigned char*)ptr,len);
73   SHA1_Final(dm,&context);
74 #endif
75 #endif
76 }
77 
btContent()78 btContent::btContent()
79 {
80   m_announce = global_piece_buffer = (char*) 0;
81   global_buffer_size = 0;
82   memset(m_announcelist, 0, 9*sizeof(char *));
83   m_hash_table = (unsigned char *) 0;
84   m_create_date = m_seed_timestamp = (time_t) 0;
85   m_private = 0;
86   m_comment = m_created_by = (char *)0;
87 
88   pBF = (BitField*) 0;
89   pBMasterFilter = (BitField*) 0;
90   pBRefer = (BitField*) 0;
91   pBChecked = (BitField*) 0;
92   pBMultPeer = (BitField*) 0;
93   time(&m_start_timestamp);
94   m_cache_oldest = m_cache_newest = (BTCACHE *)0;
95   m_cache_size = m_cache_used = 0;
96   m_flush_failed = m_flush_tried = (time_t) 0;
97   m_check_piece = 0;
98   m_flushq = (BTFLUSH *)0;
99   m_filters = m_current_filter = (BFNODE *)0;
100   m_prevdlrate = 0;
101 }
102 
CreateMetainfoFile(const char * mifn)103 int btContent::CreateMetainfoFile(const char *mifn)
104 {
105   FILE *fp;
106   fp = fopen(mifn, "r");
107   if( fp ){
108     CONSOLE.Warning(1, "error, file \"%s\" already exists.", mifn);
109     return -1;
110   }else if( ENOENT != errno ){
111     CONSOLE.Warning(1, "error, couldn't create \"%s\".", mifn);
112     return -1;
113   }
114 
115   fp = fopen(mifn, "w");
116 
117   if( !fp ){
118     CONSOLE.Warning(1, "error, open \"%s\" failed:  %s", mifn, strerror(errno));
119     return -1;
120   }
121   if( bencode_begin_dict(fp) != 1 ) goto err;
122 
123   // Entries in dictionary must be sorted by key!
124 
125   // announce
126   if( bencode_str("announce", fp) != 1 ) goto err;
127   if( bencode_str(m_announce, fp) != 1 ) goto err;
128 
129   // comment
130   if( arg_comment ){
131     if( bencode_str("comment", fp) != 1 ) goto err;
132     if( bencode_str(arg_comment, fp) != 1 ) goto err;
133   }
134 
135   // created by
136   if( bencode_str("created by", fp) != 1 ) goto err;
137   if( bencode_str(cfg_user_agent, fp) != 1 ) goto err;
138 
139   // creation date
140   if( bencode_str("creation date", fp) != 1 ) goto err;
141   if( bencode_int(m_create_date, fp) != 1 ) goto err;
142 
143   // info dict
144   if( bencode_str("info", fp) != 1 ) goto err;
145   if( bencode_begin_dict(fp) != 1 ) goto err;
146 
147   { // Entries in dictionary must be sorted by key!
148     // files & name, or length & name
149     if( m_btfiles.FillMetaInfo(fp) != 1 ) goto err;
150 
151     // piece length
152     if( bencode_str("piece length", fp) != 1 ) goto err;
153     if( bencode_int(m_piece_length, fp) != 1 ) goto err;
154 
155     // pieces (hash table)
156     if( bencode_str("pieces", fp) != 1 ) goto err;
157     if( bencode_buf((const char*) m_hash_table, m_hashtable_length, fp) != 1 )
158       goto err;
159 
160     // private
161     if( arg_flg_private ){
162       if( bencode_str("private", fp) != 1 ) goto err;
163       if( bencode_int(1, fp) != 1 ) goto err;
164     }
165 
166     if( bencode_end_dict_list(fp) != 1 ) goto err;  // end info
167   }
168 
169   if( bencode_end_dict_list(fp) != 1 ) goto err;  // end torrent
170 
171   fclose(fp);
172   return 0;
173  err:
174   if( fp ) fclose(fp);
175   return -1;
176 }
177 
InitialFromFS(const char * pathname,char * ann_url,size_t piece_length)178 int btContent::InitialFromFS(const char *pathname, char *ann_url, size_t piece_length)
179 {
180   size_t n, percent;
181 
182   // piece length
183   m_piece_length = piece_length;
184   if( m_piece_length % 65536 ){
185     m_piece_length /= 65536;
186     m_piece_length *= 65536;
187   }
188 
189   // This is really just a sanity check on the piece length to create.
190   if( !m_piece_length || m_piece_length > 4096*1024 )
191     m_piece_length = 262144;
192 
193   m_announce = ann_url;
194   m_create_date = time((time_t*) 0);
195 
196   if(m_btfiles.BuildFromFS(pathname) < 0) return -1;
197 
198   global_piece_buffer = new char[m_piece_length];
199 #ifndef WINDOWS
200   if( !global_piece_buffer ) return -1;
201 #endif
202   global_buffer_size = m_piece_length;
203 
204   // n pieces
205   m_npieces = m_btfiles.GetTotalLength() / m_piece_length;
206   if( m_btfiles.GetTotalLength() % m_piece_length ) m_npieces++;
207 
208   // create hash table.
209   m_hashtable_length = m_npieces * 20;
210   m_hash_table = new unsigned char[m_hashtable_length];
211 #ifndef WINDOWS
212   if( !m_hash_table ) return -1;
213 #endif
214 
215   percent = m_npieces / 100;
216   if( !percent ) percent = 1;
217 
218   CONSOLE.Interact_n("");
219   for( n = 0; n < m_npieces; n++ ){
220     if( GetHashValue(n, m_hash_table + n * 20) < 0 ) return -1;
221     if( n % percent == 0 || n == m_npieces-1 ){
222       CONSOLE.InteractU("Create hash table: %d/%d", (int)n+1, (int)m_npieces);
223     }
224   }
225   return 0;
226 }
227 
PrintOut()228 int btContent::PrintOut()
229 {
230   CONSOLE.Print("META INFO");
231   CONSOLE.Print("Announce: %s", m_announce);
232   if( m_announcelist[0] ){
233     CONSOLE.Print("Alternates:");
234     for( int n=0; n < 9 && m_announcelist[n]; n++ )
235       CONSOLE.Print(" %d. %s", n+1, m_announcelist[n]);
236   }
237   if( m_create_date ){
238     char s[42];
239 #ifdef HAVE_CTIME_R_3
240     ctime_r(&m_create_date, s, sizeof(s));
241 #else
242     ctime_r(&m_create_date, s);
243 #endif
244     if( s[strlen(s)-1] == '\n' ) s[strlen(s)-1] = '\0';
245     CONSOLE.Print("Created On: %s", s);
246   }
247   CONSOLE.Print("Piece length: %lu", (unsigned long)m_piece_length);
248   if( m_private ) CONSOLE.Print("Private: %s", m_private ? "Yes" : "No");
249   if( m_comment ){
250     char *s = new char[strlen(m_comment)+1];
251     if(s){
252       strcpy(s, m_comment);
253       for(char *t=s; *t; t++)
254         if( !isprint(*t) && !strchr("\t\r\n", *t) ) *t = '?';
255       CONSOLE.Print("Comment: %s", s);
256       delete []s;
257     }
258   }
259   if( m_created_by ) CONSOLE.Print("Created with: %s", m_created_by);
260   m_btfiles.PrintOut();
261   return 0;
262 }
263 
PrintFiles()264 int btContent::PrintFiles()
265 {
266   m_btfiles.PrintOut();
267   return 0;
268 }
269 
InitialFromMI(const char * metainfo_fname,const char * saveas)270 int btContent::InitialFromMI(const char *metainfo_fname,const char *saveas)
271 {
272 #define ERR_RETURN()	{if(b) delete []b; return -1;}
273   unsigned char *ptr = m_shake_buffer;
274   char *b;
275   const char *s;
276   size_t flen, q, r;
277   int tmp;
278 
279   m_cache_hit = m_cache_miss = m_cache_pre = 0;
280   time(&m_cache_eval_time);
281 
282   b = _file2mem(metainfo_fname,&flen);
283   if ( !b ) return -1;
284 
285   // announce
286   if( meta_str("announce",&s,&r) ) {
287   if( r > MAXPATHLEN ) ERR_RETURN();
288   m_announce = new char [r + 1];
289   memcpy(m_announce, s, r);
290   m_announce[r] = '\0';
291   }
292 
293   // announce-list
294   if( r = meta_pos("announce-list") ){
295     const char *sptr;
296     size_t slen, n=0;
297     if( q = decode_list(b+r, flen-r, (char *)0) ){
298       int alend = r + q;
299       r++;  // 'l'
300       for( ; r < alend && *(b+r) != 'e' && n < 9; ){  // each list
301         if( !(q = decode_list(b+r, alend-r, (char *)0)) ) break;
302         r++;  // 'l'
303         for( ; r < alend && n < 9; ){  // each value
304           if( !(q = buf_str(b+r, alend-r, &sptr, &slen)) )
305             break;  // next list
306           r += q;
307           if( !m_announce || strncasecmp(m_announce, sptr, slen) ){
308             m_announcelist[n] = new char[slen+1];
309             memcpy(m_announcelist[n], sptr, slen);
310             (m_announcelist[n])[slen] = '\0';
311             n++;
312           }
313         }
314         r++;  // 'e'
315       }
316     }
317   }
318 
319   if( meta_int("creation date", &r) ) m_create_date = (time_t) r;
320   if( meta_str("comment", &s, &r) && r ){
321     if( m_comment = new char[r + 1] ){
322       memcpy(m_comment, s, r);
323       m_comment[r] = '\0';
324     }
325   }
326   if( meta_str("created by", &s, &r) && r ){
327     if( m_created_by = new char[r + 1] ){
328       memcpy(m_created_by, s, r);
329       m_created_by[r] = '\0';
330     }
331   }
332 
333   // infohash
334   if( !(r = meta_pos("info")) ) ERR_RETURN();
335   if( !(q = decode_dict(b + r, flen - r, (char *) 0)) ) ERR_RETURN();
336   Sha1(b + r, q, m_shake_buffer + 28);
337 
338   // private flag
339   if( meta_int("info|private", &r) ) m_private = r;
340 
341   // hash table
342   if( !meta_str("info|pieces",&s,&m_hashtable_length) ||
343       m_hashtable_length % 20 != 0 ) ERR_RETURN();
344 
345   if( !arg_flg_exam_only ){
346     m_hash_table = new unsigned char[m_hashtable_length];
347 #ifndef WINDOWS
348     if( !m_hash_table ) ERR_RETURN();
349 #endif
350     memcpy(m_hash_table, s, m_hashtable_length);
351   }
352 
353   if( !meta_int("info|piece length",&m_piece_length) ) ERR_RETURN();
354   m_npieces = m_hashtable_length / 20;
355 
356   if( m_piece_length < cfg_req_slice_size )
357     cfg_req_slice_size = m_piece_length;
358 
359   cfg_req_queue_length = (m_piece_length / cfg_req_slice_size) * 2 - 1;
360 
361   if( m_btfiles.BuildFromMI(b, flen, saveas) < 0 ) ERR_RETURN();
362 
363   delete []b;
364   b = (char *)0;
365 
366   if( arg_flg_exam_only ){
367     PrintOut();
368     return 0;
369   }else{
370     arg_flg_exam_only = 1;
371     PrintOut();
372     arg_flg_exam_only = 0;
373   }
374 
375   if( (tmp = m_btfiles.CreateFiles()) < 0 ) ERR_RETURN();
376   r = tmp;
377 
378   if( !arg_flg_exam_only ){
379     global_piece_buffer = new char[DEFAULT_SLICE_SIZE];
380 #ifndef WINDOWS
381     if( !global_piece_buffer ) ERR_RETURN();
382 #endif
383     global_buffer_size = DEFAULT_SLICE_SIZE;
384 
385     pBF = new BitField(m_npieces);
386 #ifndef WINDOWS
387     if( !pBF ) ERR_RETURN();
388 #endif
389 
390     pBRefer = new BitField(m_npieces);
391 #ifndef WINDOWS
392     if( !pBRefer ) ERR_RETURN();
393 #endif
394 
395     pBChecked = new BitField(m_npieces);
396 #ifndef WINDOWS
397     if( !pBChecked ) ERR_RETURN();
398 #endif
399 
400     pBMultPeer = new BitField(m_npieces);
401 #ifndef WINDOWS
402     if( !pBMultPeer ) ERR_RETURN();
403 #endif
404 
405     //create the file filter
406     pBMasterFilter = new BitField(m_npieces);
407 #ifndef WINDOWS
408      if( !pBMasterFilter ) ERR_RETURN();
409 #endif
410     if( arg_file_to_download ) SetFilter();
411   }
412 
413   m_left_bytes = m_btfiles.GetTotalLength() / m_piece_length;
414   if( m_btfiles.GetTotalLength() % m_piece_length ) m_left_bytes++;
415   if( m_left_bytes != m_npieces ) ERR_RETURN();
416 
417   m_left_bytes = m_btfiles.GetTotalLength();
418 
419   if( arg_flg_check_only ){
420     struct stat sb;
421     if( stat(arg_bitfield_file, &sb) == 0 ){
422       if( remove(arg_bitfield_file) < 0 ){
423         CONSOLE.Warning(2, "warn, couldn't delete bit field file \"%s\":  %s",
424           arg_bitfield_file, strerror(errno));
425       }
426     }
427     if( r ){
428       if( CheckExist() < 0 ) ERR_RETURN();
429       if( !pBF->IsEmpty() )
430         m_btfiles.PrintOut(); // show file completion
431     }
432     CONSOLE.Print("Already/Total: %d/%d (%d%%)", (int)(pBF->Count()),
433       (int)m_npieces, (int)(100 * pBF->Count() / m_npieces));
434     if( !arg_flg_force_seed_mode ){
435       SaveBitfield();
436       if( arg_completion_exit ) CompletionCommand();
437       exit(0);
438     }
439   }else if( r ){  // files exist already
440     if( pBRefer->SetReferFile(arg_bitfield_file) < 0 ){
441       if( !arg_flg_force_seed_mode ){
442         CONSOLE.Warning(2,
443           "warn, couldn't set bit field refer file \"%s\":  %s",
444           arg_bitfield_file, strerror(errno));
445         CONSOLE.Warning(2, "This is normal if you are seeding.");
446       }
447       pBRefer->SetAll();  // need to check all pieces
448     }else{
449       CONSOLE.Interact("Found bit field file; %s previous state.",
450         arg_flg_force_seed_mode ? "resuming download from" : "verifying");
451       if( unlink(arg_bitfield_file) < 0 ){
452         CONSOLE.Warning(2, "warn, couldn't delete bit field file \"%s\":  %s",
453           arg_bitfield_file, strerror(errno));
454       }
455       // Mark missing pieces as "checked" (eligible for download).
456       *pBChecked = *pBRefer;
457       pBChecked->Invert();
458     }
459   }
460   if( !r ){  // don't hash-check if the files were just created
461     m_check_piece = m_npieces;
462     pBChecked->SetAll();
463     if( arg_flg_force_seed_mode ){
464       CONSOLE.Warning(2, "Files were not present; overriding force mode!");
465     }
466   }else if( arg_flg_force_seed_mode && !arg_flg_check_only ){
467     size_t idx = 0;
468     *pBF = *pBRefer;
469     if( pBF->IsFull() ){
470       CONSOLE.Interact("Skipping hash checks and forcing seed mode.");
471       CONSOLE.Interact(
472        "-----> STOP NOW if you have not downloaded the whole torrent! <-----");
473       m_left_bytes = 0;
474     }else for( ; idx < m_npieces; idx++ ){
475       if( pBF->IsSet(idx) )
476         m_left_bytes -= GetPieceLength(idx);
477     }
478     m_check_piece = m_npieces;
479     pBChecked->SetAll();
480   }
481   delete pBRefer;
482 
483   m_cache = new BTCACHE *[m_npieces];
484   if( !m_cache ){
485     CONSOLE.Warning(1, "error, allocate cache index failed");
486     ERR_RETURN();
487   }
488   memset(m_cache, 0, m_npieces * sizeof(BTCACHE*));
489   CacheConfigure();
490 
491   *ptr = (unsigned char) 19; ptr++; // protocol string length
492   memcpy(ptr,"BitTorrent protocol",19); ptr += 19; //  protocol string
493   memset(ptr,0,8);		// reserved set zero.
494 
495   {				// peer id
496         char *sptr = arg_user_agent;
497         char *dptr = (char *)m_shake_buffer + 48;
498         char *eptr = dptr + PEER_ID_LEN;
499         while (*sptr) *dptr++ = *sptr++;
500         while (dptr < eptr) *dptr++ = (unsigned char)random();
501   }
502 
503   if( arg_announce ){
504     int n;
505     delete []m_announce;
506     if( (n = atoi(arg_announce)) && n <= 9 && m_announcelist[n-1] )
507       m_announce = m_announcelist[n-1];
508     else m_announce = arg_announce;
509     CONSOLE.Print("Using announce URL:  %s", m_announce);
510   }
511 
512   return 0;
513 }
514 
~btContent()515 btContent::~btContent()
516 {
517   if(m_hash_table) delete []m_hash_table;
518   if(m_announce) delete []m_announce;
519   if(global_piece_buffer) delete []global_piece_buffer;
520   if(pBF) delete pBF;
521 }
522 
_Set_InfoHash(unsigned char buf[20])523 void btContent::_Set_InfoHash(unsigned char buf[20])
524 {
525   memcpy(m_shake_buffer + 28, buf, 20);
526 }
527 
528 // returns <0 if error; if using cache: 1 if read from disk, 0 otherwise
ReadSlice(char * buf,size_t idx,size_t off,size_t len)529 ssize_t btContent::ReadSlice(char *buf,size_t idx,size_t off,size_t len)
530 {
531   ssize_t retval = 0;
532   uint64_t offset = (uint64_t)idx * (uint64_t)m_piece_length + off;
533 
534   if( !m_cache_size ) return buf ? m_btfiles.IO(buf, offset, len, 0) : 0;
535   else{
536     size_t len2;
537     BTCACHE *p;
538 
539     p = m_cache[idx];
540     while( len && p ){
541       while( p && offset + len > p->bc_off && !CACHE_FIT(p, offset, len) ){
542         p = p->bc_next;
543       }
544       if( !p || !CACHE_FIT(p, offset, len) ) break;
545       if( offset < p->bc_off ){
546         len2 = p->bc_off - offset;
547         if( CacheIO(buf, offset, len2, 0) < 0 ) return -1;
548         retval = 1;
549         if(buf) m_cache_miss += len2 / DEFAULT_SLICE_SIZE +
550                                 ((len2 % DEFAULT_SLICE_SIZE) ? 1 : 0);
551         else m_cache_pre += len2 / DEFAULT_SLICE_SIZE +
552                             ((len2 % DEFAULT_SLICE_SIZE) ? 1 : 0);
553         p = m_cache[idx];  // p may not be valid after CacheIO
554       }else{
555         char *src;
556         if( offset > p->bc_off ){
557           len2 = p->bc_off + p->bc_len - offset;
558           if( len2 > len ) len2 = len;
559           src = p->bc_buf + offset - p->bc_off;
560         }else{
561           len2 = (len > p->bc_len) ? p->bc_len : len;
562           src = p->bc_buf;
563         }
564         if( buf ){
565           memcpy(buf, src, len2);
566           m_cache_hit += len2 / DEFAULT_SLICE_SIZE +
567                          ((len2 % DEFAULT_SLICE_SIZE) ? 1 : 0);
568         }else{  // prefetch only, update the age
569           if( m_cache_newest != p ){
570             if( m_cache_oldest == p ) m_cache_oldest = p->age_next;
571             else p->age_prev->age_next = p->age_next;
572             p->age_next->age_prev = p->age_prev;
573             m_cache_newest->age_next = p;
574             p->age_next = (BTCACHE *)0;
575             p->age_prev = m_cache_newest;
576             m_cache_newest = p;
577           }
578         }
579         p = p->bc_next;
580       }
581 
582       if( buf ) buf += len2;
583       offset += len2;
584       len -= len2;
585     }// end for;
586 
587     if( len ){
588       if(buf) m_cache_miss += len / DEFAULT_SLICE_SIZE +
589                               ((len % DEFAULT_SLICE_SIZE) ? 1 : 0);
590       else m_cache_pre += len / DEFAULT_SLICE_SIZE +
591                           ((len % DEFAULT_SLICE_SIZE) ? 1 : 0);
592       retval = CacheIO(buf, offset, len, 0);
593       return (retval < 0) ? retval : 1;
594     }
595   }
596   return retval;
597 }
598 
CacheClean(size_t need)599 void btContent::CacheClean(size_t need)
600 {
601   BTCACHE *p, *pnext;
602   int f_flush = 0;
603 
604   if( m_flush_failed ) FlushCache();  // try again
605 
606   again:
607   for( p=m_cache_oldest; p && m_cache_size < m_cache_used + need; p=pnext ){
608     pnext = p->age_next;
609     if( f_flush ){
610       if(arg_verbose)
611         CONSOLE.Debug("Flushing %d/%d/%d", (int)(p->bc_off / m_piece_length),
612           (int)(p->bc_off % m_piece_length), (int)(p->bc_len));
613       FlushEntry(p);
614     }
615     if( !p->bc_f_flush ){
616       if(arg_verbose)
617         CONSOLE.Debug("Expiring %d/%d/%d", (int)(p->bc_off / m_piece_length),
618           (int)(p->bc_off % m_piece_length), (int)(p->bc_len));
619 
620       if( m_cache_oldest == p ) m_cache_oldest = p->age_next;
621       else p->age_prev->age_next = p->age_next;
622       if( m_cache_newest == p ) m_cache_newest = p->age_prev;
623       else p->age_next->age_prev = p->age_prev;
624 
625       if( p->bc_prev ) p->bc_prev->bc_next = p->bc_next;
626       else m_cache[p->bc_off / m_piece_length] = p->bc_next;
627       if( p->bc_next ) p->bc_next->bc_prev = p->bc_prev;
628 
629       m_cache_used -= p->bc_len;
630       delete []p->bc_buf;
631       delete p;
632     }
633   }
634   if( m_cache_size < m_cache_used + need ){  // still not enough
635     if( m_cache_size < cfg_cache_size*1024*1024 ){  // can alloc more
636       m_cache_size = (m_cache_used + need > cfg_cache_size*1024*1024) ?
637         cfg_cache_size*1024*1024 : (m_cache_used + need);
638     }
639     if( m_cache_size < m_cache_used + need && m_cache_used && !f_flush ){
640       if(arg_verbose) CONSOLE.Debug("CacheClean flushing to obtain space");
641       f_flush = 1;
642       goto again;
643     }  // else we tried...
644   }
645 }
646 
647 // Don't call this function if cfg_cache_size==0 !
CacheEval()648 void btContent::CacheEval()
649 {
650   BTCACHE *p = m_cache_oldest;
651   size_t interval;
652   size_t unflushed = 0, dlnext, upadd = 0, upmax = 0, upmin = 0, total;
653 
654   size_t rateup = Self.RateUL();
655   size_t ratedn = Self.RateDL();
656   size_t unchoked = WORLD.GetUnchoked();
657 
658   // Time until next cache size eval: unchoke interval or time to dl a piece.
659   if( ratedn ){
660     interval = m_piece_length / ratedn;
661     if( interval > WORLD.GetUnchokeInterval() )
662       interval = WORLD.GetUnchokeInterval();
663     else if( 0==interval ) interval = 1;
664   }else interval = WORLD.GetUnchokeInterval();
665 
666   // Download: total unflushed data + data to dl before next eval
667   // Hold the first piece a bit to let uploading begin.
668   if( pBF->IsFull() ) dlnext = 0;
669   else{
670     if( pBF->Count() < 2 ) unflushed = m_cache_used;
671     else for( ; p; p = p->age_next )
672       if( p->bc_f_flush ) unflushed += p->bc_len;
673     // Make sure we can read back and check a completed piece.
674     // But free some cache if download has completely stalled.
675     dlnext = ratedn ? (ratedn * interval + m_piece_length) : 0;
676   }
677 
678   // Upload: need enough to hold read/dl'd data until it can be sent
679   upmin = DEFAULT_SLICE_SIZE * unchoked;
680   upmax = cfg_cache_size*1024*1024;
681   if( pBF->IsFull() ){
682     // Seed mode.  All cache data is prefetched, and we don't normally need to
683     // keep prefetched data longer than 2.5 unchoke intervals.
684     if( rateup && unchoked ){
685       // A very slow peer can't possibly benefit from cache--don't grow for it.
686       size_t slowest = (size_t)( 1 + DEFAULT_SLICE_SIZE /
687                                  ((double)cfg_cache_size*1024*1024 / rateup) );
688       // Lead cache: data we need to cache to keep the slowest up's data cached
689       // Add a slice per up for timing uncertainty
690       if( slowest = WORLD.GetSlowestUp(slowest) )
691         upadd = DEFAULT_SLICE_SIZE * ( rateup / slowest + unchoked-1 );
692       else upadd = DEFAULT_SLICE_SIZE * unchoked;
693 
694       upmin = DEFAULT_SLICE_SIZE * unchoked;
695       upmax = (size_t)( DEFAULT_SLICE_SIZE * (unchoked-1) +
696         rateup * 2.5 * WORLD.GetUnchokeInterval() );
697     }
698   }else{
699     if( rateup > ratedn ){
700       size_t slowest = (size_t)( 1 +
701         cfg_req_slice_size * ((double)ratedn / cfg_cache_size*1024*1024) +
702         DEFAULT_SLICE_SIZE * ((double)rateup / cfg_cache_size*1024*1024) );
703       if( slowest = WORLD.GetSlowestUp(slowest) )
704         // lead cache is how much we'll use while uploading a slice to slowest
705         // (default_slice_size / slowest) * (ratedn + rateup)
706         upadd = (size_t)( ((double)DEFAULT_SLICE_SIZE / slowest) *
707                           (ratedn + rateup + 1) );
708       else upadd = m_piece_length * unchoked;
709     }
710     else if( rateup ){
711       // same as m_piece_length / (cfg_cache_size*1024*1024 / (double)ratedn)
712       size_t slowest = (size_t)( 1 +
713         ratedn * ((double)m_piece_length / (cfg_cache_size*1024*1024)) );
714       if( slowest = WORLD.GetSlowestUp(slowest) ){
715         // m_piece_length / (double)slowest * ratedn
716         // optimize, then round up a piece and add a piece
717         upadd = m_piece_length * (ratedn / slowest + 2);
718       }else{  // gimme 10 seconds worth (unchoke interval)
719         // Can't keep pieces in cache long enough to upload them.
720         // Rely on prefetching slices from disk instead.
721         upadd = ratedn * WORLD.GetUnchokeInterval() +
722                 DEFAULT_SLICE_SIZE * unchoked;
723       }
724     }
725   }
726 
727   if( upadd < upmin ) upadd = upmin;
728 
729   // Add a slice to round up
730   total = unflushed + dlnext + upadd + cfg_req_slice_size;
731 
732   // Limit to max configured size
733   if( total > cfg_cache_size*1024*1024 ) total = cfg_cache_size*1024*1024;
734 
735   // Don't decrease cache size if flush failed.
736   if( !m_flush_failed || total > m_cache_size ) m_cache_size = total;
737 
738   if(arg_verbose)
739     CONSOLE.Debug("DL need: %dK  UL need: %dK  Cache: %dK  Used: %dK",
740     (int)((unflushed+dlnext)/1024), (int)(upadd/1024),
741     (int)(m_cache_size/1024), (int)(m_cache_used/1024));
742   m_cache_eval_time = now + interval;
743 }
744 
CacheConfigure()745 void btContent::CacheConfigure()
746 {
747   if( cfg_cache_size ){
748     if( cfg_cache_size > GetTotalFilesLength()/1024/1024 )
749       cfg_cache_size = (GetTotalFilesLength()+1024*1024-1)/1024/1024;
750     CacheEval();
751   }else m_cache_size = 0;
752 
753   if( m_cache_size < m_cache_used && !m_flush_failed ) CacheClean(0);
754 }
755 
NeedFlush() const756 int btContent::NeedFlush() const
757 {
758   if( m_flush_failed ){
759     if( now > m_flush_tried ) return 1;
760   }else
761     return (m_flushq ||
762             (m_cache_oldest && m_cache_oldest->bc_f_flush &&
763              m_cache_used >= cfg_cache_size*1024*1024-cfg_req_slice_size+1)) ?
764            1 : 0;
765 }
766 
FlushCache()767 void btContent::FlushCache()
768 {
769   if(arg_verbose) CONSOLE.Debug("Flushing all cache");
770   for( int i=0; i < m_npieces; i++ ){
771     if( m_cache[i] ) FlushPiece(i);
772     if( m_flush_failed ) break;
773   }
774 }
775 
FlushPiece(size_t idx)776 void btContent::FlushPiece(size_t idx)
777 {
778   BTCACHE *p;
779 
780   p = m_cache[idx];
781 
782   for( ; p; p = p->bc_next ){
783     // Update the age if piece is complete, as this should mean we've just
784     // completed the piece and made it available.
785     if( pBF->IsSet(idx) && m_cache_newest != p ){
786       if( m_cache_oldest == p ) m_cache_oldest = p->age_next;
787       else p->age_prev->age_next = p->age_next;
788       p->age_next->age_prev = p->age_prev;
789       m_cache_newest->age_next = p;
790       p->age_next = (BTCACHE *)0;
791       p->age_prev = m_cache_newest;
792       m_cache_newest = p;
793     }
794     if( p->bc_f_flush ) FlushEntry(p);
795   }
796 }
797 
FlushEntry(BTCACHE * p)798 void btContent::FlushEntry(BTCACHE *p)
799 {
800   if( p->bc_f_flush ){
801     if( m_btfiles.IO(p->bc_buf, p->bc_off, p->bc_len, 1) < 0 ){
802       m_flush_tried = now;
803       if( now >= m_flush_failed + 300 ){
804         if( !m_flush_failed )
805           m_cache_size += cfg_req_slice_size * WORLD.GetDownloads() * 2;
806         CONSOLE.Warning(1, "warn, write file failed while flushing cache.");
807         CONSOLE.Warning(1,
808           "You need to have at least %llu bytes free on this filesystem!",
809           (unsigned long long)(m_left_bytes + m_cache_used));
810         CONSOLE.Warning(1,
811           "This could also be caused by a conflict or disk error.");
812         if( !IsFull() ||
813             (!m_flush_failed && m_cache_size > cfg_cache_size*1024*1024) ){
814           CONSOLE.Warning(1, "Temporarily %s%s...",
815             IsFull() ? "" : "suspending download",
816             (!m_flush_failed && m_cache_size > cfg_cache_size*1024*1024) ?
817               (IsFull() ? " and increasing cache" : "increasing cache") : "");
818         }
819         m_flush_failed = now;
820         WORLD.StopDownload();
821       }
822     }else{
823       p->bc_f_flush = 0;
824       if( Seeding() ){
825         for( size_t n=1; n <= m_btfiles.GetNFiles(); n++ )
826           m_btfiles.CloseFile(n);  // files will reopen read-only
827       }
828       if(m_flush_failed){
829         m_flush_failed = 0;
830         CONSOLE.Warning(3, "Flushing cache succeeded%s.",
831           Seeding() ? "" : "; resuming download");
832         CacheConfigure();
833         WORLD.CheckInterest();
834       }
835     }
836   }
837 }
838 
Uncache(size_t idx)839 void btContent::Uncache(size_t idx)
840 {
841   BTCACHE *p, *pnext;
842 
843   p = m_cache[idx];
844   for( ; p; p = pnext ){
845     pnext = p->bc_next;
846      if( m_cache_oldest == p ) m_cache_oldest = p->age_next;
847      else p->age_prev->age_next = p->age_next;
848      if( m_cache_newest == p ) m_cache_newest = p->age_prev;
849      else p->age_next->age_prev = p->age_prev;
850 
851      m_cache_used -= p->bc_len;
852      delete []p->bc_buf;
853      delete p;
854   }
855   m_cache[idx] = (BTCACHE *)0;
856 }
857 
FlushQueue()858 void btContent::FlushQueue()
859 {
860   if( m_flushq ){
861     if(arg_verbose)
862       CONSOLE.Debug("Writing piece #%d to disk", (int)(m_flushq->idx));
863     FlushPiece(m_flushq->idx);
864     if( !m_flush_failed ){
865       BTFLUSH *goner = m_flushq;
866       m_flushq = m_flushq->next;
867       delete goner;
868     }
869   }else{
870     if(arg_verbose) CONSOLE.Debug("Flushing %d/%d/%d",
871       (int)(m_cache_oldest->bc_off / m_piece_length),
872       (int)(m_cache_oldest->bc_off % m_piece_length),
873       (int)(m_cache_oldest->bc_len));
874     FlushEntry(m_cache_oldest);
875   }
876 }
877 
878 /* Prepare for prefetching a whole piece.
879    return -1:  do not prefetch (problem or not needed)
880    return  0:  already ready (no time used)
881    return  1:  data was flushed (time used)
882 */
CachePrep(size_t idx)883 int btContent::CachePrep(size_t idx)
884 {
885   int retval = 0;
886   BTCACHE *p, *pnext;
887   size_t need = GetPieceLength(idx);
888 
889   if( m_cache_size < m_cache_used + need ){
890     for( p=m_cache[idx]; p; p=p->bc_next ) need -= p->bc_len;
891     if( 0==need ) retval = -1;  // don't need to prefetch
892     for( p=m_cache_oldest; p && m_cache_size < m_cache_used + need; p=pnext ){
893       pnext = p->age_next;
894       if( p->bc_off / m_piece_length == idx ) continue;
895       if( p->bc_f_flush ){
896         if(arg_verbose)
897           CONSOLE.Debug("Flushing %d/%d/%d", (int)(p->bc_off / m_piece_length),
898             (int)(p->bc_off % m_piece_length), (int)(p->bc_len));
899         FlushEntry(p);
900         retval = 1;
901       }
902       if(arg_verbose)
903         CONSOLE.Debug("Expiring %d/%d/%d", (int)(p->bc_off / m_piece_length),
904           (int)(p->bc_off % m_piece_length), (int)(p->bc_len));
905       if( m_cache_oldest == p ) m_cache_oldest = p->age_next;
906       else p->age_prev->age_next = p->age_next;
907       if( m_cache_newest == p ) m_cache_newest = p->age_prev;
908       else p->age_next->age_prev = p->age_prev;
909 
910       if( p->bc_prev ) p->bc_prev->bc_next = p->bc_next;
911       else m_cache[p->bc_off / m_piece_length] = p->bc_next;
912       if( p->bc_next ) p->bc_next->bc_prev = p->bc_prev;
913 
914       m_cache_used -= p->bc_len;
915       delete []p->bc_buf;
916       delete p;
917     }
918   }
919   return retval;
920 }
921 
WriteSlice(char * buf,size_t idx,size_t off,size_t len)922 ssize_t btContent::WriteSlice(char *buf,size_t idx,size_t off,size_t len)
923 {
924   uint64_t offset = (uint64_t)idx * (uint64_t)m_piece_length + off;
925 
926   //CONSOLE.Debug("Offset-write: %llu - Piece:%lu",
927   //  (unsigned long long)offset, (unsigned long)idx);
928 
929   if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 1);
930   else{
931     size_t len2;
932     BTCACHE *p;
933 
934     p = m_cache[idx];
935     while( len && p ){
936       while( p && offset + len > p->bc_off && !CACHE_FIT(p, offset, len) ){
937         p = p->bc_next;
938       }
939       if( !p || !CACHE_FIT(p, offset, len) ) break;
940       if( offset < p->bc_off ){
941         len2 = p->bc_off - offset;
942         if( CacheIO(buf, offset, len2, 1) < 0 ) return -1;
943         p = m_cache[idx];  // p may not be valid after CacheIO
944       }else{
945         if( offset > p->bc_off ){
946           len2 = p->bc_off + p->bc_len - offset;
947           if( len2 > len ) len2 = len;
948           memcpy(p->bc_buf + (offset - p->bc_off), buf, len2);
949         }else{
950           len2 = (len > p->bc_len) ? p->bc_len : len;
951           memcpy(p->bc_buf, buf, len2);
952         }
953         p->bc_f_flush = 1;
954         // re-received this data, make it new again
955         if( m_cache_newest != p ){
956           if( m_cache_oldest == p ) m_cache_oldest = p->age_next;
957           else p->age_prev->age_next = p->age_next;
958           p->age_next->age_prev = p->age_prev;
959           m_cache_newest->age_next = p;
960           p->age_next = (BTCACHE *)0;
961           p->age_prev = m_cache_newest;
962           m_cache_newest = p;
963         }
964         p = p->bc_next;
965       }
966 
967       buf += len2;
968       offset += len2;
969       len -= len2;
970     }// end for;
971 
972     if( len ) return CacheIO(buf, offset, len, 1);
973   }
974   return 0;
975 }
976 
CacheIO(char * buf,uint64_t off,size_t len,int method)977 ssize_t btContent::CacheIO(char *buf, uint64_t off, size_t len, int method)
978 {
979   BTCACHE *p;
980   BTCACHE *pp = (BTCACHE*) 0;
981   BTCACHE *pnew = (BTCACHE*) 0;
982 
983   if( len >= cfg_cache_size*1024*768 ){  // 75% of cache limit
984     if( buf ) return m_btfiles.IO(buf, off, len, method);
985     else return 0;
986   }
987 
988   if(arg_verbose && 0==method)
989     CONSOLE.Debug("Read to %s %d/%d/%d", buf?"buffer":"cache",
990       (int)(off / m_piece_length), (int)(off % m_piece_length), (int)len);
991 
992   if( m_cache_size < m_cache_used + len ) CacheClean(len);
993   // Note, there is no failure code from CacheClean().  If nothing can be done
994   // to increase the cache size, we allocate what we need anyway.
995 
996   if( 0==method && buf && m_btfiles.IO(buf, off, len, method) < 0 ) return -1;
997 
998   pnew = new BTCACHE;
999 #ifndef WINDOWS
1000   if( !pnew )
1001     return (method && buf) ? m_btfiles.IO(buf, off, len, method) : 0;
1002 #endif
1003 
1004   pnew->bc_buf = new char[len];
1005 #ifndef WINDOWS
1006   if( !(pnew->bc_buf) ){
1007     delete pnew;
1008     return (method && buf) ? m_btfiles.IO(buf, off, len, method) : 0;
1009   }
1010 #endif
1011 
1012   if( buf ) memcpy(pnew->bc_buf, buf, len);
1013   else if( 0==method && m_btfiles.IO(pnew->bc_buf, off, len, method) < 0 ){
1014     delete []pnew->bc_buf;
1015     delete pnew;
1016     return -1;
1017   }
1018   pnew->bc_off = off;
1019   pnew->bc_len = len;
1020   pnew->bc_f_flush = method;
1021   m_cache_used += len;
1022   pnew->age_next = (BTCACHE *)0;
1023   if( m_cache_newest ){
1024     pnew->age_prev = m_cache_newest;
1025     m_cache_newest->age_next = pnew;
1026   }else{
1027     pnew->age_prev = (BTCACHE *)0;
1028     m_cache_oldest = pnew;
1029   }
1030   m_cache_newest = pnew;
1031 
1032   // find insert point: after pp, before p.
1033   size_t idx = off / m_piece_length;
1034   p = m_cache[idx];
1035   if( p ) pp = p->bc_prev;
1036   for( ; p && off > p->bc_off; pp = p, p = pp->bc_next );
1037 
1038   pnew->bc_next = p;
1039   pnew->bc_prev = pp;
1040   if( pp ) pp->bc_next = pnew;
1041   if( p ) p->bc_prev = pnew;
1042   if( !m_cache[idx] || off < m_cache[idx]->bc_off )
1043     m_cache[idx] = pnew;
1044 
1045   return 0;
1046 }
1047 
ReadPiece(char * buf,size_t idx)1048 ssize_t btContent::ReadPiece(char *buf,size_t idx)
1049 {
1050   return ReadSlice(buf, idx, 0, GetPieceLength(idx));
1051 }
1052 
GetPieceLength(size_t idx)1053 size_t btContent::GetPieceLength(size_t idx)
1054 {
1055   // Slight optimization to avoid division in every call.  The second test is
1056   // still needed in case the torrent size is exactly n pieces.
1057   return (idx == m_npieces - 1 &&
1058           idx == m_btfiles.GetTotalLength() / m_piece_length) ?
1059     (size_t)(m_btfiles.GetTotalLength() % m_piece_length) :
1060     m_piece_length;
1061 }
1062 
CheckExist()1063 int btContent::CheckExist()
1064 {
1065   size_t idx = 0;
1066   size_t percent = GetNPieces() / 100;
1067   unsigned char md[20];
1068 
1069   if( !percent ) percent = 1;
1070 
1071   CONSOLE.Interact_n("");
1072   for( ; idx < m_npieces; idx++ ){
1073     if( GetHashValue(idx, md) < 0 ){
1074       CONSOLE.Warning(1, "Error while checking piece %d of %d",
1075         (int)idx+1, (int)m_npieces);
1076       return -1;
1077     }
1078     if( memcmp(md, m_hash_table + idx * 20, 20) == 0 ){
1079        m_left_bytes -= GetPieceLength(idx);
1080        pBF->Set(idx);
1081     }
1082     if( idx % percent == 0 || idx == m_npieces-1 )
1083       CONSOLE.InteractU("Check exist: %d/%d", idx+1, m_npieces);
1084   }
1085   m_check_piece = m_npieces;
1086   pBChecked->SetAll();
1087   return 0;
1088 }
1089 
CheckNextPiece()1090 int btContent::CheckNextPiece()
1091 {
1092   size_t idx = m_check_piece;
1093   unsigned char md[20];
1094   int f_checkint = 0;
1095 
1096   if( idx >= m_npieces ) return 0;
1097   if( pBChecked->IsSet(idx) ){
1098     while( idx < m_npieces && pBChecked->IsSet(idx) ){
1099       if(arg_verbose) CONSOLE.Debug("Check: %u skipped", idx);
1100       pBChecked->Set(idx);
1101       ++idx;
1102     }
1103     f_checkint = 1;
1104     m_check_piece = idx;
1105   }
1106   if( idx < m_npieces ){
1107     // Don't use the cache for this (looks a bit ugly but helps performance).
1108     size_t tmp_cache_size = m_cache_size;
1109     m_cache_size = 0;
1110     int r = GetHashValue(idx, md);
1111     m_cache_size = tmp_cache_size;
1112     if( r < 0 ) return -1;
1113 
1114     pBChecked->Set(idx);  // need to set before CheckInterest below
1115     if( memcmp(md, m_hash_table + idx * 20, 20) == 0 ){
1116       if(arg_verbose) CONSOLE.Debug("Check: %u ok", idx);
1117       m_left_bytes -= GetPieceLength(idx);
1118       pBF->Set(idx);
1119       WORLD.Tell_World_I_Have(idx);
1120     }else{
1121       if(arg_verbose) CONSOLE.Debug("Check: %u failed", idx);
1122       f_checkint = 1;
1123     }
1124     m_check_piece = idx + 1;
1125   }
1126   if( f_checkint ) WORLD.CheckInterest();
1127 
1128   if( m_check_piece >= m_npieces ){
1129     CONSOLE.Print("Checking completed.");
1130     if( !pBF->IsEmpty() )
1131       m_btfiles.PrintOut();  // show file completion
1132     if( pBF->IsFull() ){
1133       WORLD.CloseAllConnectionToSeed();
1134     }
1135   }
1136   return 0;
1137 }
1138 
_file2mem(const char * fname,size_t * psiz)1139 char* btContent::_file2mem(const char *fname, size_t *psiz)
1140 {
1141   char *b = (char*) 0;
1142   struct stat sb;
1143   FILE* fp;
1144   fp = fopen(fname,"r");
1145   if( !fp ){
1146     CONSOLE.Warning(1, "error, open \"%s\" failed:  %s",fname,strerror(errno));
1147     return (char*) 0;
1148   }
1149 
1150   if(stat(fname,&sb) < 0){
1151     CONSOLE.Warning(1, "error, stat \"%s\" failed:  %s",fname,strerror(errno));
1152     return (char*) 0;
1153   }
1154 
1155   if( sb.st_size > MAX_METAINFO_FILESIZ ){
1156     CONSOLE.Warning(1, "error, \"%s\" is really a metainfo file???",fname);
1157     return (char*) 0;
1158   }
1159 
1160   b = new char[sb.st_size];
1161 #ifndef WINDOWS
1162   if( !b ) return (char*) 0;
1163 #endif
1164 
1165   if(fread(b, sb.st_size, 1, fp) != 1){
1166     if( ferror(fp) ){
1167       delete []b;
1168       return (char*) 0;
1169     }
1170   }
1171   fclose(fp);
1172 
1173   if(psiz) *psiz = sb.st_size;
1174   return b;
1175 }
1176 
APieceComplete(size_t idx)1177 int btContent::APieceComplete(size_t idx)
1178 {
1179   unsigned char md[20];
1180   if(pBF->IsSet(idx)) return 1;
1181   if( GetHashValue(idx, md) < 0 ){
1182     // error reading data
1183     Uncache(idx);
1184     return -1;
1185   }
1186 
1187   if( memcmp(md,(m_hash_table + idx * 20), 20) != 0 ){
1188     CONSOLE.Warning(3, "warn, piece %d hash check failed.", idx);
1189     Uncache(idx);
1190     CountHashFailure();
1191     return 0;
1192   }
1193 
1194   pBF->Set(idx);
1195   m_left_bytes -= GetPieceLength(idx);
1196   Tracker.CountDL(GetPieceLength(idx));
1197 
1198   // Add the completed piece to the flush queue.
1199   if( cfg_cache_size ){
1200     if( IsFull() ){
1201       FlushCache();
1202       for( size_t n=1; n <= m_btfiles.GetNFiles(); n++ )
1203         m_btfiles.CloseFile(n);  // files will reopen read-only
1204     }
1205     if( !IsFull() || m_flush_failed ){
1206       BTFLUSH *last = m_flushq;
1207       BTFLUSH *node = new BTFLUSH;
1208       if( !node ) FlushPiece(idx);
1209       else{
1210         node->idx = idx;
1211         node->next = (BTFLUSH *)0;
1212         if( last ){
1213           for( ; last->next; last = last->next);
1214           last->next = node;
1215         }else m_flushq = node;
1216       }
1217     }
1218   }
1219 
1220   return 1;
1221 }
1222 
GetHashValue(size_t idx,unsigned char * md)1223 int btContent::GetHashValue(size_t idx,unsigned char *md)
1224 {
1225   if( global_buffer_size < m_piece_length ){
1226     delete []global_piece_buffer;
1227     global_piece_buffer = new char[m_piece_length];
1228     global_buffer_size = global_piece_buffer ? m_piece_length : 0;
1229   }
1230   if( ReadPiece(global_piece_buffer,idx) < 0 ) return -1;
1231   Sha1(global_piece_buffer,GetPieceLength(idx),md);
1232   return 0;
1233 }
1234 
1235 // This is btcontent's "IntervalCheck()"
SeedTimeout()1236 int btContent::SeedTimeout()
1237 {
1238   uint64_t dl;
1239   size_t oldrate = m_prevdlrate;
1240 
1241   if( Seeding() && (!m_flush_failed || IsFull()) ){
1242     if( !m_seed_timestamp ){
1243       if( IsFull() ){
1244         Tracker.Reset(15);
1245         ReleaseHashTable();
1246       }
1247       Self.ResetDLTimer();  // set/report dl rate = 0
1248       m_prevdlrate = 0;
1249       m_seed_timestamp = now;
1250       for( size_t n=1; n <= m_btfiles.GetNFiles(); n++ )
1251         m_btfiles.CloseFile(n);  // files will reopen read-only
1252       // Free global buffer prior to CompletionCommand fork (reallocate after).
1253       delete []global_piece_buffer;
1254       global_piece_buffer = (char *)0;
1255       if( Self.TotalDL() > 0 ){
1256         CONSOLE.Print("Download complete.");
1257         CONSOLE.Print("Total time used: %ld minutes.",
1258           (long)((now - m_start_timestamp) / 60));
1259         if(arg_verbose) CONSOLE.cpu();
1260         if( arg_completion_exit )
1261           CompletionCommand();
1262       }
1263       // Reallocate global buffer for uploading.
1264       global_piece_buffer = new char[DEFAULT_SLICE_SIZE];
1265       global_buffer_size = global_piece_buffer ? DEFAULT_SLICE_SIZE : 0;
1266       if(arg_ctcs) CTCS.Send_Status();
1267       CONSOLE.Print_n("Seed for others %lu hours",
1268         (unsigned long)cfg_seed_hours);
1269       if( cfg_seed_ratio )
1270         CONSOLE.Print_n(" or to ratio of %.2f", cfg_seed_ratio);
1271       CONSOLE.Print("");
1272     }else if( now < m_seed_timestamp ) m_seed_timestamp = now;
1273     dl = (Self.TotalDL() > 0) ? Self.TotalDL() : GetTotalFilesLength();
1274     if( (cfg_seed_ratio == 0 && cfg_seed_hours == 0) ||
1275         (cfg_seed_hours > 0 &&
1276           (now - m_seed_timestamp) >= (cfg_seed_hours * 60 * 60)) ||
1277         (cfg_seed_ratio > 0 &&
1278           cfg_seed_ratio <= (double) Self.TotalUL() / dl) ){
1279       if( m_flush_failed ){
1280         if( !WORLD.IsPaused() ){
1281           CONSOLE.Warning(1,
1282             "Seeding completed but cache flush failed; pausing...");
1283           WORLD.Pause();
1284         }
1285       }else return 1;
1286     }
1287   }else{
1288     m_prevdlrate = Self.RateDL();
1289     if( m_prevdlrate == 0 && oldrate > 0 &&
1290         global_buffer_size > DEFAULT_SLICE_SIZE ){
1291       delete []global_piece_buffer;
1292       global_piece_buffer = new char[DEFAULT_SLICE_SIZE];
1293       global_buffer_size = global_piece_buffer ? DEFAULT_SLICE_SIZE : 0;
1294     }
1295   }
1296   if( (cfg_cache_size && now >= m_cache_eval_time) ||
1297       (oldrate == 0 && m_prevdlrate > 0) ){
1298     CacheEval();
1299   }
1300   return 0;
1301 }
1302 
1303 
CompletionCommand()1304 void btContent::CompletionCommand()
1305 {
1306   char *pt, *pd, *pw, *cmdstr;
1307   int nt=0, nd=0, nw=0;
1308 
1309   pt = pd = pw = arg_completion_exit;
1310   while( pt = strstr(pt, "&t") ){ nt++; pt+=2; }
1311   while( pd = strstr(pd, "&d") ){ nd++; pd+=2; }
1312   while( pw = strstr(pw, "&w") ){ nw++; pw+=2; }
1313 
1314   if( nt || nd || nw ){
1315     char wd[MAXPATHLEN], *ptmp, *parg = arg_completion_exit;
1316     if( nw && !getcwd(wd, MAXPATHLEN) ){
1317       CONSOLE.Warning(2, "warn, couldn't get working directory:  %s",
1318         strerror(errno));
1319       return;
1320     }
1321     cmdstr = new char[1 + strlen(arg_completion_exit) +
1322       nt * (strlen(arg_metainfo_file) - 2) +
1323       nd * (strlen(m_btfiles.GetDataName()) - 2) +
1324       nw * (strlen(wd) - 2)];
1325     if( !cmdstr ){
1326       CONSOLE.Warning(2,
1327         "warn, failed to allocate memory for completion command");
1328       return;
1329     }
1330     strcpy(cmdstr, arg_completion_exit);
1331 
1332     pt = strstr(cmdstr, "&t");
1333     pd = strstr(cmdstr, "&d");
1334     pw = strstr(cmdstr, "&w");
1335     while( pt || pd || pw ){
1336       if( pt && (!pd || pt < pd) && (!pw || pt < pw) ){
1337         strcpy(pt, arg_metainfo_file);
1338         ptmp = cmdstr + strlen(cmdstr);
1339         parg = strstr(parg, "&t") + 2;
1340         strcat(pt, parg);
1341         pt = strstr(ptmp, "&t");
1342         if( pd ) pd = strstr(ptmp, "&d");
1343         if( pw ) pw = strstr(ptmp, "&w");
1344       }
1345       if( pd && (!pt || pd < pt) && (!pw || pd < pw) ){
1346         strcpy(pd, m_btfiles.GetDataName());
1347         ptmp = cmdstr + strlen(cmdstr);
1348         parg = strstr(parg, "&d") + 2;
1349         strcat(pd, parg);
1350         pd = strstr(ptmp, "&d");
1351         if( pt ) pt = strstr(ptmp, "&t");
1352         if( pw ) pw = strstr(ptmp, "&w");
1353       }
1354       if( pw && (!pt || pw < pt) && (!pd || pw < pd) ){
1355         strcpy(pw, wd);
1356         ptmp = cmdstr + strlen(cmdstr);
1357         parg = strstr(parg, "&w") + 2;
1358         strcat(pw, parg);
1359         pw = strstr(ptmp, "&w");
1360         if( pt ) pt = strstr(ptmp, "&t");
1361         if( pd ) pd = strstr(ptmp, "&d");
1362       }
1363     }
1364   }
1365   else cmdstr = arg_completion_exit;
1366   if(arg_verbose) CONSOLE.Debug("Executing: %s", cmdstr);
1367 #ifdef HAVE_WORKING_FORK
1368   if( cfg_cache_size ){  // maybe free some cache before forking
1369     CacheEval();
1370     if( m_cache_size < m_cache_used && !m_flush_failed ) CacheClean(0);
1371   }
1372   pid_t r;
1373   if( (r = fork()) < 0 ){
1374     CONSOLE.Warning(2,"warn, fork failed running completion command:  %s",
1375       strerror(errno));
1376   }else if( r==0 ){
1377     if( m_cache_used ){  // free the cache in the child process
1378       BTCACHE *p, *pnext;
1379       for( p=m_cache_oldest; p; p=pnext ){
1380         pnext = p->age_next;
1381         delete []p->bc_buf;
1382         delete p;
1383       }
1384     }
1385 #endif
1386     if( system(cmdstr) < 0 )
1387       CONSOLE.Warning(2, "warn, failure running completion command:  %s",
1388         strerror(errno));
1389 #ifdef HAVE_WORKING_FORK
1390     exit(EXIT_SUCCESS);
1391   }
1392 #endif
1393   if( cmdstr != arg_completion_exit ) delete []cmdstr;
1394 }
1395 
1396 
CheckFilter()1397 void btContent::CheckFilter()
1398 {
1399   BitField tmpBitfield;
1400   BFNODE *original = m_current_filter;
1401 
1402   if( !m_filters ) return;
1403   if( !m_current_filter ) m_current_filter = m_filters;
1404 
1405   while( m_current_filter ){
1406     tmpBitfield = *pBF;             // what I have...
1407     tmpBitfield.Comb(GetFilter());  // ...plus what I don't want
1408     if( !tmpBitfield.IsFull() ) break;
1409     m_current_filter = m_current_filter->next;
1410   }
1411 
1412   if( !m_current_filter ){
1413     if( !IsFull() ) CONSOLE.Print("End of download files list.");
1414     for( BFNODE *goner=m_filters; goner; goner=m_current_filter ){
1415       m_current_filter = goner->next;
1416       delete goner;
1417     }
1418     m_filters = (BFNODE *)0;
1419   }
1420 
1421   if( m_current_filter != original ){
1422     if( m_current_filter ){
1423       size_t last;
1424       tmpBitfield = *GetFilter();
1425       tmpBitfield.Invert();      // what I want...
1426       tmpBitfield.Except(*pBF);  // ...that I don't have
1427       last = tmpBitfield.IsSet(m_npieces-1) ? 1 : 0;
1428       if( GetFilter()->IsEmpty() )
1429         CONSOLE.Print("Downloading remaining files");
1430       else CONSOLE.Print("Downloading file(s): %s", m_current_filter->name);
1431       CONSOLE.Print( "Pieces: %d (%llu bytes)", (int)(tmpBitfield.Count()),
1432         (unsigned long long)
1433           ((tmpBitfield.Count() - last) * (uint64_t)m_piece_length +
1434            (last ? GetPieceLength(m_npieces-1) : 0)) );
1435     }
1436   }
1437 
1438   if( m_seed_timestamp && m_current_filter ){
1439     // was seeding, now downloading again
1440     m_seed_timestamp = (time_t)0;
1441   }
1442 }
1443 
1444 
SetFilter()1445 void btContent::SetFilter()
1446 {
1447   // Set up filter list
1448   char *list=(char *)0, *tok, *dash, *plus;
1449   size_t start, end;
1450   BitField tmpFilter, *pfilter;
1451   BFNODE *node=m_filters, *pnode=(BFNODE *)0;
1452 
1453   if( arg_file_to_download ){
1454     pBMasterFilter->SetAll();
1455     list = new char[strlen(arg_file_to_download) + 1];
1456     if( !list ){
1457       CONSOLE.Warning(1, "error, failed to allocate memory for filter");
1458       return;
1459     }
1460     strcpy(list, arg_file_to_download);
1461     tok = strtok(list, ", ");
1462     while( tok ){
1463       if( !node ){
1464         node = new BFNODE;
1465         if( !node ){
1466           CONSOLE.Warning(1, "error, failed to allocate memory for filter");
1467           return;
1468         }
1469         if( pnode ) pnode->next = node;
1470         else m_filters = node;
1471       }
1472 
1473       if( node->name && strlen(node->name) < strlen(tok) ){
1474         delete []node->name;
1475         node->name = (char *)0;
1476       }
1477       if( !node->name ){
1478         node->name = new char[strlen(tok)+1];
1479         if( !node ){
1480           CONSOLE.Warning(1, "error, failed to allocate memory for filter");
1481           return;
1482         }
1483       }
1484       strcpy(node->name, tok);
1485 
1486       pfilter = &(node->bitfield);
1487       if( strstr(tok, "...") || strchr(tok, '*') ){
1488         pfilter->Clear();
1489         pBMasterFilter->Clear();
1490         pnode = node;
1491         node = node->next;
1492         break;
1493       }
1494       pfilter->SetAll();
1495       do{
1496         start = atoi(tok);
1497         m_btfiles.SetFilter((int)start, &tmpFilter, m_piece_length);
1498         pfilter->And(tmpFilter);
1499 
1500         plus = strchr(tok, '+');
1501 
1502         if( (dash = strchr(tok, '-')) && (!plus || dash < plus) ){
1503           end = atoi(dash + 1);
1504           while( ++start <= end ){
1505             m_btfiles.SetFilter((int)start, &tmpFilter, m_piece_length);
1506             pfilter->And(tmpFilter);
1507           }
1508         }
1509 
1510         tok = plus ? plus+1 : plus;
1511       }while( tok );
1512 
1513       pBMasterFilter->And(*pfilter);
1514       tok = strtok(NULL, ", ");
1515       pnode = node;
1516       node = node->next;
1517     }
1518     delete []list;
1519   }else  // no arg_file_to_download
1520     pBMasterFilter->Clear();
1521 
1522   if( m_filters && m_filters->bitfield.IsEmpty() ){
1523     delete []arg_file_to_download;
1524     arg_file_to_download = (char *)0;
1525     pBMasterFilter->Clear();
1526     node = m_filters;
1527     pnode = (BFNODE *)0;
1528   }
1529 
1530   if( node ){
1531     if( m_filters == node ) m_filters = (BFNODE *)0;
1532     if( pnode ) pnode->next = (BFNODE *)0;
1533     for( BFNODE *goner=node; goner; goner=node ){
1534       node = goner->next;
1535       delete goner;
1536     }
1537   }
1538 
1539   m_current_filter = (BFNODE *)0;
1540   CheckFilter();
1541   WORLD.CheckInterest();
1542 }
1543 
1544 
GetNextFilter(BitField * pfilter) const1545 BitField *btContent::GetNextFilter(BitField *pfilter) const
1546 {
1547   static BFNODE *p = m_filters;
1548 
1549   if( !pfilter ) p = m_filters;
1550   else if( p && &(p->bitfield) == pfilter ){
1551     p = p->next;
1552   }else{
1553     for( p=m_filters; p && (&(p->bitfield) != pfilter); p = p->next );
1554     if(p) p = p->next;
1555     else p = m_filters;
1556   }
1557 
1558   if(p) return &(p->bitfield);
1559   else return (BitField *) 0;
1560 }
1561 
1562 
Seeding() const1563 int btContent::Seeding() const
1564 {
1565   if( IsFull() || m_flush_failed ) return 1;
1566   if( arg_file_to_download && !m_current_filter ) return 1;
1567   return 0;
1568 }
1569 
1570 
1571 // Note, this functions assumes the program is exiting.
SaveBitfield()1572 void btContent::SaveBitfield()
1573 {
1574   if( arg_bitfield_file ){
1575     if( m_check_piece < m_npieces ){  // still checking
1576       // Anything unchecked needs to be checked next time.
1577       pBChecked->Invert();
1578       pBF->Comb(*pBChecked);
1579     }
1580     if( !pBF->IsFull() ) pBF->WriteToFile(arg_bitfield_file);
1581   }
1582 }
1583 
1584 
CountDupBlock(size_t len)1585 void btContent::CountDupBlock(size_t len)
1586 {
1587   m_dup_blocks++;
1588   Tracker.CountDL(len);
1589 }
1590 
1591 
DumpCache()1592 void btContent::DumpCache()
1593 {
1594   BTCACHE *p = m_cache_oldest;
1595   int count;
1596 
1597   CONSOLE.Debug("CACHE CONTENTS:");
1598   count = 0;
1599   for( ; p; p = p->age_next ){
1600     CONSOLE.Debug("  %p prev=%p %d/%d/%d %sflushed",
1601       p, p->age_prev,
1602       (int)(p->bc_off / m_piece_length), (int)(p->bc_off % m_piece_length),
1603       (int)(p->bc_len),
1604       p->bc_f_flush ? "un" : "");
1605     count++;
1606   }
1607   CONSOLE.Debug("  count=%d", count);
1608   CONSOLE.Debug("  newest=%p", m_cache_newest);
1609 
1610   CONSOLE.Debug("BY PIECE:");
1611   count = 0;
1612   for( size_t idx=0; idx < m_npieces; idx++ ){
1613     for( p=m_cache[idx]; p; p=p->bc_next ){
1614       CONSOLE.Debug("  %p prev=%p %d/%d/%d %sflushed",
1615         p, p->bc_prev,
1616         (int)(p->bc_off / m_piece_length), (int)(p->bc_off % m_piece_length),
1617         (int)(p->bc_len),
1618         p->bc_f_flush ? "un" : "");
1619       count++;
1620     }
1621   }
1622   CONSOLE.Debug("  count=%d", count);
1623 }
1624 
1625