1 /*
2  * Copyright (C) 2001-2012 Jacek Sieka, arnetheduck on gmail point com
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #pragma once
20 
21 #include "User.h"
22 #include "FastAlloc.h"
23 #include "MerkleTree.h"
24 #include "Flags.h"
25 #include "forward.h"
26 #include "Segment.h"
27 
28 namespace dcpp {
29 
30 class QueueManager;
31 
32 class QueueItem : public Flags, public FastAlloc<QueueItem> {
33 public:
34     typedef QueueItem* Ptr;
35     typedef deque<Ptr> List;
36     typedef List::iterator Iter;
37     typedef unordered_map<string*, Ptr, CaseStringHash, CaseStringEq> StringMap;
38     typedef StringMap::iterator StringIter;
39     typedef unordered_map<UserPtr, Ptr, User::Hash> UserMap;
40     typedef UserMap::iterator UserIter;
41     typedef unordered_map<UserPtr, List, User::Hash> UserListMap;
42     typedef UserListMap::iterator UserListIter;
43 
44     enum Priority {
45         DEFAULT = -1,
46         PAUSED = 0,
47         LOWEST,
48         LOW,
49         NORMAL,
50         HIGH,
51         HIGHEST,
52         LAST
53     };
54 
55     enum FileFlags {
56         /** Normal download, no flags set */
57         FLAG_NORMAL = 0x00,
58         /** This is a user file listing download */
59         FLAG_USER_LIST = 0x02,
60         /** The file list is downloaded to use for directory download (used with USER_LIST) */
61         FLAG_DIRECTORY_DOWNLOAD = 0x04,
62         /** The file is downloaded to be viewed in the gui */
63         FLAG_CLIENT_VIEW = 0x08,
64         /** Flag to indicate that file should be viewed as a text file */
65         FLAG_TEXT = 0x20,
66         /** Match the queue against this list */
67         FLAG_MATCH_QUEUE = 0x80,
68         /** The file list downloaded was actually an .xml.bz2 list */
69         FLAG_XML_BZLIST = 0x100,
70         /** Only download a part of the file list */
71         FLAG_PARTIAL_LIST = 0x200
72     };
73 
74     /**
75      * Source parts info
76      * Meaningful only when Source::FLAG_PARTIAL is set
77      */
78     class PartialSource : public FastAlloc<PartialSource>, public intrusive_ptr_base<PartialSource> {
79     public:
PartialSource(const string & aMyNick,const string & aHubIpPort,const string & aIp,uint16_t udp)80         PartialSource(const string& aMyNick, const string& aHubIpPort, const string& aIp, uint16_t udp) :
81           myNick(aMyNick), hubIpPort(aHubIpPort), ip(aIp), udpPort(udp), nextQueryTime(0), pendingQueryCount(0) { }
82 
~PartialSource()83         ~PartialSource() { }
84 
85         typedef boost::intrusive_ptr<PartialSource> Ptr;
86 
87         GETSET(PartsInfo, partialInfo, PartialInfo);
88         GETSET(string, myNick, MyNick);                 // for NMDC support only
89         GETSET(string, hubIpPort, HubIpPort);
90         GETSET(string, ip, Ip);
91         GETSET(uint16_t, udpPort, UdpPort);
92         GETSET(uint64_t, nextQueryTime, NextQueryTime);
93         GETSET(uint8_t, pendingQueryCount, PendingQueryCount);
94     };
95 
96 
97     class Source : public Flags {
98     public:
99         enum {
100             FLAG_NONE = 0x00,
101             FLAG_FILE_NOT_AVAILABLE = 0x01,
102             FLAG_PASSIVE = 0x02,
103             FLAG_REMOVED = 0x04,
104             FLAG_CRC_FAILED = 0x08,
105             FLAG_CRC_WARN = 0x10,
106             FLAG_NO_TTHF = 0x20,
107             FLAG_BAD_TREE = 0x40,
108             FLAG_NO_TREE = 0x80,
109             FLAG_SLOW_SOURCE = 0x100,
110             FLAG_PARTIAL    = 0x200,
111             FLAG_NO_NEED_PARTS      = 0x250,
112             FLAG_TTH_INCONSISTENCY  = 0x300,
113             FLAG_UNTRUSTED = 0x400,
114             FLAG_UNENCRYPTED = 0x450,
115             FLAG_MASK = FLAG_FILE_NOT_AVAILABLE
116                 | FLAG_PASSIVE | FLAG_REMOVED | FLAG_CRC_FAILED | FLAG_CRC_WARN
117                 | FLAG_BAD_TREE | FLAG_NO_TREE | FLAG_SLOW_SOURCE | FLAG_TTH_INCONSISTENCY | FLAG_UNTRUSTED | FLAG_UNENCRYPTED
118         };
119 
Source(const HintedUser & aUser)120         Source(const HintedUser& aUser) : user(aUser), partialSource(NULL) { }
Source(const Source & aSource)121         Source(const Source& aSource) : Flags(aSource), user(aSource.user), partialSource(aSource.partialSource) { }
122 
123         bool operator==(const UserPtr& aUser) const { return user == aUser; }
getPartialSource()124         PartialSource::Ptr& getPartialSource() { return partialSource; }
125 
126         GETSET(HintedUser, user, User);
127         GETSET(PartialSource::Ptr, partialSource, PartialSource);
128     };
129 
130     typedef std::vector<Source> SourceList;
131     typedef SourceList::iterator SourceIter;
132     typedef SourceList::const_iterator SourceConstIter;
133 
134     typedef set<Segment> SegmentSet;
135     typedef SegmentSet::iterator SegmentIter;
136     typedef SegmentSet::const_iterator SegmentConstIter;
137 
QueueItem(const string & aTarget,int64_t aSize,Priority aPriority,int aFlag,time_t aAdded,const TTHValue & tth)138     QueueItem(const string& aTarget, int64_t aSize, Priority aPriority, int aFlag,
139         time_t aAdded, const TTHValue& tth) :
140         Flags(aFlag), target(aTarget), size(aSize),
141         priority(aPriority), added(aAdded), tthRoot(tth), nextPublishingTime(0)
142     { }
143 
QueueItem(const QueueItem & rhs)144     QueueItem(const QueueItem& rhs) :
145         Flags(rhs), done(rhs.done), downloads(rhs.downloads), target(rhs.target),
146         size(rhs.size), priority(rhs.priority), added(rhs.added), tthRoot(rhs.tthRoot),
147         nextPublishingTime(rhs.nextPublishingTime), sources(rhs.sources), badSources(rhs.badSources),
148         tempTarget(rhs.tempTarget)
149 
150     { }
151 
~QueueItem()152     virtual ~QueueItem() { }
153 
154     int countOnlineUsers() const;
hasOnlineUsers()155     bool hasOnlineUsers() const { return countOnlineUsers() > 0; }
156     void getOnlineUsers(HintedUserList& l) const;
157 
getSources()158     SourceList& getSources() { return sources; }
getSources()159     const SourceList& getSources() const { return sources; }
getBadSources()160     SourceList& getBadSources() { return badSources; }
getBadSources()161     const SourceList& getBadSources() const { return badSources; }
162 
getTargetFileName()163     string getTargetFileName() const { return Util::getFileName(getTarget()); }
164 
getSource(const UserPtr & aUser)165     SourceIter getSource(const UserPtr& aUser) { return find(sources.begin(), sources.end(), aUser); }
getBadSource(const UserPtr & aUser)166     SourceIter getBadSource(const UserPtr& aUser) { return find(badSources.begin(), badSources.end(), aUser); }
getSource(const UserPtr & aUser)167     SourceConstIter getSource(const UserPtr& aUser) const { return find(sources.begin(), sources.end(), aUser); }
getBadSource(const UserPtr & aUser)168     SourceConstIter getBadSource(const UserPtr& aUser) const { return find(badSources.begin(), badSources.end(), aUser); }
169 
isSource(const UserPtr & aUser)170     bool isSource(const UserPtr& aUser) const { return getSource(aUser) != sources.end(); }
isBadSource(const UserPtr & aUser)171     bool isBadSource(const UserPtr& aUser) const { return getBadSource(aUser) != badSources.end(); }
isBadSourceExcept(const UserPtr & aUser,Flags::MaskType exceptions)172     bool isBadSourceExcept(const UserPtr& aUser, Flags::MaskType exceptions) const {
173         SourceConstIter i = getBadSource(aUser);
174         if(i != badSources.end())
175             return i->isAnySet(exceptions^Source::FLAG_MASK);
176         return false;
177     }
178 
179     int64_t getDownloadedBytes() const;
getDownloadedFraction()180     double getDownloadedFraction() const { return static_cast<double>(getDownloadedBytes()) / getSize(); }
181 
getDownloads()182     DownloadList& getDownloads() { return downloads; }
183 
isChunkDownloaded(int64_t startPos,int64_t & len)184     bool isChunkDownloaded(int64_t startPos, int64_t& len) const {
185         if(len <= 0) return false;
186 
187         for(SegmentSet::const_iterator i = done.begin(); i != done.end(); ++i) {
188             int64_t first  = (*i).getStart();
189             int64_t second = (*i).getEnd();
190 
191             if(first <= startPos && startPos < second){
192                 len = min(len, second - startPos);
193                 return true;
194             }
195         }
196 
197         return false;
198     }
199 
200     /** Next segment that is not done and not being downloaded, zero-sized segment returned if there is none is found */
201     Segment getNextSegment(int64_t blockSize, int64_t wantedSize, int64_t lastSpeed, const PartialSource::Ptr partialSource) const;
202     /**
203      * Is specified parts needed by this download?
204      */
205     bool isNeededPart(const PartsInfo& partsInfo, int64_t blockSize);
206     /**
207      * Get shared parts info, max 255 parts range pairs
208      */
209     void getPartialInfo(PartsInfo& partialInfo, int64_t blockSize) const;
210 
211 
212     void addSegment(const Segment& segment);
resetDownloaded()213     void resetDownloaded() { done.clear(); }
214 
isFinished()215     bool isFinished() const {
216         return done.size() == 1 && *done.begin() == Segment(0, getSize());
217     }
218 
isRunning()219     bool isRunning() const {
220         return !isWaiting();
221     }
isWaiting()222     bool isWaiting() const {
223         return downloads.empty();
224     }
225 
getListName()226     string getListName() const {
227         dcassert(isSet(QueueItem::FLAG_USER_LIST));
228         if(isSet(QueueItem::FLAG_XML_BZLIST)) {
229             return getTarget() + ".xml.bz2";
230         } else {
231             return getTarget() + ".xml";
232         }
233     }
234 
235     const string& getTempTarget();
setTempTarget(const string & aTempTarget)236     void setTempTarget(const string& aTempTarget) { tempTarget = aTempTarget; }
237 
238     GETSET(SegmentSet, done, Done);
239     GETSET(DownloadList, downloads, Downloads);
240     GETSET(string, target, Target);
241     GETSET(int64_t, size, Size);
242     GETSET(Priority, priority, Priority);
243     GETSET(time_t, added, Added);
244     GETSET(TTHValue, tthRoot, TTH);
245     GETSET(uint64_t, nextPublishingTime, NextPublishingTime);
246 private:
247     QueueItem& operator=(const QueueItem&);
248 
249     friend class QueueManager;
250     SourceList sources;
251     SourceList badSources;
252     string tempTarget;
253 
254     void addSource(const HintedUser& aUser);
255     void removeSource(const UserPtr& aUser, int reason);
256 };
257 
258 } // namespace dcpp
259