From: victor Date: Mon, 9 Nov 2009 13:34:57 +0000 (+0000) Subject: prettified, Windows build broken X-Git-Url: http://p2p-next.cs.pub.ro/gitweb/?a=commitdiff_plain;h=37d814920656ef322a366b2f6bb26417fe8a55d7;p=swift-upb.git prettified, Windows build broken git-svn-id: https://ttuki.vtt.fi/svn/p2p-next/TUD/p2tp/trunk@511 e16421f0-f15b-0410-abcd-98678b794739 --- diff --git a/bins.cpp b/bins.cpp index 3be3d68..ca3616f 100644 --- a/bins.cpp +++ b/bins.cpp @@ -37,7 +37,8 @@ bins::bins() : height(4), blocks_allocated(0), cells(NULL), } void bins::twist (uint64_t mask) { - assert( (1< mask ); + while ( (1< #endif #include "datagram.h" +#include "compat.h" namespace p2tp { @@ -126,10 +127,10 @@ SOCKET Datagram::Wait (int sockcnt, SOCKET* sockets, tint usec) { } tint Datagram::Time () { - HiResTimeOfDay* tod = HiResTimeOfDay::Instance(); - tint ret = tod->getTimeUSec(); + //HiResTimeOfDay* tod = HiResTimeOfDay::Instance(); + //tint ret = tod->getTimeUSec(); //DLOG(INFO)<<"now is "<=5) + bindaddr = Address(args[4]); + else + bindaddr = Address(INADDR_ANY,rand()%10000+7000); assert(0 #include -#ifndef _WIN32 -#include -#endif -#include #include #include +#include "compat.h" -using namespace std; +using namespace p2tp; #define HASHSZ 20 const size_t Sha1Hash::SIZE = HASHSZ; const Sha1Hash Sha1Hash::ZERO = Sha1Hash(); Sha1Hash::Sha1Hash(const Sha1Hash& left, const Sha1Hash& right) { - uint8_t data[HASHSZ*2]; + char data[HASHSZ*2]; memcpy(data,left.bits,SIZE); memcpy(data+SIZE,right.bits,SIZE); - SHA1(data,SIZE*2,bits); + SHA1((unsigned char*)data,SIZE*2,bits); } -Sha1Hash::Sha1Hash(const uint8_t* data, size_t length) { - SHA1(data,length,bits); +Sha1Hash::Sha1Hash(const char* data, size_t length) { + if (length==-1) + length = strlen(data); + SHA1((unsigned char*)data,length,bits); } -Sha1Hash::Sha1Hash(const char* str) { - SHA1((const unsigned char*)str,strlen(str),bits); +Sha1Hash::Sha1Hash(const uint8_t* data, size_t length) { + SHA1(data,length,bits); } Sha1Hash::Sha1Hash(bool hex, const char* hash) { @@ -47,129 +46,275 @@ Sha1Hash::Sha1Hash(bool hex, const char* hash) { sscanf(hx, "%x", &val); bits[i] = val; } - assert(this->hex()==string(hash)); + assert(this->hex()==std::string(hash)); } else memcpy(bits,hash,SIZE); } -string Sha1Hash::hex() const { +std::string Sha1Hash::hex() const { char hex[HASHSZ*2+1]; for(int i=0; i>10) + ((size_&1023) ? 1 : 0); + peak_count_ = bin64_t::peaks(sizek_,peaks_); + int hashes_size = Sha1Hash::SIZE*sizek_*2; + file_resize(hash_fd_,hashes_size); + hashes_ = (Sha1Hash*) memory_map(hash_fd_,hashes_size); + if (!hashes_) { + size_ = sizek_ = complete_ = completek_ = 0; + print_error("mmap failed"); + return; + } + for (size_t i=0; i>10) + ((size&1023) ? 1 : 0); + bin64_t peaks[64]; + int peak_count = bin64_t::peaks(sizek,peaks); + for(int i=0; isize()) + return; // if no valid peak hashes found + // at this point, we may use mmapd hashes already + // so, lets verify hashes and the data we've got + char zeros[1<<10]; + memset(zeros, 0, 1<<10); + Sha1Hash kilo_zero(zeros,1<<10); + for(int p=0; p=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; + 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; i>10) + ((size_&1023) ? 1 : 0); + + // FIXME check tail here + if (file_size(fd_)!=size_) + 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 + size_t expected_size = sizeof(Sha1Hash)*sizek_*2; + if ( file_size(hash_fd_) != expected_size ) + file_resize (hash_fd_, expected_size); + + hashes_ = (Sha1Hash*) memory_map(hash_fd_,expected_size); + if (!hashes_) { + size_ = sizek_ = complete_ = completek_ = 0; + print_error("mmap failed"); + return false; + } + + for(int i=0; i>10) + (st.st_size%1024 ? 1 : 0); - mass = bin::lenpeak(length); // incorrect - bits.resize(mass+1); - status.resize(mass+1); - uint8_t buf[1024]; - for(bin i=1; i<=mass; i++) - if (i.layer()) { - bits[i] = Sha1Hash(bits[i.left()],bits[i.right()]); - } else { - int len = pread(fd,buf,1024,i.offset()<<10); - bits[i] = Sha1Hash(buf,len); - } - //close(fd); - bin::vec p = bin::peaks(length); - while(p.size()) { - peaks.push_back(binhash(p.front(),bits[p.front()])); - p.pop_front(); - } - root = deriveRoot(); + +/** 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; } -HashTree::HashTree (const Sha1Hash& with_root) : root(with_root), length(0), mass(0) { - // recover the partially filled hash file - // first, size - // then, peaks - // works? then offer the rest + +bin64_t HashTree::peak_for (bin64_t pos) const { + int pi=0; + while (pimass) - 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; i #include -#include + +namespace p2tp { + struct Sha1Hash { uint8_t bits[20]; Sha1Hash() { memset(bits,0,20); } Sha1Hash(const Sha1Hash& left, const Sha1Hash& right); - Sha1Hash(const uint8_t* bits, size_t length); - /***/ - Sha1Hash(const char* bits); + Sha1Hash(const char* str, size_t length=-1); + Sha1Hash(const uint8_t* data, size_t length); Sha1Hash(bool hex, const char* hash); std::string hex() const; @@ -33,42 +35,72 @@ struct Sha1Hash { const static size_t SIZE; }; -/* -typedef std::pair binhash; -struct HashTree { - Sha1Hash root; - int fd; - bin mass; - uint32_t length; - std::vector status; - std::vector bits; - std::vector peaks; - typedef enum { ACCEPT, DUNNO, PEAK_ACCEPT, REJECT } hashres_t; +class HashTree { + + /** Merkle hash tree: root */ + Sha1Hash root_hash_; + Sha1Hash *hashes_; + /** Merkle hash tree: peak hashes */ + Sha1Hash peak_hashes_[64]; + bin64_t peaks_[64]; + int peak_count_; + /** File descriptor to put hashes to */ + int fd_; + int hash_fd_; + /** Whether to re-hash files. */ + bool data_recheck_; + /** Base size, as derived from the hashes. */ + size_t size_; + size_t sizek_; + /** Part of the tree currently checked. */ + size_t complete_; + size_t completek_; + bins ack_out_; + protected: - Sha1Hash deriveRoot(); - hashres_t offerPeak (bin pos, Sha1Hash hash); + + void Submit(); + void RecoverProgress(); + Sha1Hash DeriveRoot(); + bool OfferPeakHash (bin64_t pos, const Sha1Hash& hash); + public: - HashTree (int fd); - HashTree (const Sha1Hash& root); + HashTree (const char* file_name, const Sha1Hash& root=Sha1Hash::ZERO, + const char* hash_filename=NULL); + + /** 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); + /** Offer data; the behavior is the same as with a hash: + accept or remember or drop. Returns true => ACK is sent. */ + bool OfferData (bin64_t bin, const char* data, size_t length); + /** Not implemented yet. */ + int AppendData (char* data, int length) ; + + int file_descriptor () const { return fd_; } + int peak_count () const { return peak_count_; } + bin64_t peak (int i) const { return peaks_[i]; } + const Sha1Hash& peak_hash (int i) const { return peak_hashes_[i]; } + bin64_t peak_for (bin64_t pos) const; + const Sha1Hash& hash (bin64_t pos) const {return hashes_[pos];} + const Sha1Hash& root_hash () const { return root_hash_; } + uint64_t size () const { return size_; } + uint64_t size_kilo () const { return sizek_; } + uint64_t complete () const { return complete_; } + uint64_t complete_kilo () const { return completek_; } + uint64_t seq_complete () ; + bool is_complete () + { return size_ && seq_complete()==size_; } + bins& ack_out () { return ack_out_; } ~HashTree (); - hashres_t offer (bin pos, const Sha1Hash& hash); - - bool rooted () const { return length>0; } - - const Sha1Hash& operator [] (bin i) { - return i<=mass ? bits[i] : Sha1Hash::ZERO; - } - uint32_t data_size () const { return length; } - - bin data_mass () const { return mass; } - - const std::vector& peak_hashes() const { return peaks; } - -};*/ +}; + +} #endif diff --git a/p2tp.cpp b/p2tp.cpp index fea73a6..70a9b21 100644 --- a/p2tp.cpp +++ b/p2tp.cpp @@ -34,8 +34,8 @@ tbqueue Channel::send_queue; #include "ext/simple_selector.cpp" PeerSelector* Channel::peer_selector = new SimpleSelector(); -Channel::Channel (FileTransfer* file, int socket, Address peer_addr) : - file_(file), peer_(peer_addr), peer_channel_id_(0), pex_out_(0), +Channel::Channel (FileTransfer* transfer, int socket, Address peer_addr) : + transfer_(transfer), peer_(peer_addr), peer_channel_id_(0), pex_out_(0), socket_(socket==-1?sockets[0]:socket), // FIXME own_id_mentioned_(false), next_send_time_(0), last_send_time_(0), last_recv_time_(0), rtt_avg_(TINT_SEC), dev_avg_(0), dip_avg_(TINT_SEC) @@ -91,7 +91,7 @@ void p2tp::Loop (tint till) { int p2tp::Open (const char* filename, const Sha1Hash& hash) { FileTransfer* ft = new FileTransfer(filename, hash); - int fdes = ft->file_descriptor(); + int fdes = ft->file().file_descriptor(); if (fdes>0) { /*if (FileTransfer::files.size()fdes && FileTransfer::files[fdes]) - return FileTransfer::files[fdes]->size(); + return FileTransfer::files[fdes]->file().size(); else return 0; } @@ -132,7 +132,7 @@ size_t p2tp::Size (int fdes) { size_t p2tp::Complete (int fdes) { if (FileTransfer::files.size()>fdes && FileTransfer::files[fdes]) - return FileTransfer::files[fdes]->is_complete(); + return FileTransfer::files[fdes]->file().is_complete(); else return 0; } @@ -140,7 +140,7 @@ size_t p2tp::Complete (int fdes) { size_t p2tp::SeqComplete (int fdes) { if (FileTransfer::files.size()>fdes && FileTransfer::files[fdes]) - return FileTransfer::files[fdes]->seq_complete(); + return FileTransfer::files[fdes]->file().seq_complete(); else return 0; } @@ -150,7 +150,7 @@ const Sha1Hash& p2tp::RootMerkleHash (int file) { FileTransfer* trans = FileTransfer::file(file); if (!trans) return Sha1Hash::ZERO; - return trans->root_hash(); + return trans->file().root_hash(); } diff --git a/p2tp.h b/p2tp.h index 589a7e5..5e8b5c7 100644 --- a/p2tp.h +++ b/p2tp.h @@ -105,13 +105,6 @@ namespace p2tp { /** 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. */ - void OfferHash (bin64_t pos, const Sha1Hash& hash); - /** Offer data; the behavior is the same as with a hash: - accept or remember or drop. Returns true => ACK is sent. */ - bool OfferData (bin64_t bin, const uint8_t* data, size_t length); /** While we need to feed ACKs to every peer, we try (1) avoid unnecessary duplication and (2) keep minimum state. Thus, @@ -125,83 +118,33 @@ namespace p2tp { return fd files; - static std::string GetTempFilename(Sha1Hash& root_hash, int instance, std::string postfix); - - /** file descriptor. */ - int fd_; - /** File size, as derived from the hashes. */ - size_t size_; - size_t sizek_; - /** Part the file currently downloaded. */ - size_t complete_; - size_t completek_; - size_t seq_complete_; - /** A binmap for all packets obtained and succesfully checked. */ - bins ack_out_; - /** History of bin retrieval. */ - //binqueue data_in_; - //int data_in_off_; + + HashTree file_; + /** Piece picker strategy. */ PiecePicker* picker_; - /** File for keeping the Merkle hash tree. */ - int hashfd_; -#ifdef _WIN32 - HANDLE hashmaphandle_; -#endif - /** Merkle hash tree: root */ - Sha1Hash root_hash_; - /** Merkle hash tree: 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_; - /** Error encountered */ - char* error_; - + /** Channels working for this transfer. */ binqueue hs_in_; int hs_in_offset_; std::deque
pex_in_; + /** Messages we are accepting. */ uint64_t cap_out_; protected: - void SetSize(size_t bytes); - void Submit(); - void RecoverProgress(); - void OfferPeak (bin64_t pos, const Sha1Hash& hash); - Sha1Hash DeriveRoot(); - void SavePeaks(); - void LoadPeaks(); void OnDataIn (bin64_t pos); void OnPexIn (const Address& addr); @@ -277,7 +220,8 @@ namespace p2tp { const std::string id_string () const; /** A channel is "established" if had already sent and received packets. */ bool is_established () { return peer_channel_id_ && own_id_mentioned_; } - FileTransfer& file() { return *file_; } + FileTransfer& transfer() { return *transfer_; } + HashTree& file () { return transfer_->file(); } const Address& peer() const { return peer_; } static int DecodeID(int scrambled); @@ -294,7 +238,7 @@ namespace p2tp { /** The UDP socket fd. */ int socket_; /** Descriptor of the file in question. */ - FileTransfer* file_; + FileTransfer* transfer_; /** Peer channel id; zero if we are trying to open a channel. */ uint32_t peer_channel_id_; bool own_id_mentioned_; diff --git a/sendrecv.cpp b/sendrecv.cpp index a01d853..a3ca654 100644 --- a/sendrecv.cpp +++ b/sendrecv.cpp @@ -173,10 +173,10 @@ void Channel::AddHint (Datagram& dgram) { if ( 4*peer_cwnd > hinted ) { //hinted*1024 < peer_cwnd*4 ) { uint8_t layer = 2; // actually, enough - bin64_t hint = file().picker().Pick(ack_in_,layer); + bin64_t hint = transfer().picker().Pick(ack_in_,layer); // FIXME FIXME FIXME: any layer if (hint==bin64_t::NONE) - hint = file().picker().Pick(ack_in_,0); + hint = transfer().picker().Pick(ack_in_,0); if (hint!=bin64_t::NONE) { hint_out_.push_back(hint); @@ -256,7 +256,7 @@ void Channel::Recv (Datagram& dgram) { rtt_avg_ = NOW - last_send_time_; dev_avg_ = rtt_avg_; dip_avg_ = rtt_avg_; - file_->hs_in_.push_back(id); + transfer().hs_in_.push_back(id); dprintf("%s #%i rtt init %lli\n",tintstr(),id,rtt_avg_); } bin64_t data = dgram.size() ? bin64_t::NONE : bin64_t::ALL; @@ -295,7 +295,7 @@ bin64_t Channel::OnData (Datagram& dgram) { bin64_t pos = dgram.Pull32(); uint8_t *data; int length = dgram.Pull(&data,1024); - bool ok = file().OfferData(pos, data, length) ; + bool ok = file().OfferData(pos, (char*)data, length) ; dprintf("%s #%i %cdata (%lli)\n",tintstr(),id,ok?'-':'!',pos.offset()); if (ok) { data_in_ = tintbin(NOW,pos); @@ -365,12 +365,12 @@ void Channel::OnPex (Datagram& dgram) { uint16_t port = dgram.Pull16(); Address addr(ipv4,port); dprintf("%s #%i -pex %s\n",tintstr(),id,addr.str().c_str()); - file_->OnPexIn(addr); + transfer().OnPexIn(addr); } void Channel::AddPex (Datagram& dgram) { - int chid = file_->RevealChannel(pex_out_); + int chid = transfer().RevealChannel(pex_out_); if (chid==-1 || chid==id) return; Address a = channels[chid]->peer(); @@ -395,7 +395,7 @@ void Channel::Recv (int socket) { uint8_t hashid = data.Pull8(); if (hashid!=P2TP_HASH) RETLOG ("no hash in the initial handshake"); - bin pos = data.Pull32(); + bin64_t pos = data.Pull32(); if (pos!=bin64_t::ALL32) RETLOG ("that is not the root hash"); hash = data.PullHash(); diff --git a/tests/binstest2.cpp b/tests/binstest2.cpp index cb3950c..99b7078 100755 --- a/tests/binstest2.cpp +++ b/tests/binstest2.cpp @@ -303,6 +303,15 @@ TEST(BinsTest,Twist) { EXPECT_EQ(bins::EMPTY,b.get(bin64_t(3,3))); } +TEST(BinsTest,SeqLength) { + bins b; + b.set(bin64_t(3,0)); + b.set(bin64_t(1,4)); + b.set(bin64_t(0,10)); + b.set(bin64_t(3,2)); + EXPECT_EQ(11,b.seq_length()); +} + TEST(BinheapTest,Eat) { binheap b; diff --git a/tests/hashtest.cpp b/tests/hashtest.cpp index a0d16ae..d0812e6 100644 --- a/tests/hashtest.cpp +++ b/tests/hashtest.cpp @@ -7,29 +7,48 @@ * */ #include -#include "bin.h" +#include "bin64.h" #include #include "hashtree.h" +using namespace p2tp; + char hash123[] = "a8fdc205a9f19cc1c7507a60c4f01b13d11d7fd0"; -//char roothash123[] = "84e1e5f4b549fe072d803709eeb06143cd2ad736"; +char rooth123[] = "d0bdb8ba28076d84d2b3a0e62521b998e42349a1"; TEST(Sha1HashTest,Trivial) { Sha1Hash hash("123\n"); EXPECT_STREQ(hash123,hash.hex().c_str()); } -/* -TEST(Sha1HashTest,HashTreeTest) { - Sha1Hash roothash123(hash123); - for(bin pos=1; pos //#include #include "p2tp.h" -#include "compat/util.h" -#ifdef _MSC_VER -#include "compat/unixio.h" -#endif +#include "compat.h" using namespace p2tp; -const char* BTF = "big_test_file"; +const char* BTF = "test_file"; Sha1Hash A,B,C,D,E,AB,CD,ABCD,E0,E000,ABCDE000,ROOT; @@ -34,9 +31,11 @@ TEST(TransferTest,TransferFile) { ROOT = Sha1Hash(ROOT,Sha1Hash::ZERO); //printf("m %lli %s\n",(uint64_t)pos.parent(),ROOT.hex().c_str()); } - - // submit a new file - FileTransfer* seed = new FileTransfer(BTF); + + // now, submit a new file + + FileTransfer* seed_transfer = new FileTransfer(BTF); + HashTree* seed = & seed_transfer->file(); EXPECT_TRUE(A==seed->hash(0)); EXPECT_TRUE(E==seed->hash(bin64_t(0,4))); EXPECT_TRUE(ABCD==seed->hash(bin64_t(2,0))); @@ -52,8 +51,9 @@ TEST(TransferTest,TransferFile) { // retrieve it unlink("copy"); FileTransfer::instance = 1; - FileTransfer* leech = new FileTransfer("copy",seed->root_hash()); - leech->picker().Randomize(0); + FileTransfer* leech_transfer = new FileTransfer("copy",seed->root_hash()); + HashTree* leech = & leech_transfer->file(); + leech_transfer->picker().Randomize(0); // transfer peak hashes for(int i=0; ipeak_count(); i++) leech->OfferHash(seed->peak(i),seed->peak_hash(i)); @@ -68,13 +68,14 @@ TEST(TransferTest,TransferFile) { leech->OfferHash(bin64_t(1,1), seed->hash(bin64_t(1,1))); for (int i=0; i<5; i++) { if (i==2) { // now: stop, save, start - delete leech; + delete leech_transfer; FileTransfer::instance = 1; - leech = new FileTransfer("copy",seed->root_hash()); - leech->picker().Randomize(0); + leech_transfer = new FileTransfer("copy",seed->root_hash()); + leech = & leech_transfer->file(); + leech_transfer->picker().Randomize(0); EXPECT_EQ(2,leech->complete_kilo()); } - bin64_t next = leech->picker().Pick(seed->ack_out(),0); + bin64_t next = leech_transfer->picker().Pick(seed->ack_out(),0); ASSERT_NE(bin64_t::NONE,next); ASSERT_TRUE(next.base_offset()<5); uint8_t buf[1024]; //size_t len = seed->storer->ReadData(next,&buf); @@ -84,9 +85,9 @@ TEST(TransferTest,TransferFile) { leech->OfferHash(sibling, seed->hash(sibling)); uint8_t memo = *buf; *buf = 'z'; - EXPECT_FALSE(leech->OfferData(next, buf, len)); + EXPECT_FALSE(leech->OfferData(next, (char*)buf, len)); *buf = memo; - EXPECT_TRUE(leech->OfferData(next, buf, len)); + EXPECT_TRUE(leech->OfferData(next, (char*)buf, len)); } EXPECT_EQ(4100,leech->size()); EXPECT_EQ(5,leech->size_kilo()); @@ -101,16 +102,10 @@ TEST(TransferTest,TransferFile) { int main (int argc, char** argv) { - std::string tempdir = gettmpdir(); - unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.0.hashes")).c_str()); - unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.0.peaks")).c_str()); - unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.1.hashes")).c_str()); - unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.1.peaks")).c_str()); - unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.2.hashes")).c_str()); - unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.2.peaks")).c_str()); - - unlink(BTF); + unlink("test_file"); unlink("copy"); + unlink("test_file.mhash"); + unlink("copy.mhash"); int f = open(BTF,O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (f < 0) diff --git a/transfer.cpp b/transfer.cpp index 4ae31b8..c26cef6 100644 --- a/transfer.cpp +++ b/transfer.cpp @@ -29,306 +29,22 @@ int FileTransfer::instance = 0; // FIXME: separate Bootstrap() and Download(), then Size(), Progress(), SeqProgress() FileTransfer::FileTransfer (const char* filename, const Sha1Hash& _root_hash) : - root_hash_(_root_hash), fd_(0), hashfd_(0), dry_run_(false), - peak_count_(0), hashes_(NULL), error_(NULL), size_(0), sizek_(0), - complete_(0), completek_(0), seq_complete_(0), hs_in_offset_(0) + file_(filename,_root_hash), hs_in_offset_(0) { - fd_ = open(filename,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - if (fd_<0) - return; - if (files.size()Randomize(rand()&31&(file_.peak(0).width()-1)); } -void FileTransfer::LoadPeaks () { - std::string file_name = GetTempFilename(root_hash_,instance,std::string(".peaks")); - int peakfd = open(file_name.c_str(),O_RDONLY,0); - if (peakfd<0) - return; - bin64_t peak; - char hash[128]; - while (sizeof(bin64_t)==read(peakfd,&peak,sizeof(bin64_t))) { - read(peakfd,hash,Sha1Hash::SIZE); - OfferPeak(peak, Sha1Hash(false,hash)); - } - close(peakfd); -} - - -/** Basically, simulated receiving every single packet, except - for some optimizations. */ -void FileTransfer::RecoverProgress () { - dry_run_ = true; - LoadPeaks(); - if (!size()) - return; - // at this point, we may use mmapd hashes already - // so, lets verify hashes and the data we've got - lseek(fd_,0,SEEK_SET); - for(int p=0; p>10) + ((size_&1023) ? 1 : 0); - - struct stat st; - fstat(fd_, &st); - if (st.st_size!=bytes) - if (ftruncate(fd_, bytes)) - return; // remain in the 0-state - // mmap the hash file into memory - std::string file_name = GetTempFilename(root_hash_,instance,std::string(".hashes")); - hashfd_ = open(file_name.c_str(),O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - size_t expected_size_ = Sha1Hash::SIZE * sizek_ * 2; - struct stat hash_file_st; - fstat(hashfd_, &hash_file_st); - if ( hash_file_st.st_size != expected_size_ ) - ftruncate(hashfd_, expected_size_); -#ifdef _WIN32 - HANDLE hashhandle = (HANDLE)_get_osfhandle(hashfd_); - hashmaphandle_ = CreateFileMapping(hashhandle, - NULL, - PAGE_READWRITE, - 0, - 0, - NULL); - if (hashmaphandle_ != NULL) - { - hashes_ = (Sha1Hash*)MapViewOfFile(hashmaphandle_, - FILE_MAP_WRITE, - 0, - 0, - 0); - - } - if (hashmaphandle_ == NULL || hashes_ == NULL) -#else - hashes_ = (Sha1Hash*) mmap (NULL, expected_size_, PROT_READ|PROT_WRITE, - MAP_SHARED, hashfd_, 0); - if (hashes_==MAP_FAILED) -#endif - { - hashes_ = NULL; - size_ = sizek_ = complete_ = completek_ = seq_complete_ = 0; - error_ = strerror(errno); // FIXME dprintf() - perror("hash tree mmap failed"); - return; - } - for(int i=0; iRandomize(rand()&31&(sizek_-1)); -} - - -void FileTransfer::Submit () { - struct stat st; // TODO: AppendData() and streaming - fstat(fd_, &st); - size_ = st.st_size; - sizek_ = (size_>>10) + ((size_&1023) ? 1 : 0); - hashes_ = (Sha1Hash*) malloc(Sha1Hash::SIZE*sizek_*2); - peak_count_ = bin64_t::peaks(sizek_,peaks_); - for (int p=0; p>10))==bins::FILLED) - seq_complete_+=1024; - if (seq_complete_>size_) - seq_complete_ = size_; - return true; -} - - -/*bin64_t FileTransfer::RevealAck (uint64_t& offset) { - if (offset=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 (mustbe_root!=root_hash_) - return; - // bingo, we now know the file size (rounded up to a KByte) - SetSize( (pos.base_offset()+pos.width()) << 10 ); - SavePeaks(); -} - FileTransfer::~FileTransfer () { -#ifdef _WIN32 - UnmapViewOfFile(hashes_); - CloseHandle(hashmaphandle_); -#else - munmap(hashes_,sizek_*2*Sha1Hash::SIZE); - close(hashfd_); - close(fd_); - files[fd_] = NULL; -#endif + + files[fd()] = NULL; } @@ -340,35 +56,10 @@ FileTransfer* FileTransfer::Find (const Sha1Hash& root_hash) { } -std::string FileTransfer::GetTempFilename(Sha1Hash& root_hash, int instance, std::string postfix) -{ - std::string tempfile = gettmpdir(); - std::stringstream ss; - ss << instance; - tempfile += std::string(".") + root_hash.hex() + std::string(".") + ss.str() + postfix; - return tempfile; -} - - -/*int p2tp::Open (const char* filename, const Sha1Hash& hash) { - FileTransfer* ft = new FileTransfer(filename, hash); - int fdes = ft->file_descriptor(); - if (fdes>0) { - if (FileTransfer::files.size()file_==this && c->peer_==addr) + if (c && c->transfer().fd()==this->fd() && c->peer_==addr) return; // already connected } if (hs_in_.size()<20) { @@ -387,7 +78,7 @@ int FileTransfer::RevealChannel (int& pex_out_) { pex_out_ = 0; while (pex_out_file_==this) { + if (c && c->transfer().fd()==this->fd()) { pex_out_ += hs_in_offset_ + 1; return c->id; } else { @@ -400,65 +91,3 @@ int FileTransfer::RevealChannel (int& pex_out_) { return -1; } - -/* - for(int i=0; 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); - } - - - - - // open file - 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; - - - */