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