1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
//
// This file is part of the aMule Project.
//
// Copyright (c) 2004-2011 Angel Vidal ( kry@amule.org )
// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
// Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
//
// Any parts of this program derived from the xMule, lMule or eMule project,
// or contributed by third-party developers are copyrighted by their
// respective authors.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
//

/*
 SHA hashset basically exists of 1 Tree for all Parts (9.28MB) + n Trees
 for all blocks (180KB) while n is the number of Parts.
 This means it is NOT a complete hashtree, since the 9.28MB is a given level, in order
 to be able to create a hashset format similar to the MD4 one.

 If the number of elements for the next level are odd (for example 21 blocks to spread into 2 hashs)
 the majority of elements will go into the left branch if the parent node was a left branch
 and into the right branch if the parent node was a right branch. The first node is always
 taken as a left branch.

Example tree:
	FileSize: 19506000 Bytes = 18,6 MB

              X(18,6 MB)						MasterHash
             /          \
          X(18,55)       \
         /        \       \
  X(9,28)         X(9,28)  X(0,05MB)				PartHashs
 /     \         /     \          \
X(4,75) X(4,57) X(4,57) X(4,57)    X(4,75)
[...............]
X(180KB)   X(180KB)  [...] X(140KB) | X(180KB) X(180KB) [...]	BlockHashs
                                    v
                                    Border between first and second Part (9.28MB)

HashsIdentifier:
When sending hashes, they are sent with a 16bit identifier which specifies its position in the
tree (so StartPosition + HashDataSize would lead to the same hash)
The identifier basically describes the way from the top of the tree to the hash. a set bit (1)
means follow the left branch, a 0 means follow the right. The highest bit which is set is seen as the start-
position (since the first node is always seen as left).

Example

    x                   0000000000000001
   / \
  x   \			0000000000000011
 / \   \
x  _X_  x	        0000000000000110


Version 2 of AICH also supports 32bit identifiers to support large files, check CAICHHashSet::CreatePartRecoveryData
*/

#ifndef __SHAHAHSET_H__
#define __SHAHAHSET_H__

#include <deque>
#include <set>

#include "Types.h"
#include "ClientRef.h"

#define HASHSIZE			20
#define KNOWN2_MET_FILENAME		wxT("known2_64.met")
#define OLD_KNOWN2_MET_FILENAME		wxT("known2.met")
#define KNOWN2_MET_VERSION		0x02

enum EAICHStatus {
	AICH_ERROR = 0,
	AICH_EMPTY,
	AICH_UNTRUSTED,
	AICH_TRUSTED,
	AICH_VERIFIED,
	AICH_HASHSETCOMPLETE
};

class CFileDataIO;
class CKnownFile;
class CMemFile;
class CPartFile;
class CUpDownClient;


/////////////////////////////////////////////////////////////////////////////////////////
///CAICHHash
class CAICHHash
{
private:
	uint8_t m_abyBuffer[HASHSIZE];

public:
	CAICHHash()				{ memset(m_abyBuffer, 0, HASHSIZE); }
	CAICHHash(CFileDataIO* file)		{ Read(file); }
	CAICHHash(uint8_t* data)		{ Read(data); }
	CAICHHash(const CAICHHash& k1)		{ *this = k1; }
	~CAICHHash() {}
	CAICHHash& operator=(const CAICHHash& k1)
	{
		memcpy(m_abyBuffer, k1.m_abyBuffer, HASHSIZE);
		return *this;
	}
	friend bool operator==(const CAICHHash& k1,const CAICHHash& k2)
	{
		return memcmp(k1.m_abyBuffer, k2.m_abyBuffer, HASHSIZE) == 0;
	}
	friend bool operator!=(const CAICHHash& k1,const CAICHHash& k2)	{ return !(k1 == k2); }
	void Read(CFileDataIO* file);
	void Write(CFileDataIO* file) const;
	void Read(uint8_t* data)		{ memcpy(m_abyBuffer, data, HASHSIZE); }<--- Parameter 'data' can be declared as pointer to const
	wxString GetString() const;
	uint8_t* GetRawHash()			{ return m_abyBuffer; }
	static uint32 GetHashSize()		{ return HASHSIZE;}
	unsigned int DecodeBase32(const wxString &base32);
};

/////////////////////////////////////////////////////////////////////////////////////////
///CAICHHashAlgo
class CAICHHashAlgo
{
public:
	virtual ~CAICHHashAlgo() {};
	virtual void Reset() = 0;
	virtual void Add(const void* pData, uint32 nLength) = 0;
	virtual void Finish(CAICHHash& Hash) = 0;
	virtual void GetHash(CAICHHash& Hash) = 0;
};

/////////////////////////////////////////////////////////////////////////////////////////
///CAICHHashTree
class CAICHHashTree
{
	friend class CAICHHashSet;
private:
	CAICHHash m_Hash;
	uint64 m_nDataSize;	// size of data which is covered by this hash
	uint64 m_nBaseSize;	// blocksize on which the lowest hash is based on
	bool m_bIsLeftBranch;	// left or right branch of the tree
	bool m_bHashValid;	// the hash is valid and not empty
	CAICHHashTree* m_pLeftTree;
	CAICHHashTree* m_pRightTree;

public:
	CAICHHashTree(uint64 nDataSize, bool bLeftBranch, uint64 nBaseSize);
	~CAICHHashTree();

	const CAICHHash &GetHash() const	{ return m_Hash; }
	uint64 GetNDataSize() const		{ return m_nDataSize; }
	uint64 GetNBaseSize() const		{ return m_nBaseSize; }
	bool GetIsLeftBranch() const		{ return m_bIsLeftBranch; }
	bool GetHashValid() const		{ return m_bHashValid; }

	void SetBlockHash(uint64 nSize, uint64 nStartPos, CAICHHashAlgo* pHashAlg);
	bool ReCalculateHash(CAICHHashAlgo* hashalg, bool bDontReplace );
	bool VerifyHashTree(CAICHHashAlgo* hashalg, bool bDeleteBadTrees);
	CAICHHashTree* FindHash(uint64 nStartPos, uint64 nSize)
	{
		uint8 buffer = 0;
		return FindHash(nStartPos, nSize, &buffer);
	}

protected:
	CAICHHashTree* FindHash(uint64 nStartPos, uint64 nSize, uint8* nLevel);
	bool CreatePartRecoveryData(uint64 nStartPos, uint64 nSize,
		CFileDataIO* fileDataOut, uint32 wHashIdent, bool b32BitIdent);
	void WriteHash(CFileDataIO* fileDataOut, uint32 wHashIdent, bool b32BitIdent) const;
	bool WriteLowestLevelHashs(CFileDataIO* fileDataOut,
		uint32 wHashIdent, bool bNoIdent, bool b32BitIdent) const;
	bool LoadLowestLevelHashs(CFileDataIO* fileInput);
	bool SetHash(CFileDataIO* fileInput, uint32 wHashIdent, sint8 nLevel = (-1), bool bAllowOverwrite = true);
};

/////////////////////////////////////////////////////////////////////////////////////////
///CAICHUntrustedHashs
class CAICHUntrustedHash {
public:
	CAICHUntrustedHash& operator=(const CAICHUntrustedHash& k1)
	{
		m_adwIpsSigning = k1.m_adwIpsSigning;
		m_Hash = k1.m_Hash ;
		return *this;
	}
	bool AddSigningIP(uint32 dwIP);

	CAICHHash m_Hash;
	std::set<uint32> m_adwIpsSigning;
};

/////////////////////////////////////////////////////////////////////////////////////////
///CAICHUntrustedHashs
class CAICHRequestedData {
public:
	CAICHRequestedData()
	{
		m_nPart = 0;
		m_pPartFile = NULL;
	}
	CAICHRequestedData& operator=(const CAICHRequestedData& k1)
	{
		m_nPart = k1.m_nPart;
		m_pPartFile = k1.m_pPartFile;
		m_pClient = k1.m_pClient;
		return *this;
	}
	uint16 m_nPart;
	CPartFile* m_pPartFile;
	CClientRef m_pClient;
};


using namespace std;

typedef std::list<CAICHRequestedData> CAICHRequestedDataList;

/////////////////////////////////////////////////////////////////////////////////////////
///CAICHHashSet
class CAICHHashSet
{
private:
	CKnownFile* m_pOwner;
	EAICHStatus m_eStatus;
	deque<CAICHUntrustedHash> m_aUntrustedHashs;

public:
	static CAICHRequestedDataList m_liRequestedData;
	CAICHHashTree m_pHashTree;

	CAICHHashSet(CKnownFile* pOwner);
	~CAICHHashSet(void);
	bool CreatePartRecoveryData(uint64 nPartStartPos, CFileDataIO* fileDataOut, bool bDbgDontLoad = false);
	bool ReadRecoveryData(uint64 nPartStartPos, CMemFile* fileDataIn);
	bool ReCalculateHash(bool bDontReplace = false);
	bool VerifyHashTree(bool bDeleteBadTrees);
	void UntrustedHashReceived(const CAICHHash& Hash, uint32 dwFromIP);
	bool IsPartDataAvailable(uint64 nPartStartPos);
	void SetStatus(EAICHStatus bNewValue)	{ m_eStatus = bNewValue; }
	EAICHStatus GetStatus()	const		{ return m_eStatus; }

	void FreeHashSet();
	void SetFileSize(uint64 nSize);

	CAICHHash& GetMasterHash()		{ return m_pHashTree.m_Hash; }
	void SetMasterHash(const CAICHHash& Hash, EAICHStatus eNewStatus);
	bool HasValidMasterHash()		{ return m_pHashTree.m_bHashValid; }

	bool SaveHashSet();
	bool LoadHashSet(); // only call directly when debugging

	static CAICHHashAlgo* GetNewHashAlgo();
	static void ClientAICHRequestFailed(CUpDownClient* pClient);
	static void RemoveClientAICHRequest(const CUpDownClient* pClient);
	static bool IsClientRequestPending(const CPartFile* pForFile, uint16 nPart);
	static CAICHRequestedData GetAICHReqDetails(const  CUpDownClient* pClient);
	void DbgTest();

	void SetOwner(CKnownFile* owner)	{ m_pOwner = owner; }
};

#endif  //__SHAHAHSET_H__

// File_checked_for_headers