in progress
[swift-upb.git] / transfer.cpp
1 /*
2  *  transfer.cpp
3  *  p2tp
4  *
5  *  Created by Victor Grishchenko on 10/6/09.
6  *  Copyright 2009 Delft Technical University. All rights reserved.
7  *
8  */
9
10 #include "p2tp.h"
11
12
13 File::File (int _fd) : fd(_fd), status_(DONE), hashes(_fd)
14 {
15         bin::vec peaks = bin::peaks(hashes.data_size());
16         history.insert(history.end(),peaks.begin(),peaks.end());
17         for(bin::vec::iterator i=peaks.begin(); i!=peaks.end(); i++)
18                 ack_out.set(*i);
19 }
20
21 File::File (Sha1Hash hash, int _fd) : hashes(hash), fd(_fd), status_(EMPTY) {
22         // TODO resubmit data
23 }
24
25 File::~File() {
26         if (fd>0) ::close(fd);
27 }
28
29
30 bool    File::OfferHash (bin pos, const Sha1Hash& hash) {
31         HashTree::hashres_t res = hashes.offer(pos,hash);
32         if (res==HashTree::PEAK_ACCEPT) { // file size is finally known
33                 ftruncate(fd, size());
34                 LOG(INFO)<<fd<<" file size is set to "<<size();
35                 history.push_back(0);
36                 status_ = IN_PROGRESS;
37         }
38         return res==HashTree::PEAK_ACCEPT || res==HashTree::ACCEPT;
39 }
40
41
42 File*   File::find (const Sha1Hash& hash) {
43         for(vector<File*>::iterator i=files.begin(); i!=files.end(); i++)
44                 if (*i && (*i)->hashes.root==hash)
45                         return *i;
46         return NULL;
47 }
48
49
50 int p2tp::Open (const char* filename) {
51         int fd = ::open(filename,O_RDONLY);
52         if (fd<0)
53                 return -1;
54         if (File::files.size()<fd+1)
55                 File::files.resize(fd+1);
56         File::files[fd] = new File(fd);
57         return fd;
58 }
59
60 int p2tp::Open (const Sha1Hash& root_hash, const char* filename) {
61         int fd = ::open(filename,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
62         if (fd<0)
63                 return -1;
64         if (File::files.size()<fd+1)
65                 File::files.resize(fd+1);
66         File::files[fd] = new File(root_hash,fd);
67         return fd;
68 }
69
70 size_t  p2tp::file_size (int fd) { return File::file(fd)->size(); }
71
72 void p2tp::Close (int fid) {
73         if (!File::files[fid])
74                 return;
75         delete File::files[fid];
76         File::files[fid] = NULL;
77 }
78
79
80 Sha1Hash HashTree::deriveRoot () {
81         int i = peak_count-1;
82         bin64_t p = peaks[i].first;
83         Sha1Hash hash = peak_hashes[i].second;
84         i--;
85         while (p<bin64_t::ALL) {
86                 if (p.is_left()) {
87                         p = p.parent();
88                         hash = Sha1Hash(hash,Sha1Hash::ZERO);
89                 } else {
90                         if (i<0 || peaks[i].first!=p.sibling())
91                                 return Sha1Hash::ZERO;
92                         hash = Sha1Hash(peak_hashes[i].second,hash);
93                         p = p.parent();
94                         i--;
95                 }
96         }
97         return hash;
98 }
99
100 /** Three stages: have file, have root hash, have peaks. */
101 HashTree::HashTree (int _datafd, int _hashfd, Sha1Hash _root)
102 : datafd(_datafd), hashfd(_hashfd), root(_root) 
103 {
104     if (root==Sha1Hash::ZERO) { // fresh file; derive the root hash
105         struct stat st;
106         if (fstat(fd, &st)!=0)
107             return;
108         resize(st.st_size);
109         lseek(datafd,0,SEEK_SET);
110         for(bin64_t k=0; k!=toppeak.right(); k=k.dfs_next()) {
111             if (k.is_base()) {
112                 uint8_t data[1024];
113                 int rd = read(datafd,data,1024);
114                 if (rd<=0)
115                     return; // FIXME
116                 hashes[k] = Sha1Hash(data,rd);
117             } else
118                 hashes[k] = Sha1Hash(hashes[k.left()],hashes[k.right()]);
119         }
120         // zeros
121         root = hashes[toppeak];
122         for(bin64_t p=toppeak; p!=bin64_t::ALL; p=p.parent())
123             root = Sha1Hash(root,Sha1Hash::ZERO);
124     }
125     // TODO:  THIS MUST BE THE "Transfer"/"File" CLASS
126     if (file_size==0) { // hash only, no file, no peak hashes
127         if (root==Sha1Hash::ZERO)
128             return; // FIXME
129         resize(0); // anyway, 1cell for the root, 63 for peaks
130     }
131     
132 }
133
134 bool FileTransfer::acceptData (uint64_t bin, uint8_t* data, size_t len) {
135 }
136
137
138 HashTree::~HashTree () {
139         close(fd);
140 }
141
142 HashTree::hashres_t     HashTree::offerPeak (bin pos, Sha1Hash hash) {
143         if (bin(pos+1).layer())
144                 return REJECT;
145         if (bin::all1(pos))
146                 peaks.clear();
147         peaks.push_back(binhash(pos,hash));
148         if (deriveRoot()==root) { // bingo
149                 mass = peaks.back().first;
150                 length = mass.length();
151                 status.resize(mass+1);
152                 bits.resize(mass+1);
153                 for(int i=0; i<peaks.size(); i++) {
154                         bits[peaks[i].first] = peaks[i].second;
155                         status[peaks[i].first] = true;
156                 }
157                 return PEAK_ACCEPT;
158         } else
159                 return pos.layer() ? DUNNO : REJECT;
160 }
161
162 HashTree::hashres_t     HashTree::offer (bin pos, const Sha1Hash& hash) {
163         if (!length)  // only peak hashes are accepted at this point
164                 return offerPeak(pos,hash);
165         if (pos>mass)
166                 return REJECT;
167         if (status[pos])
168                 return bits[pos]==hash ? ACCEPT : REJECT;
169         bits[pos] = hash;
170         // walk to the nearest proven hash
171         if (bits[pos.sibling()]==Sha1Hash::ZERO)
172                 return DUNNO;
173         bin p = pos.parent();
174         while (!status[p]) {
175                 bits[p] = Sha1Hash(bits[p.left()],bits[p.right()]);
176                 p = p.parent();
177         }
178         if ( bits[p] == Sha1Hash(bits[p.left()],bits[p.right()]) ) {
179                 for(bin i=pos; i<p; i=i.parent())
180                         status[i] = status[i.sibling()] = true;
181                 return ACCEPT;
182         } else
183                 return REJECT;
184         
185 }
186
187
188