📄 btcontent.cpp
字号:
if( idx < m_npieces ){ // Don't use the cache for this (looks a bit ugly but helps performance). size_t tmp_cache_size = m_cache_size; m_cache_size = 0; int r = GetHashValue(idx, md); m_cache_size = tmp_cache_size; if( r < 0 ) return -1; pBChecked->Set(idx); // need to set before CheckInterest below if( memcmp(md, m_hash_table + idx * 20, 20) == 0 ){ m_left_bytes -= GetPieceLength(idx); pBF->Set(idx); WORLD.Tell_World_I_Have(idx); if( pBF->IsFull() ){ WORLD.CloseAllConnectionToSeed(); } } else f_checkint = 1; m_check_piece = idx + 1; } if( f_checkint ) WORLD.CheckInterest(); if( m_check_piece >= m_npieces ){ CONSOLE.Print("Checking completed."); m_btfiles.PrintOut(); // show file completion delete pBRefer; } return 0;}char* btContent::_file2mem(const char *fname, size_t *psiz){ char *b = (char*) 0; struct stat sb; FILE* fp; fp = fopen(fname,"r"); if( !fp ){ CONSOLE.Warning(1, "error, open \"%s\" failed: %s",fname,strerror(errno)); return (char*) 0; } if(stat(fname,&sb) < 0){ CONSOLE.Warning(1, "error, stat \"%s\" failed: %s",fname,strerror(errno)); return (char*) 0; } if( sb.st_size > MAX_METAINFO_FILESIZ ){ CONSOLE.Warning(1, "error, \"%s\" is really a metainfo file???",fname); return (char*) 0; } b = new char[sb.st_size];#ifndef WINDOWS if( !b ) return (char*) 0;#endif if(fread(b, sb.st_size, 1, fp) != 1){ if( ferror(fp) ){ delete []b; return (char*) 0; } } fclose(fp); if(psiz) *psiz = sb.st_size; return b;}int btContent::APieceComplete(size_t idx){ unsigned char md[20]; if(pBF->IsSet(idx)) return 1; if( GetHashValue(idx, md) < 0 ){ Uncache(idx); return -1; } if( memcmp(md,(m_hash_table + idx * 20), 20) != 0 ){ CONSOLE.Warning(3, "warn, piece %d hash check failed.", idx); return 0; } pBF->Set(idx); m_left_bytes -= GetPieceLength(idx); // Add the completed piece to the flush queue. if( cfg_cache_size ){ if( IsFull() ){ FlushCache(); for( size_t n=1; n <= m_btfiles.GetNFiles(); n++ ) m_btfiles.CloseFile(n); // files will reopen read-only } if( !IsFull() || m_flush_failed ){ BTFLUSH *last = m_flushq; BTFLUSH *node = new BTFLUSH; if( !node ) FlushCache(idx); else{ node->idx = idx; node->next = (BTFLUSH *)0; if( last ){ for( ; last->next; last = last->next); last->next = node; }else m_flushq = node; } } } return 1;}int btContent::GetHashValue(size_t idx,unsigned char *md){ 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; if( Seeding() && (!m_flush_failed || IsFull()) ){ if( !m_seed_timestamp ){ if( IsFull() ){ Tracker.Reset(1); ReleaseHashTable(); } Self.ResetDLTimer(); // set/report dl rate = 0 m_seed_timestamp = now; for( size_t n=1; n <= m_btfiles.GetNFiles(); n++ ) m_btfiles.CloseFile(n); // files will reopen read-only 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.Debug( "%.2f CPU seconds used; %lu seconds elapsed (%.2f%% usage)", clock() / (double)CLOCKS_PER_SEC, (unsigned long)(time((time_t *)0) - BTCONTENT.GetStartTime()), clock() / (double)CLOCKS_PER_SEC / (time((time_t *)0) - BTCONTENT.GetStartTime()) * 100 ); if( arg_completion_exit ) CompletionCommand(); } 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; } } if( cfg_cache_size && now >= m_cache_eval_time ) 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 pBChecked->Invert(); pBRefer->And(*pBChecked); pBF->Comb(*pBRefer); } if( !pBF->IsFull() ) pBF->WriteToFile(arg_bitfield_file); }}void btContent::DumpCache(){ BTCACHE *p = m_cache_oldest; CONSOLE.Debug("CACHE CONTENTS:"); for( ; p; p = p->age_next ){ CONSOLE.Debug(" 0x%llx: %d bytes %sflushed", p->bc_off, (int)(p->bc_len), p->bc_f_flush ? "un" : ""); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -