X-Git-Url: http://p2p-next.cs.pub.ro/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Flibswift%2Fhashtree.cpp;fp=src%2Flibswift%2Fhashtree.cpp;h=17785bf48fe48b8941532fd6ec8b87248444a455;hb=45963a7511531cd1656ad5d3847d2dafd015c54d;hp=0000000000000000000000000000000000000000;hpb=d069796805ad79542fd7e4406d1e9c6d2d8c2ef7;p=swifty.git diff --git a/src/libswift/hashtree.cpp b/src/libswift/hashtree.cpp new file mode 100644 index 0000000..17785bf --- /dev/null +++ b/src/libswift/hashtree.cpp @@ -0,0 +1,589 @@ +/* + * hashtree.cpp + * serp++ + * + * Created by Victor Grishchenko on 3/6/09. + * Copyright 2009-2012 TECHNISCHE UNIVERSITEIT DELFT. All rights reserved. + * + */ + +#include "hashtree.h" +#include "bin_utils.h" +//#include +#include "sha1.h" +#include +#include +#include +#include +#include "compat.h" +#include "swift.h" + +#include + +#ifdef _WIN32 +#define OPENFLAGS O_RDWR|O_CREAT|_O_BINARY +#else +#define OPENFLAGS O_RDWR|O_CREAT +#endif + + +using namespace swift; + +const Sha1Hash Sha1Hash::ZERO = Sha1Hash(); + +void SHA1 (const void *data, size_t length, unsigned char *hash) { + blk_SHA_CTX ctx; + blk_SHA1_Init(&ctx); + blk_SHA1_Update(&ctx, data, length); + blk_SHA1_Final(hash, &ctx); +} + +Sha1Hash::Sha1Hash(const Sha1Hash& left, const Sha1Hash& right) { + blk_SHA_CTX ctx; + blk_SHA1_Init(&ctx); + blk_SHA1_Update(&ctx, left.bits,SIZE); + blk_SHA1_Update(&ctx, right.bits,SIZE); + blk_SHA1_Final(bits, &ctx); +} + +Sha1Hash::Sha1Hash(const char* data, size_t length) { + if (length==-1) + length = strlen(data); + SHA1((unsigned char*)data,length,bits); +} + +Sha1Hash::Sha1Hash(const uint8_t* data, size_t length) { + SHA1(data,length,bits); +} + +Sha1Hash::Sha1Hash(bool hex, const char* hash) { + if (hex) { + int val; + for(int i=0; ihex()==std::string(hash)); + } else + memcpy(bits,hash,SIZE); +} + +std::string Sha1Hash::hex() const { + char hex[HASHSZ*2+1]; + for(int i=0; isize()) + return false; // if no valid peak hashes found + + return true; +} + +int HashTree::serialize(FILE *fp) +{ + fprintf_retiffail(fp,"version %i\n", 1 ); + fprintf_retiffail(fp,"root hash %s\n", root_hash_.hex().c_str() ); + fprintf_retiffail(fp,"chunk size %lu\n", chunk_size_ ); + fprintf_retiffail(fp,"complete %llu\n", complete_ ); + fprintf_retiffail(fp,"completec %llu\n", completec_ ); + return ack_out_.serialize(fp); +} + + +/** Arno: recreate hash tree from .mbinmap file without rereading content. + * Precondition: root hash known + */ +int HashTree::deserialize(FILE *fp) { + return internal_deserialize(fp,true); +} + +int HashTree::partial_deserialize(FILE *fp) { + return internal_deserialize(fp,false); +} + + +int HashTree::internal_deserialize(FILE *fp,bool contentavail) { + + char hexhashstr[256]; + uint64_t c,cc; + size_t cs; + int version; + + fscanf_retiffail(fp,"version %i\n", &version ); + fscanf_retiffail(fp,"root hash %s\n", hexhashstr); + fscanf_retiffail(fp,"chunk size %lu\n", &cs); + fscanf_retiffail(fp,"complete %llu\n", &c ); + fscanf_retiffail(fp,"completec %llu\n", &cc ); + + //fprintf(stderr,"hashtree: deserialize: %s %llu ~ %llu * %i\n", hexhashstr, c, cc, cs ); + + if (ack_out_.deserialize(fp) < 0) + return -1; + root_hash_ = Sha1Hash(true, hexhashstr); + chunk_size_ = cs; + + // Arno, 2012-01-03: Hack to just get root hash + if (!contentavail) + return 2; + + if (!RecoverPeakHashes()) { + root_hash_ = Sha1Hash::ZERO; + ack_out_.clear(); + return -1; + } + + // Are reset by RecoverPeakHashes() for some reason. + complete_ = c; + completec_ = cc; + size_ = file_size(fd_); + sizec_ = (size_ + chunk_size_-1) / chunk_size_; + + return 0; +} + + +bool HashTree::OfferPeakHash (bin_t pos, const Sha1Hash& hash) { + char bin_name_buf[32]; + dprintf("%s hashtree offer peak %s\n",tintstr(),pos.str(bin_name_buf)); + + assert(!size_); + if (peak_count_) { + bin_t last_peak = peaks_[peak_count_-1]; + if ( pos.layer()>=last_peak.layer() || + pos.base_offset()!=last_peak.base_offset()+last_peak.base_length() ) + peak_count_ = 0; + } + peaks_[peak_count_] = pos; + peak_hashes_[peak_count_] = hash; + peak_count_++; + // check whether peak hash candidates add up to the root hash + Sha1Hash mustbe_root = DeriveRoot(); + if (mustbe_root!=root_hash_) + return false; + for(int i=0; isizec_*chunk_size_ ) { + dprintf("%s hashtree offerpeak resizing file\n",tintstr() ); + if (file_resize(fd_, size_)) { + print_error("cannot set file size\n"); + size_=0; // remain in the 0-state + return false; + } + } + + // mmap the hash file into memory + uint64_t expected_size = sizeof(Sha1Hash)*sizec_*2; + // Arno, 2011-10-18: on Windows we could optimize this away, + //CreateFileMapping, see compat.cpp will resize the file for us with + // the right params. + // + if ( file_size(hash_fd_) != expected_size ) { + dprintf("%s hashtree offerpeak resizing hash file\n",tintstr() ); + file_resize (hash_fd_, expected_size); + } + + hashes_ = (Sha1Hash*) memory_map(hash_fd_,expected_size); + if (!hashes_) { + size_ = sizec_ = complete_ = completec_ = 0; + print_error("mmap failed"); + return false; + } + + for(int i=0; i= 0) { + if (p.is_left()) { + p = p.parent(); + hash = Sha1Hash(hash,Sha1Hash::ZERO); + } else { + if (c<0 || peaks_[c]!=p.sibling()) + return Sha1Hash::ZERO; + hash = Sha1Hash(peak_hashes_[c],hash); + p = p.parent(); + c--; + } + } + //fprintf(stderr,"root bin is %lli covers %lli\n", p.toUInt(), p.base_length() ); + return hash; +} + + +/** For live streaming: appends the data, adjusts the tree. + @ return the number of fresh (tail) peak hashes */ +int HashTree::AppendData (char* data, int length) { + return 0; +} + + +bin_t HashTree::peak_for (bin_t pos) const { + int pi=0; + while (pi