1 /* <!-- copyright */
2 /*
3 * aria2 - The high speed download utility
4 *
5 * Copyright (C) 2006 Tatsuhiro Tsujikawa
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * In addition, as a special exception, the copyright holders give
22 * permission to link the code of portions of this program with the
23 * OpenSSL library under certain conditions as described in each
24 * individual source file, and distribute linked combinations
25 * including the two.
26 * You must obey the GNU General Public License in all respects
27 * for all of the code used other than OpenSSL. If you modify
28 * file(s) with this exception, you may extend this exception to your
29 * version of the file(s), but you are not obligated to do so. If you
30 * do not wish to do so, delete this exception statement from your
31 * version. If you delete this exception statement from all source
32 * files in the program, then also delete it here.
33 */
34 /* copyright --> */
35 #include "DownloadContext.h"
36
37 #include <algorithm>
38
39 #include "FileEntry.h"
40 #include "fmt.h"
41 #include "util.h"
42 #include "wallclock.h"
43 #include "DlAbortEx.h"
44 #include "a2functional.h"
45 #include "Signature.h"
46 #include "RequestGroupMan.h"
47
48 namespace aria2 {
49
DownloadContext()50 DownloadContext::DownloadContext()
51 : ownerRequestGroup_(nullptr),
52 attrs_(MAX_CTX_ATTR),
53 downloadStopTime_(Timer::zero()),
54 pieceLength_(0),
55 checksumVerified_(false),
56 knowsTotalLength_(true),
57 #ifdef ENABLE_METALINK
58 acceptMetalink_(true)
59 #else // !ENABLE_METALINK
60 acceptMetalink_(false)
61 #endif // !ENABLE_METALINK
62 {
63 }
64
DownloadContext(int32_t pieceLength,int64_t totalLength,std::string path)65 DownloadContext::DownloadContext(int32_t pieceLength, int64_t totalLength,
66 std::string path)
67 : ownerRequestGroup_(nullptr),
68 attrs_(MAX_CTX_ATTR),
69 downloadStopTime_(Timer::zero()),
70 pieceLength_(pieceLength),
71 checksumVerified_(false),
72 knowsTotalLength_(true),
73 #ifdef ENABLE_METALINK
74 acceptMetalink_(true)
75 #else // !ENABLE_METALINK
76 acceptMetalink_(false)
77 #endif // !ENABLE_METALINK
78 {
79 fileEntries_.push_back(
80 std::make_shared<FileEntry>(std::move(path), totalLength, 0));
81 }
82
83 DownloadContext::~DownloadContext() = default;
84
resetDownloadStartTime()85 void DownloadContext::resetDownloadStartTime()
86 {
87 downloadStopTime_ = Timer::zero();
88 netStat_.downloadStart();
89 }
90
resetDownloadStopTime()91 void DownloadContext::resetDownloadStopTime()
92 {
93 downloadStopTime_ = global::wallclock();
94 netStat_.downloadStop();
95 }
96
calculateSessionTime() const97 Timer::Clock::duration DownloadContext::calculateSessionTime() const
98 {
99 const Timer& startTime = netStat_.getDownloadStartTime();
100 return startTime.difference(downloadStopTime_);
101 }
102
103 std::shared_ptr<FileEntry>
findFileEntryByOffset(int64_t offset) const104 DownloadContext::findFileEntryByOffset(int64_t offset) const
105 {
106 if (fileEntries_.empty() ||
107 (offset > 0 && fileEntries_.back()->getLastOffset() <= offset)) {
108 return nullptr;
109 }
110
111 auto obj = std::make_shared<FileEntry>();
112 obj->setOffset(offset);
113 auto i = std::upper_bound(fileEntries_.begin(), fileEntries_.end(), obj,
114 DerefLess<std::shared_ptr<FileEntry>>());
115 if (i != fileEntries_.end() && (*i)->getOffset() == offset) {
116 return *i;
117 }
118 else {
119 return *(--i);
120 }
121 }
122
setFilePathWithIndex(size_t index,const std::string & path)123 void DownloadContext::setFilePathWithIndex(size_t index,
124 const std::string& path)
125 {
126 if (0 < index && index <= fileEntries_.size()) {
127 // We don't escape path because path may come from users.
128 fileEntries_[index - 1]->setPath(path);
129 }
130 else {
131 throw DL_ABORT_EX(
132 fmt("No such file with index=%u", static_cast<unsigned int>(index)));
133 }
134 }
135
setFileFilter(SegList<int> sgl)136 void DownloadContext::setFileFilter(SegList<int> sgl)
137 {
138 using namespace std::placeholders;
139
140 if (!sgl.hasNext() || fileEntries_.size() == 1) {
141 std::for_each(fileEntries_.begin(), fileEntries_.end(),
142 std::bind(&FileEntry::setRequested, _1, true));
143 return;
144 }
145 assert(sgl.peek() >= 1);
146 size_t len = fileEntries_.size();
147 size_t i = 0;
148 for (; i < len && sgl.hasNext(); ++i) {
149 size_t idx = sgl.peek() - 1;
150 if (i == idx) {
151 fileEntries_[i]->setRequested(true);
152 sgl.next();
153 }
154 else if (i < idx) {
155 fileEntries_[i]->setRequested(false);
156 }
157 }
158 for (; i < len; ++i) {
159 fileEntries_[i]->setRequested(false);
160 }
161 }
162
setAttribute(ContextAttributeType key,std::shared_ptr<ContextAttribute> value)163 void DownloadContext::setAttribute(ContextAttributeType key,
164 std::shared_ptr<ContextAttribute> value)
165 {
166 assert(key < MAX_CTX_ATTR);
167 attrs_[key] = std::move(value);
168 }
169
170 const std::shared_ptr<ContextAttribute>&
getAttribute(ContextAttributeType key)171 DownloadContext::getAttribute(ContextAttributeType key)
172 {
173 assert(key < MAX_CTX_ATTR);
174 const auto& attr = attrs_[key];
175 if (!attr) {
176 throw DL_ABORT_EX(
177 fmt("No attribute named %s", strContextAttributeType(key)));
178 }
179
180 return attr;
181 }
182
hasAttribute(ContextAttributeType key) const183 bool DownloadContext::hasAttribute(ContextAttributeType key) const
184 {
185 assert(key < MAX_CTX_ATTR);
186 return attrs_[key].get();
187 }
188
189 const std::vector<std::shared_ptr<ContextAttribute>>&
getAttributes() const190 DownloadContext::getAttributes() const
191 {
192 return attrs_;
193 }
194
releaseRuntimeResource()195 void DownloadContext::releaseRuntimeResource()
196 {
197 for (std::vector<std::shared_ptr<FileEntry>>::const_iterator
198 i = fileEntries_.begin(),
199 eoi = fileEntries_.end();
200 i != eoi; ++i) {
201 (*i)->putBackRequest();
202 (*i)->releaseRuntimeResource();
203 }
204 }
205
getNumPieces() const206 size_t DownloadContext::getNumPieces() const
207 {
208 if (pieceLength_ == 0) {
209 return 0;
210 }
211 else {
212 assert(!fileEntries_.empty());
213 return (fileEntries_.back()->getLastOffset() + pieceLength_ - 1) /
214 pieceLength_;
215 }
216 }
217
getTotalLength() const218 int64_t DownloadContext::getTotalLength() const
219 {
220 if (fileEntries_.empty()) {
221 return 0;
222 }
223 else {
224 return fileEntries_.back()->getLastOffset();
225 }
226 }
227
getBasePath() const228 const std::string& DownloadContext::getBasePath() const
229 {
230 if (basePath_.empty()) {
231 assert(!fileEntries_.empty());
232 return getFirstFileEntry()->getPath();
233 }
234 else {
235 return basePath_;
236 }
237 }
238
getFirstRequestedFileEntry() const239 std::shared_ptr<FileEntry> DownloadContext::getFirstRequestedFileEntry() const
240 {
241 for (auto& e : fileEntries_) {
242 if (e->isRequested()) {
243 return e;
244 }
245 }
246 return nullptr;
247 }
248
countRequestedFileEntry() const249 size_t DownloadContext::countRequestedFileEntry() const
250 {
251 size_t numFiles = 0;
252 for (const auto& e : fileEntries_) {
253 if (e->isRequested()) {
254 ++numFiles;
255 }
256 }
257 return numFiles;
258 }
259
isChecksumVerificationNeeded() const260 bool DownloadContext::isChecksumVerificationNeeded() const
261 {
262 return pieceHashType_.empty() && !digest_.empty() && !hashType_.empty() &&
263 !checksumVerified_;
264 }
265
isChecksumVerificationAvailable() const266 bool DownloadContext::isChecksumVerificationAvailable() const
267 {
268 return !digest_.empty() && !hashType_.empty();
269 }
270
isPieceHashVerificationAvailable() const271 bool DownloadContext::isPieceHashVerificationAvailable() const
272 {
273 return !pieceHashType_.empty() && pieceHashes_.size() > 0 &&
274 pieceHashes_.size() == getNumPieces();
275 }
276
getPieceHash(size_t index) const277 const std::string& DownloadContext::getPieceHash(size_t index) const
278 {
279 if (index < pieceHashes_.size()) {
280 return pieceHashes_[index];
281 }
282 else {
283 return A2STR::NIL;
284 }
285 }
286
setDigest(const std::string & hashType,const std::string & digest)287 void DownloadContext::setDigest(const std::string& hashType,
288 const std::string& digest)
289 {
290 hashType_ = hashType;
291 digest_ = digest;
292 }
293
setBasePath(const std::string & basePath)294 void DownloadContext::setBasePath(const std::string& basePath)
295 {
296 basePath_ = basePath;
297 }
298
setSignature(std::unique_ptr<Signature> signature)299 void DownloadContext::setSignature(std::unique_ptr<Signature> signature)
300 {
301 signature_ = std::move(signature);
302 }
303
updateDownload(size_t bytes)304 void DownloadContext::updateDownload(size_t bytes)
305 {
306 netStat_.updateDownload(bytes);
307 RequestGroupMan* rgman = ownerRequestGroup_->getRequestGroupMan();
308 if (rgman) {
309 rgman->getNetStat().updateDownload(bytes);
310 }
311 }
312
updateUploadSpeed(size_t bytes)313 void DownloadContext::updateUploadSpeed(size_t bytes)
314 {
315 netStat_.updateUploadSpeed(bytes);
316 auto rgman = ownerRequestGroup_->getRequestGroupMan();
317 if (rgman) {
318 rgman->getNetStat().updateUploadSpeed(bytes);
319 }
320 }
321
updateUploadLength(size_t bytes)322 void DownloadContext::updateUploadLength(size_t bytes)
323 {
324 netStat_.updateUploadLength(bytes);
325 auto rgman = ownerRequestGroup_->getRequestGroupMan();
326 if (rgman) {
327 rgman->getNetStat().updateUploadLength(bytes);
328 }
329 }
330
331 } // namespace aria2
332