📄 btcontent.cpp
字号:
return 1;}int btContent::GetHashValue(size_t idx,unsigned char *md){ if( global_buffer_size < m_piece_length ){ delete []global_piece_buffer; global_piece_buffer = new char[m_piece_length]; global_buffer_size = global_piece_buffer ? m_piece_length : 0; } if( ReadPiece(global_piece_buffer,idx) < 0 ) return -1; Sha1(global_piece_buffer,GetPieceLength(idx),md); return 0;}// This is btcontent's "IntervalCheck()"int btContent::SeedTimeout(){ uint64_t dl; size_t oldrate = m_prevdlrate; if( Seeding() && (!m_flush_failed || IsFull()) ){ if( !m_seed_timestamp ){ if( IsFull() ){ Tracker.Reset(15); ReleaseHashTable(); } Self.ResetDLTimer(); // set/report dl rate = 0 m_prevdlrate = 0; m_seed_timestamp = now; for( size_t n=1; n <= m_btfiles.GetNFiles(); n++ ) m_btfiles.CloseFile(n); // files will reopen read-only // Free global buffer prior to CompletionCommand fork (reallocate after). delete []global_piece_buffer; global_piece_buffer = (char *)0; if( Self.TotalDL() > 0 ){ CONSOLE.Print("Download complete."); CONSOLE.Print("Total time used: %ld minutes.", (long)((now - m_start_timestamp) / 60)); if(arg_verbose) CONSOLE.cpu(); if( arg_completion_exit ) CompletionCommand(); } // Reallocate global buffer for uploading. global_piece_buffer = new char[DEFAULT_SLICE_SIZE]; global_buffer_size = global_piece_buffer ? DEFAULT_SLICE_SIZE : 0; if(arg_ctcs) CTCS.Send_Status(); CONSOLE.Print_n("Seed for others %lu hours", (unsigned long)cfg_seed_hours); if( cfg_seed_ratio ) CONSOLE.Print_n(" or to ratio of %.2f", cfg_seed_ratio); CONSOLE.Print(""); }else if( now < m_seed_timestamp ) m_seed_timestamp = now; dl = (Self.TotalDL() > 0) ? Self.TotalDL() : GetTotalFilesLength(); if( (cfg_seed_ratio == 0 && cfg_seed_hours == 0) || (cfg_seed_hours > 0 && (now - m_seed_timestamp) >= (cfg_seed_hours * 60 * 60)) || (cfg_seed_ratio > 0 && cfg_seed_ratio <= (double) Self.TotalUL() / dl) ){ if( m_flush_failed ){ if( !WORLD.IsPaused() ){ CONSOLE.Warning(1, "Seeding completed but cache flush failed; pausing..."); WORLD.Pause(); } }else return 1; } }else{ m_prevdlrate = Self.RateDL(); if( m_prevdlrate == 0 && oldrate > 0 && global_buffer_size > DEFAULT_SLICE_SIZE ){ delete []global_piece_buffer; global_piece_buffer = new char[DEFAULT_SLICE_SIZE]; global_buffer_size = global_piece_buffer ? DEFAULT_SLICE_SIZE : 0; } } if( (cfg_cache_size && now >= m_cache_eval_time) || (oldrate == 0 && m_prevdlrate > 0) ){ CacheEval(); } return 0;}void btContent::CompletionCommand(){ char *pt, *pd, *pw, *cmdstr; int nt=0, nd=0, nw=0; pt = pd = pw = arg_completion_exit; while( pt = strstr(pt, "&t") ){ nt++; pt+=2; } while( pd = strstr(pd, "&d") ){ nd++; pd+=2; } while( pw = strstr(pw, "&w") ){ nw++; pw+=2; } if( nt || nd || nw ){ char wd[MAXPATHLEN], *ptmp, *parg = arg_completion_exit; if( nw && !getcwd(wd, MAXPATHLEN) ){ CONSOLE.Warning(2, "warn, couldn't get working directory: %s", strerror(errno)); return; } cmdstr = new char[1 + strlen(arg_completion_exit) + nt * (strlen(arg_metainfo_file) - 2) + nd * (strlen(m_btfiles.GetDataName()) - 2) + nw * (strlen(wd) - 2)]; if( !cmdstr ){ CONSOLE.Warning(2, "warn, failed to allocate memory for completion command"); return; } strcpy(cmdstr, arg_completion_exit); pt = strstr(cmdstr, "&t"); pd = strstr(cmdstr, "&d"); pw = strstr(cmdstr, "&w"); while( pt || pd || pw ){ if( pt && (!pd || pt < pd) && (!pw || pt < pw) ){ strcpy(pt, arg_metainfo_file); ptmp = cmdstr + strlen(cmdstr); parg = strstr(parg, "&t") + 2; strcat(pt, parg); pt = strstr(ptmp, "&t"); if( pd ) pd = strstr(ptmp, "&d"); if( pw ) pw = strstr(ptmp, "&w"); } if( pd && (!pt || pd < pt) && (!pw || pd < pw) ){ strcpy(pd, m_btfiles.GetDataName()); ptmp = cmdstr + strlen(cmdstr); parg = strstr(parg, "&d") + 2; strcat(pd, parg); pd = strstr(ptmp, "&d"); if( pt ) pt = strstr(ptmp, "&t"); if( pw ) pw = strstr(ptmp, "&w"); } if( pw && (!pt || pw < pt) && (!pd || pw < pd) ){ strcpy(pw, wd); ptmp = cmdstr + strlen(cmdstr); parg = strstr(parg, "&w") + 2; strcat(pw, parg); pw = strstr(ptmp, "&w"); if( pt ) pt = strstr(ptmp, "&t"); if( pd ) pd = strstr(ptmp, "&d"); } } } else cmdstr = arg_completion_exit; if(arg_verbose) CONSOLE.Debug("Executing: %s", cmdstr);#ifdef HAVE_WORKING_FORK if( cfg_cache_size ){ // maybe free some cache before forking CacheEval(); if( m_cache_size < m_cache_used && !m_flush_failed ) CacheClean(0); } pid_t r; if( (r = fork()) < 0 ){ CONSOLE.Warning(2,"warn, fork failed running completion command: %s", strerror(errno)); }else if( r==0 ){ if( m_cache_used ){ // free the cache in the child process BTCACHE *p, *pnext; for( p=m_cache_oldest; p; p=pnext ){ pnext = p->age_next; delete []p->bc_buf; delete p; } }#endif if( system(cmdstr) < 0 ) CONSOLE.Warning(2, "warn, failure running completion command: %s", strerror(errno));#ifdef HAVE_WORKING_FORK exit(EXIT_SUCCESS); }#endif if( cmdstr != arg_completion_exit ) delete []cmdstr;}void btContent::CheckFilter(){ BitField tmpBitfield; BFNODE *original = m_current_filter; if( !m_filters ) return; if( !m_current_filter ) m_current_filter = m_filters; while( m_current_filter ){ tmpBitfield = *pBF; // what I have... tmpBitfield.Comb(GetFilter()); // ...plus what I don't want if( !tmpBitfield.IsFull() ) break; m_current_filter = m_current_filter->next; } if( !m_current_filter ){ if( !IsFull() ) CONSOLE.Print("End of download files list."); for( BFNODE *goner=m_filters; goner; goner=m_current_filter ){ m_current_filter = goner->next; delete goner; } m_filters = (BFNODE *)0; } if( m_current_filter != original ){ if( m_current_filter ){ size_t last; tmpBitfield = *GetFilter(); tmpBitfield.Invert(); // what I want... tmpBitfield.Except(*pBF); // ...that I don't have last = tmpBitfield.IsSet(m_npieces-1) ? 1 : 0; if( GetFilter()->IsEmpty() ) CONSOLE.Print("Downloading remaining files"); else CONSOLE.Print("Downloading file(s): %s", m_current_filter->name); CONSOLE.Print( "Pieces: %d (%llu bytes)", (int)(tmpBitfield.Count()), (unsigned long long) ((tmpBitfield.Count() - last) * (uint64_t)m_piece_length + (last ? GetPieceLength(m_npieces-1) : 0)) ); } } if( m_seed_timestamp && m_current_filter ){ // was seeding, now downloading again m_seed_timestamp = (time_t)0; }}void btContent::SetFilter(){ // Set up filter list char *list=(char *)0, *tok, *dash, *plus; size_t start, end; BitField tmpFilter, *pfilter; BFNODE *node=m_filters, *pnode=(BFNODE *)0; if( arg_file_to_download ){ pBMasterFilter->SetAll(); list = new char[strlen(arg_file_to_download) + 1]; if( !list ){ CONSOLE.Warning(1, "error, failed to allocate memory for filter"); return; } strcpy(list, arg_file_to_download); tok = strtok(list, ", "); while( tok ){ if( !node ){ node = new BFNODE; if( !node ){ CONSOLE.Warning(1, "error, failed to allocate memory for filter"); return; } if( pnode ) pnode->next = node; else m_filters = node; } if( node->name && strlen(node->name) < strlen(tok) ){ delete []node->name; node->name = (char *)0; } if( !node->name ){ node->name = new char[strlen(tok)+1]; if( !node ){ CONSOLE.Warning(1, "error, failed to allocate memory for filter"); return; } } strcpy(node->name, tok); pfilter = &(node->bitfield); if( strstr(tok, "...") || strchr(tok, '*') ){ pfilter->Clear(); pBMasterFilter->Clear(); pnode = node; node = node->next; break; } pfilter->SetAll(); do{ start = atoi(tok); m_btfiles.SetFilter((int)start, &tmpFilter, m_piece_length); pfilter->And(tmpFilter); plus = strchr(tok, '+'); if( (dash = strchr(tok, '-')) && (!plus || dash < plus) ){ end = atoi(dash + 1); while( ++start <= end ){ m_btfiles.SetFilter((int)start, &tmpFilter, m_piece_length); pfilter->And(tmpFilter); } } tok = plus ? plus+1 : plus; }while( tok ); pBMasterFilter->And(*pfilter); tok = strtok(NULL, ", "); pnode = node; node = node->next; } delete []list; }else // no arg_file_to_download pBMasterFilter->Clear(); if( m_filters && m_filters->bitfield.IsEmpty() ){ delete []arg_file_to_download; arg_file_to_download = (char *)0; pBMasterFilter->Clear(); node = m_filters; pnode = (BFNODE *)0; } if( node ){ if( m_filters == node ) m_filters = (BFNODE *)0; if( pnode ) pnode->next = (BFNODE *)0; for( BFNODE *goner=node; goner; goner=node ){ node = goner->next; delete goner; } } m_current_filter = (BFNODE *)0; CheckFilter(); WORLD.CheckInterest();}BitField *btContent::GetNextFilter(BitField *pfilter) const{ static BFNODE *p = m_filters; if( !pfilter ) p = m_filters; else if( p && &(p->bitfield) == pfilter ){ p = p->next; }else{ for( p=m_filters; p && (&(p->bitfield) != pfilter); p = p->next ); if(p) p = p->next; else p = m_filters; } if(p) return &(p->bitfield); else return (BitField *) 0;}int btContent::Seeding() const{ if( IsFull() || m_flush_failed ) return 1; if( arg_file_to_download && !m_current_filter ) return 1; return 0;}// Note, this functions assumes the program is exiting.void btContent::SaveBitfield(){ if( arg_bitfield_file ){ if( m_check_piece < m_npieces ){ // still checking // Anything unchecked needs to be checked next time. pBChecked->Invert(); pBF->Comb(*pBChecked); } if( !pBF->IsFull() ) pBF->WriteToFile(arg_bitfield_file); }}void btContent::CountDupBlock(size_t len){ m_dup_blocks++; Tracker.CountDL(len);}void btContent::DumpCache(){ BTCACHE *p = m_cache_oldest; int count; CONSOLE.Debug("CACHE CONTENTS:"); count = 0; for( ; p; p = p->age_next ){ CONSOLE.Debug(" %p prev=%p %d/%d/%d %sflushed", p, p->age_prev, (int)(p->bc_off / m_piece_length), (int)(p->bc_off % m_piece_length), (int)(p->bc_len), p->bc_f_flush ? "un" : ""); count++; } CONSOLE.Debug(" count=%d", count); CONSOLE.Debug(" newest=%p", m_cache_newest); CONSOLE.Debug("BY PIECE:"); count = 0; for( size_t idx=0; idx < m_npieces; idx++ ){ for( p=m_cache[idx]; p; p=p->bc_next ){ CONSOLE.Debug(" %p prev=%p %d/%d/%d %sflushed", p, p->bc_prev, (int)(p->bc_off / m_piece_length), (int)(p->bc_off % m_piece_length), (int)(p->bc_len), p->bc_f_flush ? "un" : ""); count++; } } CONSOLE.Debug(" count=%d", count);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -