1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
10//
11// This program is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
24//
25
26#include "ClientCredits.h"	// Interface declarations
27
28#include <cmath>
29
30#include "GetTickCount.h"	// Needed for GetTickCount
31#include "Logger.h"			// Needed for Add(Debug)LogLine
32
33CreditStruct::CreditStruct()
34	: uploaded(0),
35	  downloaded(0),
36	  nLastSeen(0),
37	  nReserved3(0),
38	  nKeySize(0)
39{
40	memset(abySecureIdent, 0, MAXPUBKEYSIZE);
41}
42
43
44CClientCredits::CClientCredits(CreditStruct* in_credits)
45{
46	m_pCredits = in_credits;
47	InitalizeIdent();
48	m_dwUnSecureWaitTime = 0;
49	m_dwSecureWaitTime = 0;
50	m_dwWaitTimeIP = 0;
51}
52
53
54CClientCredits::CClientCredits(const CMD4Hash& key)
55{
56	m_pCredits = new CreditStruct();
57	m_pCredits->key = key;
58
59	InitalizeIdent();
60	m_dwUnSecureWaitTime = ::GetTickCount();
61	m_dwSecureWaitTime = ::GetTickCount();
62	m_dwWaitTimeIP = 0;
63}
64
65
66CClientCredits::~CClientCredits()
67{
68	delete m_pCredits;
69}
70
71
72void CClientCredits::AddDownloaded(uint32 bytes, uint32 dwForIP, bool cryptoavail)
73{
74	switch (GetCurrentIdentState(dwForIP)) {
75		case IS_IDFAILED:
76		case IS_IDBADGUY:
77		case IS_IDNEEDED:
78			if (cryptoavail) {
79				return;
80			}
81			break;
82	 	case IS_NOTAVAILABLE:
83	 	case IS_IDENTIFIED:
84			break;
85	}
86
87	m_pCredits->downloaded += bytes;
88}
89
90
91void CClientCredits::AddUploaded(uint32 bytes, uint32 dwForIP, bool cryptoavail)
92{
93	switch (GetCurrentIdentState(dwForIP)) {
94		case IS_IDFAILED:
95		case IS_IDBADGUY:
96		case IS_IDNEEDED:
97			if (cryptoavail) {
98				return;
99			}
100			break;
101	 	case IS_NOTAVAILABLE:
102	 	case IS_IDENTIFIED:
103			break;
104	}
105
106	m_pCredits->uploaded += bytes;
107}
108
109
110uint64 CClientCredits::GetUploadedTotal() const
111{
112	return m_pCredits->uploaded;
113}
114
115
116uint64	CClientCredits::GetDownloadedTotal() const
117{
118	return m_pCredits->downloaded;
119}
120
121
122float CClientCredits::GetScoreRatio(uint32 dwForIP, bool cryptoavail)
123{
124	// check the client ident status
125	switch (GetCurrentIdentState(dwForIP)) {
126		case IS_IDFAILED:
127		case IS_IDBADGUY:
128		case IS_IDNEEDED:
129			if (cryptoavail) {
130				// bad guy - no credits for you
131				return 1.0f;
132			}
133			break;
134	 	case IS_NOTAVAILABLE:
135	 	case IS_IDENTIFIED:
136			break;
137	}
138
139	if (GetDownloadedTotal() < 1000000) {
140		return 1.0f;
141	}
142
143	float result = 0.0f;
144	if (!GetUploadedTotal()) {
145		result = 10.0f;
146	} else {
147		result = (GetDownloadedTotal() * 2.0f) / GetUploadedTotal();
148	}
149
150	float result2 = sqrt((GetDownloadedTotal() / 1048576.0) + 2.0f);
151	if (result > result2) {
152		result = result2;
153	}
154
155	if (result < 1.0f) {
156		return 1.0f;
157	} else if (result > 10.0f) {
158		return 10.0f;
159	}
160
161	return result;
162}
163
164
165void CClientCredits::SetLastSeen()
166{
167	m_pCredits->nLastSeen = time(NULL);
168}
169
170
171void CClientCredits::InitalizeIdent()
172{
173	if (m_pCredits->nKeySize == 0 ){
174		memset(m_abyPublicKey,0,80); // for debugging
175		m_nPublicKeyLen = 0;
176		m_identState = IS_NOTAVAILABLE;
177	}
178	else{
179		m_nPublicKeyLen = m_pCredits->nKeySize;
180		memcpy(m_abyPublicKey, m_pCredits->abySecureIdent, m_nPublicKeyLen);
181		m_identState = IS_IDNEEDED;
182	}
183	m_dwCryptRndChallengeFor = 0;
184	m_dwCryptRndChallengeFrom = 0;
185	m_dwIdentIP = 0;
186}
187
188
189void CClientCredits::Verified(uint32 dwForIP)
190{
191	m_dwIdentIP = dwForIP;
192	// client was verified, copy the keyto store him if not done already
193	if (m_pCredits->nKeySize == 0){
194		m_pCredits->nKeySize = m_nPublicKeyLen;
195		memcpy(m_pCredits->abySecureIdent, m_abyPublicKey, m_nPublicKeyLen);
196		if (GetDownloadedTotal() > 0){
197			// for security reason, we have to delete all prior credits here
198			// in order to save this client, set 1 byte
199			m_pCredits->downloaded = 1;
200			m_pCredits->uploaded = 1;
201			AddDebugLogLineN( logCredits, wxT("Credits deleted due to new SecureIdent") );
202		}
203	}
204	m_identState = IS_IDENTIFIED;
205}
206
207
208bool CClientCredits::SetSecureIdent(const byte* pachIdent, uint8 nIdentLen)
209{ // verified Public key cannot change, use only if there is not public key yet
210	if (MAXPUBKEYSIZE < nIdentLen || m_pCredits->nKeySize != 0 ) {
211		return false;
212	}
213	memcpy(m_abyPublicKey,pachIdent, nIdentLen);
214	m_nPublicKeyLen = nIdentLen;
215	m_identState = IS_IDNEEDED;
216	return true;
217}
218
219
220EIdentState	CClientCredits::GetCurrentIdentState(uint32 dwForIP) const
221{
222	if (m_identState != IS_IDENTIFIED)
223		return m_identState;
224	else{
225		if (dwForIP == m_dwIdentIP)
226			return IS_IDENTIFIED;
227		else
228			return IS_IDBADGUY;
229			// mod note: clients which just reconnected after an IP change and have to ident yet will also have this state for 1-2 seconds
230			//		 so don't try to spam such clients with "bad guy" messages (besides: spam messages are always bad)
231	}
232}
233
234
235uint32 CClientCredits::GetSecureWaitStartTime(uint32 dwForIP)
236{
237	if (m_dwUnSecureWaitTime == 0 || m_dwSecureWaitTime == 0)
238		SetSecWaitStartTime(dwForIP);
239
240	if (m_pCredits->nKeySize != 0){	// this client is a SecureHash Client
241		if (GetCurrentIdentState(dwForIP) == IS_IDENTIFIED){ // good boy
242			return m_dwSecureWaitTime;
243		}
244		else{	// not so good boy
245			if (dwForIP == m_dwWaitTimeIP){
246				return m_dwUnSecureWaitTime;
247			}
248			else{	// bad boy
249				// this can also happen if the client has not identified himself yet, but will do later - so maybe he is not a bad boy :) .
250
251				m_dwUnSecureWaitTime = ::GetTickCount();
252				m_dwWaitTimeIP = dwForIP;
253				return m_dwUnSecureWaitTime;
254			}
255		}
256	}
257	else{	// not a SecureHash Client - handle it like before for now (no security checks)
258		return m_dwUnSecureWaitTime;
259	}
260}
261
262
263void CClientCredits::SetSecWaitStartTime(uint32 dwForIP)
264{
265	m_dwUnSecureWaitTime = ::GetTickCount()-1;
266	m_dwSecureWaitTime = ::GetTickCount()-1;
267	m_dwWaitTimeIP = dwForIP;
268}
269
270
271void CClientCredits::ClearWaitStartTime()
272{
273	m_dwUnSecureWaitTime = 0;
274	m_dwSecureWaitTime = 0;
275}
276
277// File_checked_for_headers
278