1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2011 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
7 //
8 // Any parts of this program derived from the xMule, lMule or eMule project,
9 // or contributed by third-party developers are copyrighted by their
10 // respective authors.
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
25 //
26 
27 /*
28  SHA hashset basically exists of 1 Tree for all Parts (9.28MB) + n Trees
29  for all blocks (180KB) while n is the number of Parts.
30  This means it is NOT a complete hashtree, since the 9.28MB is a given level, in order
31  to be able to create a hashset format similar to the MD4 one.
32 
33  If the number of elements for the next level are odd (for example 21 blocks to spread into 2 hashs)
34  the majority of elements will go into the left branch if the parent node was a left branch
35  and into the right branch if the parent node was a right branch. The first node is always
36  taken as a left branch.
37 
38 Example tree:
39 	FileSize: 19506000 Bytes = 18,6 MB
40 
41               X(18,6 MB)						MasterHash
42              /          \
43           X(18,55)       \
44          /        \       \
45   X(9,28)         X(9,28)  X(0,05MB)				PartHashs
46  /     \         /     \          \
47 X(4,75) X(4,57) X(4,57) X(4,57)    X(4,75)
48 [...............]
49 X(180KB)   X(180KB)  [...] X(140KB) | X(180KB) X(180KB) [...]	BlockHashs
50                                     v
51                                     Border between first and second Part (9.28MB)
52 
53 HashsIdentifier:
54 When sending hashes, they are sent with a 16bit identifier which specifies its position in the
55 tree (so StartPosition + HashDataSize would lead to the same hash)
56 The identifier basically describes the way from the top of the tree to the hash. a set bit (1)
57 means follow the left branch, a 0 means follow the right. The highest bit which is set is seen as the start-
58 position (since the first node is always seen as left).
59 
60 Example
61 
62     x                   0000000000000001
63    / \
64   x   \			0000000000000011
65  / \   \
66 x  _X_  x	        0000000000000110
67 
68 
69 Version 2 of AICH also supports 32bit identifiers to support large files, check CAICHHashSet::CreatePartRecoveryData
70 */
71 
72 #ifndef __SHAHAHSET_H__
73 #define __SHAHAHSET_H__
74 
75 #include <deque>
76 #include <set>
77 
78 #include "Types.h"
79 #include "ClientRef.h"
80 
81 #define HASHSIZE			20
82 #define KNOWN2_MET_FILENAME		wxT("known2_64.met")
83 #define OLD_KNOWN2_MET_FILENAME		wxT("known2.met")
84 #define KNOWN2_MET_VERSION		0x02
85 
86 enum EAICHStatus {
87 	AICH_ERROR = 0,
88 	AICH_EMPTY,
89 	AICH_UNTRUSTED,
90 	AICH_TRUSTED,
91 	AICH_VERIFIED,
92 	AICH_HASHSETCOMPLETE
93 };
94 
95 class CFileDataIO;
96 class CKnownFile;
97 class CMemFile;
98 class CPartFile;
99 class CUpDownClient;
100 
101 
102 /////////////////////////////////////////////////////////////////////////////////////////
103 ///CAICHHash
104 class CAICHHash
105 {
106 private:
107 	byte m_abyBuffer[HASHSIZE];
108 
109 public:
CAICHHash()110 	CAICHHash()				{ memset(m_abyBuffer, 0, HASHSIZE); }
CAICHHash(CFileDataIO * file)111 	CAICHHash(CFileDataIO* file)		{ Read(file); }
CAICHHash(byte * data)112 	CAICHHash(byte* data)			{ Read(data); }
CAICHHash(const CAICHHash & k1)113 	CAICHHash(const CAICHHash& k1)		{ *this = k1; }
~CAICHHash()114 	~CAICHHash() {}
115 	CAICHHash& operator=(const CAICHHash& k1)
116 	{
117 		memcpy(m_abyBuffer, k1.m_abyBuffer, HASHSIZE);
118 		return *this;
119 	}
120 	friend bool operator==(const CAICHHash& k1,const CAICHHash& k2)
121 	{
122 		return memcmp(k1.m_abyBuffer, k2.m_abyBuffer, HASHSIZE) == 0;
123 	}
124 	friend bool operator!=(const CAICHHash& k1,const CAICHHash& k2)	{ return !(k1 == k2); }
125 	void Read(CFileDataIO* file);
126 	void Write(CFileDataIO* file) const;
Read(byte * data)127 	void Read(byte* data)			{ memcpy(m_abyBuffer, data, HASHSIZE); }
128 	wxString GetString() const;
GetRawHash()129 	byte* GetRawHash()			{ return m_abyBuffer; }
GetHashSize()130 	static uint32 GetHashSize()		{ return HASHSIZE;}
131 	unsigned int DecodeBase32(const wxString &base32);
132 };
133 
134 /////////////////////////////////////////////////////////////////////////////////////////
135 ///CAICHHashAlgo
136 class CAICHHashAlgo
137 {
138 public:
~CAICHHashAlgo()139 	virtual ~CAICHHashAlgo() {};
140 	virtual void Reset() = 0;
141 	virtual void Add(const void* pData, uint32 nLength) = 0;
142 	virtual void Finish(CAICHHash& Hash) = 0;
143 	virtual void GetHash(CAICHHash& Hash) = 0;
144 };
145 
146 /////////////////////////////////////////////////////////////////////////////////////////
147 ///CAICHHashTree
148 class CAICHHashTree
149 {
150 	friend class CAICHHashSet;
151 private:
152 	CAICHHash m_Hash;
153 	uint64 m_nDataSize;	// size of data which is covered by this hash
154 	uint64 m_nBaseSize;	// blocksize on which the lowest hash is based on
155 	bool m_bIsLeftBranch;	// left or right branch of the tree
156 	bool m_bHashValid;	// the hash is valid and not empty
157 	CAICHHashTree* m_pLeftTree;
158 	CAICHHashTree* m_pRightTree;
159 
160 public:
161 	CAICHHashTree(uint64 nDataSize, bool bLeftBranch, uint64 nBaseSize);
162 	~CAICHHashTree();
163 
GetHash()164 	const CAICHHash &GetHash() const	{ return m_Hash; }
GetNDataSize()165 	uint64 GetNDataSize() const		{ return m_nDataSize; }
GetNBaseSize()166 	uint64 GetNBaseSize() const		{ return m_nBaseSize; }
GetIsLeftBranch()167 	bool GetIsLeftBranch() const		{ return m_bIsLeftBranch; }
GetHashValid()168 	bool GetHashValid() const		{ return m_bHashValid; }
169 
170 	void SetBlockHash(uint64 nSize, uint64 nStartPos, CAICHHashAlgo* pHashAlg);
171 	bool ReCalculateHash(CAICHHashAlgo* hashalg, bool bDontReplace );
172 	bool VerifyHashTree(CAICHHashAlgo* hashalg, bool bDeleteBadTrees);
FindHash(uint64 nStartPos,uint64 nSize)173 	CAICHHashTree* FindHash(uint64 nStartPos, uint64 nSize)
174 	{
175 		uint8 buffer = 0;
176 		return FindHash(nStartPos, nSize, &buffer);
177 	}
178 
179 protected:
180 	CAICHHashTree* FindHash(uint64 nStartPos, uint64 nSize, uint8* nLevel);
181 	bool CreatePartRecoveryData(uint64 nStartPos, uint64 nSize,
182 		CFileDataIO* fileDataOut, uint32 wHashIdent, bool b32BitIdent);
183 	void WriteHash(CFileDataIO* fileDataOut, uint32 wHashIdent, bool b32BitIdent) const;
184 	bool WriteLowestLevelHashs(CFileDataIO* fileDataOut,
185 		uint32 wHashIdent, bool bNoIdent, bool b32BitIdent) const;
186 	bool LoadLowestLevelHashs(CFileDataIO* fileInput);
187 	bool SetHash(CFileDataIO* fileInput, uint32 wHashIdent, sint8 nLevel = (-1), bool bAllowOverwrite = true);
188 };
189 
190 /////////////////////////////////////////////////////////////////////////////////////////
191 ///CAICHUntrustedHashs
192 class CAICHUntrustedHash {
193 public:
194 	CAICHUntrustedHash& operator=(const CAICHUntrustedHash& k1)
195 	{
196 		m_adwIpsSigning = k1.m_adwIpsSigning;
197 		m_Hash = k1.m_Hash ;
198 		return *this;
199 	}
200 	bool AddSigningIP(uint32 dwIP);
201 
202 	CAICHHash m_Hash;
203 	std::set<uint32> m_adwIpsSigning;
204 };
205 
206 /////////////////////////////////////////////////////////////////////////////////////////
207 ///CAICHUntrustedHashs
208 class CAICHRequestedData {
209 public:
CAICHRequestedData()210 	CAICHRequestedData()
211 	{
212 		m_nPart = 0;
213 		m_pPartFile = NULL;
214 	}
215 	CAICHRequestedData& operator=(const CAICHRequestedData& k1)
216 	{
217 		m_nPart = k1.m_nPart;
218 		m_pPartFile = k1.m_pPartFile;
219 		m_pClient = k1.m_pClient;
220 		return *this;
221 	}
222 	uint16 m_nPart;
223 	CPartFile* m_pPartFile;
224 	CClientRef m_pClient;
225 };
226 
227 
228 using namespace std;
229 
230 typedef std::list<CAICHRequestedData> CAICHRequestedDataList;
231 
232 /////////////////////////////////////////////////////////////////////////////////////////
233 ///CAICHHashSet
234 class CAICHHashSet
235 {
236 private:
237 	CKnownFile* m_pOwner;
238 	EAICHStatus m_eStatus;
239 	deque<CAICHUntrustedHash> m_aUntrustedHashs;
240 
241 public:
242 	static CAICHRequestedDataList m_liRequestedData;
243 	CAICHHashTree m_pHashTree;
244 
245 	CAICHHashSet(CKnownFile* pOwner);
246 	~CAICHHashSet(void);
247 	bool CreatePartRecoveryData(uint64 nPartStartPos, CFileDataIO* fileDataOut, bool bDbgDontLoad = false);
248 	bool ReadRecoveryData(uint64 nPartStartPos, CMemFile* fileDataIn);
249 	bool ReCalculateHash(bool bDontReplace = false);
250 	bool VerifyHashTree(bool bDeleteBadTrees);
251 	void UntrustedHashReceived(const CAICHHash& Hash, uint32 dwFromIP);
252 	bool IsPartDataAvailable(uint64 nPartStartPos);
SetStatus(EAICHStatus bNewValue)253 	void SetStatus(EAICHStatus bNewValue)	{ m_eStatus = bNewValue; }
GetStatus()254 	EAICHStatus GetStatus()	const		{ return m_eStatus; }
255 
256 	void FreeHashSet();
257 	void SetFileSize(uint64 nSize);
258 
GetMasterHash()259 	CAICHHash& GetMasterHash()		{ return m_pHashTree.m_Hash; }
260 	void SetMasterHash(const CAICHHash& Hash, EAICHStatus eNewStatus);
HasValidMasterHash()261 	bool HasValidMasterHash()		{ return m_pHashTree.m_bHashValid; }
262 
263 	bool SaveHashSet();
264 	bool LoadHashSet(); // only call directly when debugging
265 
266 	static CAICHHashAlgo* GetNewHashAlgo();
267 	static void ClientAICHRequestFailed(CUpDownClient* pClient);
268 	static void RemoveClientAICHRequest(const CUpDownClient* pClient);
269 	static bool IsClientRequestPending(const CPartFile* pForFile, uint16 nPart);
270 	static CAICHRequestedData GetAICHReqDetails(const  CUpDownClient* pClient);
271 	void DbgTest();
272 
SetOwner(CKnownFile * owner)273 	void SetOwner(CKnownFile* owner)	{ m_pOwner = owner; }
274 };
275 
276 #endif  //__SHAHAHSET_H__
277 
278 // File_checked_for_headers
279