From a4a622b57d7cad630332ddf1050178e1d419e379 Mon Sep 17 00:00:00 2001 From: victor Date: Sat, 10 Oct 2009 17:46:25 +0000 Subject: [PATCH] now it builds git-svn-id: https://ttuki.vtt.fi/svn/p2p-next/TUD/p2tp/trunk@396 e16421f0-f15b-0410-abcd-98678b794739 --- bin64.cpp | 46 +++ bin64.h | 36 +- bins.cpp | 33 +- bins.h | 6 +- datagram.h | 8 +- .../ledbat_controller.cpp | 0 ext/mmap_storer.cpp | 25 ++ seq_picker.cpp => ext/seq_picker.cpp | 26 +- .../simple_selector.cpp | 0 hashtree.cpp | 4 +- hashtree.h | 4 +- p2tp.cpp | 3 +- p2tp.h | 78 ++-- sendrecv.cpp | 2 +- tests/bin64test.cpp | 37 +- transfer.cpp | 343 +++++++++++------- 16 files changed, 436 insertions(+), 215 deletions(-) create mode 100644 bin64.cpp rename ledbat_controller.cpp => ext/ledbat_controller.cpp (100%) create mode 100644 ext/mmap_storer.cpp rename seq_picker.cpp => ext/seq_picker.cpp (53%) rename simple_selector.cpp => ext/simple_selector.cpp (100%) diff --git a/bin64.cpp b/bin64.cpp new file mode 100644 index 0000000..90524d5 --- /dev/null +++ b/bin64.cpp @@ -0,0 +1,46 @@ +/* + * bin64.cpp + * p2tp + * + * Created by Victor Grishchenko on 10/10/09. + * Copyright 2009 Delft Technical University. All rights reserved. + * + */ +#include "bin64.h" + +const uint64_t bin64_t::NONE = 0xffffffffffffffffULL; +const uint64_t bin64_t::ALL = 0x7fffffffffffffffULL; + +bin64_t bin64_t::next_dfsio (uint8_t floor) { + /*while (ret.is_right()) + ret = ret.parent(); + ret = ret.sibling(); + while (ret.layer()>floor) + ret = ret.left();*/ + if (is_right()) { + return parent(); + } else { + bin64_t ret = sibling(); + while (ret.layer()>floor) + ret = ret.left(); + return ret; + } +} + +int bin64_t::peaks (uint64_t length, bin64_t* peaks) { + int pp=0; + uint8_t layer = 0; + while (length) { + if (length&1) + peaks[pp++] = bin64_t(layer,length^1); + length>>=1; + layer++; + } + for(int i=0; i<(pp>>1); i++) { + uint64_t memo = peaks[pp-1-i]; + peaks[pp-1-i] = peaks[i]; + peaks[i] = memo; + } + peaks[pp] = NONE; + return pp; +} diff --git a/bin64.h b/bin64.h index e619468..d867545 100644 --- a/bin64.h +++ b/bin64.h @@ -3,7 +3,7 @@ #include #include -#include +//#include /** Bin numbers in the tail111 encoding: meaningless bits in the tail are set to 0111...11, while the @@ -11,8 +11,8 @@ at layer 1, offset 3 (i.e. fourth). */ struct bin64_t { uint64_t v; - static const uint64_t NONE = 0xffffffffffffffffULL; - static const uint64_t ALL = 0x7fffffffffffffffULL; + static const uint64_t NONE; + static const uint64_t ALL; bin64_t() : v(NONE) {} bin64_t(const bin64_t&b) : v(b.v) {} @@ -107,21 +107,25 @@ struct bin64_t { } bool is_right() const { return !is_left(); } + bin64_t left_foot () const { + return bin64_t(0,base_offset()); + } + + bool is_base () const { + return !(v & 1); + } + + bin64_t next_dfsio (uint8_t floor); + + bin64_t width () const { + return (tail_bits()+1)>>1; + } + /** The array must have 64 cells, as it is the max - number of peaks possible (and there are no reason + number of peaks possible +1 (and there are no reason to assume there will be less in any given case. */ - static void GetPeaks(uint64_t length, bin64_t* peaks) { - int pp=0; - uint8_t layer = 0; - while (length) { - if (length&1) - peaks[pp++] = bin64_t(layer,length^1); - length>>=1; - layer++; - } - peaks[pp] = NONE; - } - + static int peaks (uint64_t length, bin64_t* peaks) ; + }; diff --git a/bins.cpp b/bins.cpp index e6d580f..c1c7436 100644 --- a/bins.cpp +++ b/bins.cpp @@ -35,6 +35,13 @@ bins::bins() : height(4), blocks_allocated(0), cells(NULL), assert(!alloc_cell()); } +bins::bins (const bins& b) : height(b.height), ap(b.ap), +blocks_allocated(b.blocks_allocated), cells_allocated(b.cells_allocated) { + size_t memsz = blocks_allocated*16*32; + cells = (uint32_t*) malloc(memsz); + memcpy(cells,b.cells,memsz); +} + void bins::dump (const char* note) { printf("%s\t",note); for(int i=0; i<(blocks_allocated<<5); i++) { @@ -212,12 +219,13 @@ void iterator::parent () { } -bin64_t bins::find (const bin64_t range, const uint8_t layer) { +bin64_t bins::find (const bin64_t range, const uint8_t layer, fill_t seek) { iterator i(this,range,true); + fill_t stop = seek==EMPTY ? FILLED : EMPTY; while (true) { - while ( i.bin().layer()>layer && (i.deep() || *i!=FILLED) ) + while ( i.bin().layer()>layer && (i.deep() || *i!=stop) ) i.left(); - if (i.bin().layer()==layer && !i.deep() && *i==EMPTY) + if (i.bin().layer()==layer && !i.deep() && *i==seek) return i.bin(); while (i.bin().is_right() && i.bin()!=range) i.parent(); @@ -288,3 +296,22 @@ uint64_t* bins::get_stripes (int& count) { return stripes; } + + +void bins::remove (bins& b) { + uint8_t start_lr = b.height>height ? b.height : height; + bin64_t top(start_lr,0); + iterator zis(this,top), zat(&b,top); + while (!zis.end()) { + while (zis.deep() || zat.deep()) { + zis.left(); zat.left(); + } + + *zis &= ~*zat; + + while (zis.pos.is_right()) { + zis.parent(); zat.parent(); + } + zis.sibling(); zat.sibling(); + } +} \ No newline at end of file diff --git a/bins.h b/bins.h index ca226df..299ece6 100644 --- a/bins.h +++ b/bins.h @@ -20,11 +20,15 @@ public: bins(); + bins(const bins& b); + uint16_t get (bin64_t bin); void set (bin64_t bin, fill_t val=FILLED); - bin64_t find (const bin64_t range, const uint8_t layer) ; + bin64_t find (const bin64_t range, const uint8_t layer, fill_t seek=EMPTY) ; + + void remove (bins& b); void dump(const char* note); diff --git a/datagram.h b/datagram.h index 5ff689b..dd2f5dd 100644 --- a/datagram.h +++ b/datagram.h @@ -26,10 +26,10 @@ namespace p2tp { typedef int64_t tint; -#define SEC ((tint)1000000) -#define MSEC ((tint)1000) -#define uSEC ((tint)1) -#define NEVER ((tint)0x7fffffffffffffffLL) +#define TINT_SEC ((tint)1000000) +#define TINT_MSEC ((tint)1000) +#define TINT_uSEC ((tint)1) +#define TINT_NEVER ((tint)0x7fffffffffffffffLL) #define MAXDGRAMSZ 1400 struct Datagram { diff --git a/ledbat_controller.cpp b/ext/ledbat_controller.cpp similarity index 100% rename from ledbat_controller.cpp rename to ext/ledbat_controller.cpp diff --git a/ext/mmap_storer.cpp b/ext/mmap_storer.cpp new file mode 100644 index 0000000..49d07c7 --- /dev/null +++ b/ext/mmap_storer.cpp @@ -0,0 +1,25 @@ +/* + * mmap_storer.cpp + * p2tp + * + * Created by Victor Grishchenko on 10/7/09. + * Copyright 2009 Delft Technical University. All rights reserved. + * + */ +#include "p2tp.h" + +class MMappedStorer : public DataStorer { +public: + + DataStorer (Sha1Hash id, size_t size) { + } + + virtual size_t ReadData (bin64_t pos,uint8_t** buf) { + } + + virtual size_t WriteData (bin64_t pos, uint8_t* buf, size_t len) { + } + + virtual Sha1Hash* LoadHashes(); + +}; \ No newline at end of file diff --git a/seq_picker.cpp b/ext/seq_picker.cpp similarity index 53% rename from seq_picker.cpp rename to ext/seq_picker.cpp index 4b20e01..dbb7e83 100644 --- a/seq_picker.cpp +++ b/ext/seq_picker.cpp @@ -19,28 +19,28 @@ class SeqPiecePicker : public PiecePicker { public: SeqPiecePicker (FileTransfer* file_) : file(file_) { - diho(file->ack_out); } virtual bin64_t Pick (bins& from, uint8_t layer) { - bins may_pick = ~ file->ack_out; - may_pick &= from; - may_pick -= hint_out; - bin64_t pick = may_pick.find(file->top,bins::FILLED); - if ( pick==bin64_t::NONE || pick.right_foot() > file->size() ) - if (layer) - return Pick(from,layer-1); - else - return bin64_t::NONE; - return pick; + bins may_pick = from; + may_pick.remove (file->ack_out); + may_pick.remove (hint_out); + for (int l=layer; l>=0; l--) { + for(int i=0; ipeak_count; i++) { + bin64_t pick = may_pick.find(file->peaks[i],l,bins::FILLED); + if (pick!=bin64_t::NONE) + return pick; + } + } + return bin64_t::NONE; } virtual void Received (bin64_t b) { - diho.set(b,bins::FILLED); + hint_out.set(b,bins::EMPTY); } virtual void Snubbed (bin64_t b) { - diho.set(b,bins::EMPTY); + hint_out.set(b,bins::EMPTY); } }; \ No newline at end of file diff --git a/simple_selector.cpp b/ext/simple_selector.cpp similarity index 100% rename from simple_selector.cpp rename to ext/simple_selector.cpp diff --git a/hashtree.cpp b/hashtree.cpp index 6c17892..4e4d201 100644 --- a/hashtree.cpp +++ b/hashtree.cpp @@ -59,7 +59,7 @@ string Sha1Hash::hex() { }*/ -Sha1Hash HashTree::deriveRoot () { +/*Sha1Hash HashTree::deriveRoot () { int i = peaks.size()-1; bin p = peaks[i].first; Sha1Hash hash = peaks[i].second; @@ -161,4 +161,4 @@ HashTree::hashres_t HashTree::offer (bin pos, const Sha1Hash& hash) { } - +*/ diff --git a/hashtree.h b/hashtree.h index f4bdb4e..611919b 100644 --- a/hashtree.h +++ b/hashtree.h @@ -27,11 +27,13 @@ struct Sha1Hash { bool operator == (const Sha1Hash& b) const { return 0==memcmp(bits,b.bits,SIZE); } bool operator != (const Sha1Hash& b) const { return !(*this==b); } + const char* operator * () const { return (char*) bits; } const static Sha1Hash ZERO; const static size_t SIZE; }; +/* typedef std::pair binhash; struct HashTree { @@ -67,6 +69,6 @@ public: const std::vector& peak_hashes() const { return peaks; } -}; +};*/ #endif diff --git a/p2tp.cpp b/p2tp.cpp index fe540bc..1bf4bc9 100644 --- a/p2tp.cpp +++ b/p2tp.cpp @@ -18,13 +18,14 @@ #include #include #include "p2tp.h" +#include "datagram.h" using namespace std; using namespace p2tp; p2tp::tint Channel::last_tick = 0; int Channel::MAX_REORDERING = 4; -p2tp::tint Channel::TIMEOUT = TINT_1SEC*60; +p2tp::tint Channel::TIMEOUT = TINT_SEC*60; std::vector Channel::channels(1); std::vector File::files(4); int* Channel::sockets_ = (int*)malloc(40); diff --git a/p2tp.h b/p2tp.h index a5ac644..7286975 100644 --- a/p2tp.h +++ b/p2tp.h @@ -84,43 +84,40 @@ namespace p2tp { public: + /** Open/submit/retrieve a file. */ + FileTransfer(const Sha1Hash& _root_hash, const char *file_name); + + /** Close everything. */ + ~FileTransfer(); + /** Offer a hash; returns true if it verified; false otherwise. Once it cannot be verified (no sibling or parent), the hash is remembered, while returning false. */ - bool OfferHash (bin64_t pos, const Sha1Hash& hash); + void OfferHash (bin64_t pos, const Sha1Hash& hash); /** Offer data; the behavior is the same as with a hash: - accept or remember or drop. */ - bool OfferData (bin64_t bin, uint8_t* data); + accept or remember or drop. Returns true => ACK is sent. */ + bool OfferData (bin64_t bin, uint8_t* data, size_t length); - const Sha1Hash& root_hash () const { return *root_hash; } - - size_t size () const; - size_t packet_size () const; - size_t size_complete () const; - size_t packets_complete () const; - - static FileTransfer* find (const Sha1Hash& hash); + static FileTransfer* Find (const Sha1Hash& hash); static FileTransfer* file (int fd) { return fd files; - - /** Open/submit/retrieve a file. */ - FileTransfer (Sha1Hash hash, char* file_name); - /** Close everything. */ - ~FileTransfer(); - + /** file descriptor. */ int fd; /** File size, as derived from the hashes. */ + size_t size; size_t sizek; - /** Whether the file is completely downloaded. */ - bool complete; + /** Part the file currently downloaded. */ + size_t complete; + size_t completek; + size_t seq_complete; /** A map for all packets obtained and succesfully checked. */ bins ack_out; /** History of bin retrieval. */ @@ -130,20 +127,29 @@ namespace p2tp { /** File for keeping the Merkle hash tree. */ int hashfd; /** Merkle hash tree: root */ - Sha1Hash* root_hash; + Sha1Hash root_hash; /** Merkle hash tree: peak hashes */ - Sha1Hash* peak_hashes; + Sha1Hash peak_hashes[64]; + bin64_t peaks[64]; + int peak_count; /** Merkle hash tree: the tree, as a bin64_t-indexed array */ Sha1Hash* hashes; + /** for recovering saved state */ + bool dry_run; + protected: - void Resize(size_t bytes); + void SetSize(size_t bytes); + void Submit(); + void RecoverProgress(); + void OfferPeak (bin64_t pos, const Sha1Hash& hash); + Sha1Hash DeriveRoot(); friend class Channel; }; int Open (const char* filename) ; - int Open (const Sha1Hash& root_hash, const char* filename); + int Open (const Sha1Hash& hash, const char* filename) ; void Close (int fid) ; void Loop (tint till); int Bind (int port); @@ -157,10 +163,10 @@ namespace p2tp { tint dev_avg; int cwnd; int peer_cwnd; - virtual void OnDataSent(bin64_t b) = 0; - virtual void OnDataRecvd(bin64_t b) = 0; - virtual void OnAckRcvd(bin64_t b, tint peer_stamp) = 0; - virtual ~CongestionControl() = 0; + virtual void OnDataSent(bin64_t b) = 0; + virtual void OnDataRecvd(bin64_t b) = 0; + virtual void OnAckRcvd(bin64_t b, tint peer_stamp) = 0; + virtual ~CongestionController() = 0; }; class PiecePicker { @@ -172,8 +178,16 @@ namespace p2tp { class PeerSelector { public: - virtual void PeerKnown (const Sha1Hash& root, struct sockaddr_in& addr) = 0; - virtual sockaddr_in GetPeer (const Sha1Hash& for_root) = 0; + virtual void PeerKnown (const Sha1Hash& root, struct sockaddr_in& addr) = 0; + virtual struct sockaddr_in + GetPeer (const Sha1Hash& for_root) = 0; + }; + + class DataStorer { + public: + DataStorer (const Sha1Hash& id, size_t size); + virtual size_t ReadData (bin64_t pos,uint8_t** buf) = 0; + virtual size_t WriteData (bin64_t pos, uint8_t* buf, size_t len) = 0; }; @@ -195,8 +209,6 @@ namespace p2tp { tint SendSomething (); void SendHandshake (); - FileTransfer& file () { return *FileTransfer::files[fd]; } - void OnAck (Datagram& dgram); void OnData (Datagram& dgram); void OnHint (Datagram& dgram); @@ -211,8 +223,6 @@ namespace p2tp { void CleanStaleHints(); - state_t state () const; - static int DecodeID(int scrambled); static int EncodeID(int unscrambled); static Channel* channel(int i) {return ifile().hashes.data_mass()) { diff --git a/tests/bin64test.cpp b/tests/bin64test.cpp index 71db670..3a2bb44 100644 --- a/tests/bin64test.cpp +++ b/tests/bin64test.cpp @@ -9,7 +9,7 @@ #include "bin64.h" #include -TEST(BinTest,InitGet) { +TEST(Bin64Test,InitGet) { EXPECT_EQ(0x1,bin64_t(1,0)); EXPECT_EQ(0xB,bin64_t(2,1)); @@ -23,7 +23,7 @@ TEST(BinTest,InitGet) { } -TEST(BinTest,Navigation) { +TEST(Bin64Test,Navigation) { bin64_t mid(4,18); EXPECT_EQ(bin64_t(5,9),mid.parent()); @@ -35,7 +35,7 @@ TEST(BinTest,Navigation) { } -TEST(BinTest,Overflows) { +TEST(Bin64Test,Overflows) { /*EXPECT_EQ(bin64_t::NONE.parent(),bin64_t::NONE); EXPECT_EQ(bin64_t::NONE.left(),bin64_t::NONE); @@ -45,6 +45,37 @@ TEST(BinTest,Overflows) { */ } +TEST(Bin64Test, Advanced) { + + EXPECT_EQ(4,bin64_t(2,3).width()); + EXPECT_FALSE(bin64_t(1,1234).is_base()); + EXPECT_TRUE(bin64_t(0,12345).is_base()); + EXPECT_EQ(bin64_t(0,2),bin64_t(1,1).left_foot()); + bin64_t peaks[64]; + int peak_count = bin64_t::peaks(7,peaks); + EXPECT_EQ(3,peak_count); + EXPECT_EQ(bin64_t(2,0),peaks[0]); + EXPECT_EQ(bin64_t(1,2),peaks[1]); + EXPECT_EQ(bin64_t(0,6),peaks[2]); + +} + +TEST(Bin64Test, Iteration) { + bin64_t i(1,0); + i = i.next_dfsio(1); + EXPECT_EQ(bin64_t(1,1),i); + i = i.next_dfsio(1); + EXPECT_EQ(bin64_t(2,0),i); + i = i.next_dfsio(1); + EXPECT_EQ(bin64_t(1,2),i); + i = i.next_dfsio(1); + EXPECT_EQ(bin64_t(1,3),i); + i = i.next_dfsio(1); + EXPECT_EQ(bin64_t(2,1),i); + i = i.next_dfsio(1); + EXPECT_EQ(bin64_t(3,0),i); +} + int main (int argc, char** argv) { testing::InitGoogleTest(&argc, argv); diff --git a/transfer.cpp b/transfer.cpp index f268f84..8bb74c9 100644 --- a/transfer.cpp +++ b/transfer.cpp @@ -6,183 +6,254 @@ * Copyright 2009 Delft Technical University. All rights reserved. * */ - #include "p2tp.h" +#include +using namespace p2tp; -File::File (int _fd) : fd(_fd), status_(DONE), hashes(_fd) -{ - bin::vec peaks = bin::peaks(hashes.data_size()); - history.insert(history.end(),peaks.begin(),peaks.end()); - for(bin::vec::iterator i=peaks.begin(); i!=peaks.end(); i++) - ack_out.set(*i); -} - -File::File (Sha1Hash hash, int _fd) : hashes(hash), fd(_fd), status_(EMPTY) { - // TODO resubmit data -} - -File::~File() { - if (fd>0) ::close(fd); -} +std::vector FileTransfer::files(20); -bool File::OfferHash (bin pos, const Sha1Hash& hash) { - HashTree::hashres_t res = hashes.offer(pos,hash); - if (res==HashTree::PEAK_ACCEPT) { // file size is finally known - ftruncate(fd, size()); - LOG(INFO)<::iterator i=files.begin(); i!=files.end(); i++) - if (*i && (*i)->hashes.root==hash) - return *i; - return NULL; +/** Basically, simulated receiving every single packet, except + for some optimizations. */ +void FileTransfer::RecoverProgress () { + // open file + struct stat hash_file_st; + fstat(fd, &hash_file_st); + if ( hash_file_st.st_size < (sizeof(bin64_t)+Sha1Hash::SIZE)*64 ) + return; + // read root hash + char hashbuf[128]; + uint64_t binbuf; + lseek(hashfd,0,SEEK_SET); + read(hashfd,&binbuf,sizeof(bin64_t)); + read(hashfd,hashbuf,Sha1Hash::SIZE); + Sha1Hash mustberoot(false,(const char*)hashbuf); + if ( binbuf!=bin64_t::ALL || mustberoot != this->root_hash ) { + ftruncate(hashfd,Sha1Hash::SIZE*64); + return; + } + // read peak hashes + for(int i=1; i<64 && !this->size; i++){ + read(hashfd,&binbuf,sizeof(bin64_t)); + read(hashfd,hashbuf,Sha1Hash::SIZE); + Sha1Hash mustbepeak(false,(const char*)hashbuf); + if (mustbepeak==Sha1Hash::ZERO) + break; + OfferPeak(binbuf,mustbepeak); + } + if (!size) + return; + // at this point, we may use mmapd hashes already + // so, lets verify hashes and the data we've got + dry_run = true; + lseek(fd,0,SEEK_SET); + for(int p=0; p>10) + (size%1023 ? 1 : 0); + peak_count = bin64_t::peaks(sizek,peaks); + ftruncate( hashfd, sizek*2*Sha1Hash::SIZE + + (sizeof(bin64_t)+Sha1Hash::SIZE)*64 ); + lseek(hashfd,0,SEEK_SET); + write(hashfd,&bin64_t::ALL,sizeof(bin64_t)); + write(hashfd,*root_hash,Sha1Hash::SIZE); + for(int i=0; isize(); } -void p2tp::Close (int fid) { - if (!File::files[fid]) +void FileTransfer::OfferHash (bin64_t pos, const Sha1Hash& hash) { + if (!size) // only peak hashes are accepted at this point + return OfferPeak(pos,hash); + if (pos.base_offset()>=sizek) return; - delete File::files[fid]; - File::files[fid] = NULL; + if (ack_out.get(pos)!=bins::EMPTY) + return; // have this hash already, even accptd data + hashes[pos] = hash; } +bool FileTransfer::OfferData (bin64_t pos, uint8_t* data, size_t length) { + if (pos.layer()!=10) + return false; + if (ack_out.get(pos)==bins::FILLED) + return true; // ??? + int peak=0; + while (peak=last_peak.layer() || + pos.base_offset()!=last_peak.base_offset()+last_peak.width() ) + peak_count = 0; } - + peaks[peak_count] = pos; + peak_hashes[peak_count++] = hash; + // check whether peak hash candidates add up to the root hash + Sha1Hash mustbe_root = DeriveRoot(); + if (hash!=root_hash) + return; + // bingo, we now know the file size (rounded up to a KByte) + SetSize(pos.base_offset()+pos.width()); } -bool FileTransfer::acceptData (uint64_t bin, uint8_t* data, size_t len) { +FileTransfer::~FileTransfer () { + munmap(hashes,sizek*2*Sha1Hash::SIZE); + close(hashfd); + close(fd); +} + +FileTransfer* FileTransfer::Find (const Sha1Hash& root_hash) { + for(int i=0; iroot_hash==root_hash) + return files[i]; + return NULL; } - -HashTree::~HashTree () { - close(fd); +int p2tp::Open (const char* filename) { + return Open(Sha1Hash::ZERO,filename); } -HashTree::hashres_t HashTree::offerPeak (bin pos, Sha1Hash hash) { - if (bin(pos+1).layer()) - return REJECT; - if (bin::all1(pos)) - peaks.clear(); - peaks.push_back(binhash(pos,hash)); - if (deriveRoot()==root) { // bingo - mass = peaks.back().first; - length = mass.length(); - status.resize(mass+1); - bits.resize(mass+1); - for(int i=0; ifd>0) { + if (FileTransfer::files.size()fd) + FileTransfer::files.resize(ft->fd); + FileTransfer::files[ft->fd] = ft; + return ft->fd; + } else { + delete ft; + return -1; + } } -HashTree::hashres_t HashTree::offer (bin pos, const Sha1Hash& hash) { - if (!length) // only peak hashes are accepted at this point - return offerPeak(pos,hash); - if (pos>mass) - return REJECT; - if (status[pos]) - return bits[pos]==hash ? ACCEPT : REJECT; - bits[pos] = hash; - // walk to the nearest proven hash - if (bits[pos.sibling()]==Sha1Hash::ZERO) - return DUNNO; - bin p = pos.parent(); - while (!status[p]) { - bits[p] = Sha1Hash(bits[p.left()],bits[p.right()]); - p = p.parent(); - } - if ( bits[p] == Sha1Hash(bits[p.left()],bits[p.right()]) ) { - for(bin i=pos; i10) { + OfferHash(x.right(), hashes[x.right()]); + if ( ! OfferHash(x.left(), hashes[x.left()]) ) + break; + x = x.left(); + } + + if (x.layer()==10) { + if (recheck_data) { + uint8_t data[1024]; + size_t rd = pread(fd,data,2<<10,x.base_offset()); + if (hashes[x]==Sha1Hash(data,rd)) + ack_out->set(x,bins::FILLED); + // may avoid hashing by checking whether it is zero + // and whether the hash matches hash of zero + } else { + ack_out->set(x,bins::FILLED); + } + } + + while (x.is_right() && x!=peaks[i]) + x = x.parent(); + x = x.sibling(); + } while (x!=end); + } + + */ -- 2.20.1