1 /*
2 * zerostate.cpp
3 * manager for starting on-demand transfers that serve content and hashes
4 * directly from disk (so little state in memory). Requires content (named
5 * as roothash-in-hex), hashes (roothash-in-hex.mhash file) and checkpoint
6 * (roothash-in-hex.mbinmap) to be present on disk.
7 *
8 * Note: currently zero-state implementations do not respond to PEX_REQ,
9 * there is no tracker functionality.
10 *
11 * Created by Arno Bakker
12 * Copyright 2009-2016 TECHNISCHE UNIVERSITEIT DELFT. All rights reserved.
13 *
14 */
15 #include "swift.h"
16 #include "compat.h"
17
18 using namespace swift;
19
20
21 ZeroState * ZeroState::__singleton = NULL;
22
23 #define CLEANUP_INTERVAL 30 // seconds
24
ZeroState()25 ZeroState::ZeroState() : contentdir_("."), metadir_(""), connect_timeout_(TINT_NEVER)
26 {
27 if (__singleton == NULL) {
28 __singleton = this;
29 }
30
31 //fprintf(stderr,"ZeroState: registering clean up\n");
32 evtimer_assign(&evclean_,Channel::evbase,&ZeroState::LibeventCleanCallback,this);
33 evtimer_add(&evclean_,tint2tv(CLEANUP_INTERVAL*TINT_SEC));
34 }
35
36
~ZeroState()37 ZeroState::~ZeroState()
38 {
39 //fprintf(stderr,"ZeroState: deconstructor\n");
40
41 // Arno, 2012-02-06: Cancel cleanup timer, otherwise chaos!
42 evtimer_del(&evclean_);
43 }
44
45
LibeventCleanCallback(int fd,short event,void * arg)46 void ZeroState::LibeventCleanCallback(int fd, short event, void *arg)
47 {
48 //fprintf(stderr,"zero clean: enter\n");
49
50 // Arno, 2012-02-24: Why-oh-why, update NOW
51 Channel::Time();
52
53 ZeroState *zs = (ZeroState *)arg;
54 if (zs == NULL)
55 return;
56
57 // See which zero state FileTransfers have no clients
58 tdlist_t tds = swift::GetTransferDescriptors();
59 tdlist_t::iterator iter;
60 tdlist_t delset;
61 for (iter = tds.begin(); iter != tds.end(); iter++) {
62 int td = *iter;
63
64 if (!swift::IsZeroState(td))
65 continue;
66
67 ContentTransfer *ct = swift::GetActivatedTransfer(td);
68 if (ct == NULL) {
69 // Not activated, so remove in any case
70 delset.push_back(td);
71 continue;
72 }
73
74 // Arno, 2012-09-20: Work with copy of list, as "delete c" edits list.
75 channels_t copychans(*ct->GetChannels());
76 if (copychans.size() == 0)
77 delset.push_back(td);
78 else if (zs->connect_timeout_ != TINT_NEVER) {
79 // Garbage collect really slow connections, essential on Mac.
80 dprintf("%s zero clean %s has " PRISIZET " peers\n",tintstr(),ct->swarm_id().hex().c_str(), ct->GetChannels()->size());
81 channels_t::iterator iter2;
82 for (iter2=copychans.begin(); iter2!=copychans.end(); iter2++) {
83 Channel *c = *iter2;
84 if (c != NULL) {
85 //fprintf(stderr,"%s F%" PRIu32 " zero clean %s opentime %" PRIi64 " connect %" PRIi64 "\n",tintstr(),ft->fd(), c->peer().str().c_str(), (NOW-c->GetOpenTime()), zs->connect_timeout_ );
86 // Garbage collect copychans when open for long and slow upload
87 if ((NOW-c->GetOpenTime()) > zs->connect_timeout_) {
88 //fprintf(stderr,"%s F%" PRIu32 " zero clean %s opentime %" PRIi64 " ulspeed %lf\n",tintstr(),ft->fd(), c->peer().str().c_str(), (NOW-c->GetOpenTime())/TINT_SEC, ft->GetCurrentSpeed(DDIR_UPLOAD) );
89 fprintf(stderr,"%s F%" PRIu32 " zero clean %s close slow channel\n",tintstr(),td, c->peer().str() .c_str());
90 dprintf("%s F%" PRIu32 " zero clean %s close slow channel\n",tintstr(),td, c->peer().str().c_str());
91 c->Close(CLOSE_SEND_IF_ESTABLISHED);
92 delete c;
93 }
94 }
95 }
96 if (ct->GetChannels()->size() == 0) {
97 // Ain't go no clients left, cleanup transfer.
98 delset.push_back(td);
99 }
100 }
101 }
102
103
104 // Delete 0-state FileTransfers sans peers
105 for (iter=delset.begin(); iter!=delset.end(); iter++) {
106 int td = *iter;
107 dprintf("%s hash %s zero clean close\n",tintstr(),GetSwarmID(td).hex().c_str());
108 //fprintf(stderr,"%s F%" PRIu32 " zero clean close\n",tintstr(),td );
109 swift::Close(td);
110 }
111
112 // Reschedule cleanup
113 evtimer_add(&(zs->evclean_),tint2tv(CLEANUP_INTERVAL*TINT_SEC));
114 }
115
116
117
GetInstance()118 ZeroState * ZeroState::GetInstance()
119 {
120 //fprintf(stderr,"ZeroState::GetInstance: %p\n", Channel::evbase );
121 if (__singleton == NULL) {
122 new ZeroState();
123 }
124 return __singleton;
125 }
126
127
SetContentDir(std::string contentdir)128 void ZeroState::SetContentDir(std::string contentdir)
129 {
130 contentdir_ = contentdir;
131 }
132
133
SetMetaDir(std::string metadir)134 void ZeroState::SetMetaDir(std::string metadir)
135 {
136 metadir_ = metadir;
137 }
138
139
SetConnectTimeout(tint timeout)140 void ZeroState::SetConnectTimeout(tint timeout)
141 {
142 //fprintf(stderr,"ZeroState: SetConnectTimeout: %" PRIi64 "\n", timeout/TINT_SEC );
143 connect_timeout_ = timeout;
144 }
145
146
Find(const Sha1Hash & root_hash)147 int ZeroState::Find(const Sha1Hash &root_hash)
148 {
149 //fprintf(stderr,"swift: zero: Got request for %s\n",root_hash.hex().c_str() );
150
151 //std::string file_name = "content.avi";
152 std::string file_name = contentdir_+FILE_SEP+root_hash.hex();
153 std::string meta_prefix = "";
154 if (metadir_ == "")
155 meta_prefix = file_name;
156 else
157 meta_prefix = metadir_+FILE_SEP+root_hash.hex();
158
159 dprintf("%s #0 zero find %s from %s\n",tintstr(),file_name.c_str(), getcwd_utf8().c_str());
160
161 std::string reqfilename = file_name;
162 int ret = file_exists_utf8(reqfilename);
163 if (ret < 0 || ret == 0 || ret == 2)
164 return -1;
165 reqfilename = meta_prefix+".mbinmap";
166 ret = file_exists_utf8(reqfilename);
167 if (ret < 0 || ret == 0 || ret == 2)
168 return -1;
169 reqfilename = meta_prefix+".mhash";
170 ret = file_exists_utf8(reqfilename);
171 if (ret < 0 || ret == 0 || ret == 2)
172 return -1;
173
174 // Open as ZeroState
175 SwarmID swarmid(root_hash);
176 return swift::Open(file_name, swarmid, "", false, POPT_CONT_INT_PROT_MERKLE, true, true, SWIFT_DEFAULT_CHUNK_SIZE,
177 metadir_);
178 }
179
180
OnDataZeroState(struct evbuffer * evb)181 void Channel::OnDataZeroState(struct evbuffer *evb)
182 {
183 dprintf("%s #%" PRIu32 " zero -data, don't need it, am a seeder\n",tintstr(),id_);
184 }
185
OnHaveZeroState(struct evbuffer * evb)186 void Channel::OnHaveZeroState(struct evbuffer *evb)
187 {
188 binvector bv = evbuffer_remove_chunkaddr(evb,hs_in_->chunk_addr_);
189 // Forget about it, i.e.. don't build peer binmap.
190 }
191
OnHashZeroState(struct evbuffer * evb)192 void Channel::OnHashZeroState(struct evbuffer *evb)
193 {
194 dprintf("%s #%" PRIu32 " zero -hash, don't need it, am a seeder\n",tintstr(),id_);
195 }
196
OnPexAddZeroState(struct evbuffer * evb,int family)197 void Channel::OnPexAddZeroState(struct evbuffer *evb, int family)
198 {
199 evbuffer_remove_pexaddr(evb, family);
200 // Forget about it
201 }
202
OnPexAddCertZeroState(struct evbuffer * evb)203 void Channel::OnPexAddCertZeroState(struct evbuffer *evb)
204 {
205 uint16_t size = evbuffer_remove_16be(evb);
206 if (size > PEX_RES_MAX_CERT_SIZE || evbuffer_get_length(evb) < size) {
207 dprintf("%s #%" PRIu32 " ?pex cert too big\n",tintstr(),id_);
208 return;
209 }
210 //swarmidbytes = evbuffer_pullup(evb,size);
211 evbuffer_drain(evb, size);
212 // Forget about it
213 }
214
215
OnPexReqZeroState(struct evbuffer * evb)216 void Channel::OnPexReqZeroState(struct evbuffer *evb)
217 {
218 // Ignore it
219 }
220
221