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