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 <zlib.h>		// Needed for uLongf
27
28#include "Packet.h"				// Interface declarations
29
30#include <protocol/Protocols.h>
31
32#include "Logger.h"			// Neeed for AddDebugLogLineN
33#include "MemFile.h"			// Needed for CMemFile
34#include "OtherStructs.h"		// Needed for Header_Struct
35#include "ArchSpecific.h"		// Needed for ENDIAN_*
36
37// Copy constructor
38CPacket::CPacket(CPacket &p)
39{
40	size 		= p.size;
41	opcode		= p.opcode;
42	prot 		= p.prot;
43	m_bSplitted 	= p.m_bSplitted;
44	m_bLastSplitted = p.m_bLastSplitted;
45	m_bPacked 	= p.m_bPacked;
46	m_bFromPF 	= p.m_bFromPF;
47	memcpy(head, p.head, sizeof head);
48	tempbuffer	= NULL;
49	if (p.completebuffer) {
50		completebuffer 	= new byte[size + 10];;
51		pBuffer 	= completebuffer + sizeof(Header_Struct);
52	} else {
53		completebuffer 	= NULL;
54		if (p.pBuffer) {
55			pBuffer = new byte[size];
56		} else {
57			pBuffer = NULL;
58		}
59	}
60	if (pBuffer)
61		memcpy( pBuffer, p.pBuffer, size );
62}
63
64CPacket::CPacket(uint8 protocol)
65{
66	size 		= 0;
67	opcode		= 0;
68	prot 		= protocol;
69	m_bSplitted 	= false;
70	m_bLastSplitted = false;
71	m_bPacked 	= false;
72	m_bFromPF 	= false;
73	memset(head, 0, sizeof head);
74	tempbuffer	= NULL;
75	completebuffer 	= NULL;
76	pBuffer 	= NULL;
77}
78
79// only used for receiving packets
80CPacket::CPacket(byte* rawHeader, byte *buf)
81{
82	memset(head, 0, sizeof head);
83	Header_Struct* header = (Header_Struct*)rawHeader;
84	size 		= ENDIAN_SWAP_32(header->packetlength) - 1;
85	opcode		= header->command;
86	prot		= header->eDonkeyID;
87	m_bSplitted 	= false;
88	m_bLastSplitted = false;
89	m_bPacked 	= false;
90	m_bFromPF 	= false;
91	tempbuffer	= NULL;
92	completebuffer 	= NULL;
93	pBuffer 	= buf;
94}
95
96CPacket::CPacket(const CMemFile& datafile, uint8 protocol, uint8 ucOpcode)
97{
98	size		= datafile.GetLength();
99	opcode		= ucOpcode;
100	prot		= protocol;
101	m_bSplitted 	= false;
102	m_bLastSplitted = false;
103	m_bPacked 	= false;
104	m_bFromPF 	= false;
105	memset(head, 0, sizeof head);
106	tempbuffer = NULL;
107	completebuffer = new byte[size + sizeof(Header_Struct)/*Why this 4?*/];
108	pBuffer = completebuffer + sizeof(Header_Struct);
109
110	// Write contents of MemFile to buffer (while keeping original position in file)
111	off_t position = datafile.GetPosition();
112	datafile.Seek(0, wxFromStart);
113	datafile.Read(pBuffer, size);
114	datafile.Seek(position, wxFromStart);
115}
116
117CPacket::CPacket(int8 in_opcode, uint32 in_size, uint8 protocol, bool bFromPF)
118{
119	size		= in_size;
120	opcode		= in_opcode;
121	prot		= protocol;
122	m_bSplitted 	= false;
123	m_bLastSplitted = false;
124	m_bPacked 	= false;
125	m_bFromPF	= bFromPF;
126	memset(head, 0, sizeof head);
127	tempbuffer	= NULL;
128	if (in_size) {
129		completebuffer = new byte[in_size + sizeof(Header_Struct) + 4 /*Why this 4?*/];
130		pBuffer = completebuffer + sizeof(Header_Struct);
131		memset(completebuffer, 0, in_size + sizeof(Header_Struct) + 4 /*Why this 4?*/);
132	} else {
133		completebuffer = NULL;
134		pBuffer = NULL;
135	}
136}
137
138// only used for splitted packets!
139CPacket::CPacket(byte* pPacketPart, uint32 nSize, bool bLast, bool bFromPF)
140{
141	size		= nSize - sizeof(Header_Struct);
142	opcode		= 0;
143	prot		= 0;
144	m_bSplitted	= true;
145	m_bLastSplitted	= bLast;
146	m_bPacked	= false;
147	m_bFromPF	= bFromPF;
148	memset(head, 0, sizeof head);
149	tempbuffer	= NULL;
150	completebuffer	= pPacketPart;
151	pBuffer		= NULL;
152}
153
154CPacket::~CPacket()
155{
156	// Never deletes pBuffer when completebuffer is not NULL
157	if (completebuffer) {
158		delete [] completebuffer;
159	} else if (pBuffer) {
160	// On the other hand, if completebuffer is NULL and pBuffer is not NULL
161		delete [] pBuffer;
162	}
163
164	if (tempbuffer) {
165		delete [] tempbuffer;
166	}
167}
168
169uint32 CPacket::GetPacketSizeFromHeader(const byte* rawHeader)
170{
171	Header_Struct* header = (Header_Struct*)rawHeader;
172	uint32 size = ENDIAN_SWAP_32(header->packetlength);
173	if (size < 1 || size >= 0x7ffffff0u)
174		return 0;
175	return size - 1;
176}
177
178void CPacket::CopyToDataBuffer(unsigned int offset, const byte* data, unsigned int n)
179{
180	wxASSERT(offset + n <= size + 1);
181	memcpy(pBuffer + offset, data, n);
182}
183
184byte* CPacket::GetPacket() {
185	if (completebuffer) {
186		if (!m_bSplitted) {
187			memcpy(completebuffer, GetHeader(), sizeof(Header_Struct));
188		}
189		return completebuffer;
190	} else {
191		if (tempbuffer){
192			delete [] tempbuffer;
193			tempbuffer = NULL;
194		}
195		tempbuffer = new byte[size + sizeof(Header_Struct) + 4 /* why this 4?*/];
196		memcpy(tempbuffer    , GetHeader(), sizeof(Header_Struct));
197		memcpy(tempbuffer + sizeof(Header_Struct), pBuffer    , size);
198		return tempbuffer;
199	}
200}
201
202byte* CPacket::DetachPacket() {
203	if (completebuffer) {
204		if (!m_bSplitted) {
205			memcpy(completebuffer, GetHeader(), sizeof(Header_Struct));
206		}
207		byte* result = completebuffer;
208		completebuffer = pBuffer = NULL;
209		return result;
210	} else{
211		if (tempbuffer){
212			delete[] tempbuffer;
213			tempbuffer = NULL;
214		}
215		tempbuffer = new byte[size+sizeof(Header_Struct)+4 /* Why this 4?*/];
216		memcpy(tempbuffer,GetHeader(),sizeof(Header_Struct));
217		memcpy(tempbuffer+sizeof(Header_Struct),pBuffer,size);
218		byte* result = tempbuffer;
219		tempbuffer = 0;
220		return result;
221	}
222}
223
224byte* CPacket::GetHeader() {
225	wxASSERT( !m_bSplitted );
226
227	Header_Struct* header = (Header_Struct*) head;
228	header->command = opcode;
229	header->eDonkeyID =  prot;
230	header->packetlength = ENDIAN_SWAP_32(size + 1);
231
232	return head;
233}
234
235byte* CPacket::GetUDPHeader() {
236	wxASSERT( !m_bSplitted );
237
238	memset(head, 0, 6);
239	UDP_Header_Struct* header = (UDP_Header_Struct*) head;
240	header->eDonkeyID =  prot;
241	header->command = opcode;
242
243	return head;
244}
245
246
247void CPacket::PackPacket()
248{
249	wxASSERT(!m_bSplitted);
250
251	uLongf newsize = size + 300;
252	byte* output = new byte[newsize];
253
254	uint16 result = compress2(output, &newsize, pBuffer, size, Z_BEST_COMPRESSION);
255
256	if (result != Z_OK || size <= newsize) {
257		delete[] output;
258		return;
259	}
260
261	if (prot == OP_KADEMLIAHEADER) {
262		prot = OP_KADEMLIAPACKEDPROT;
263	} else {
264		prot = OP_PACKEDPROT;
265	}
266
267	memcpy(pBuffer, output, newsize);
268	delete[] output;
269	m_bPacked = true;
270
271	size = newsize;
272}
273
274
275bool CPacket::UnPackPacket(uint32 uMaxDecompressedSize) {
276	wxASSERT( prot == OP_PACKEDPROT || prot == OP_ED2KV2PACKEDPROT);
277	// OP_ED2KV2PACKEDPROT is experimental aMule test code,
278	// this should not happen yet. Leave a warining in the log.
279	if (prot == OP_ED2KV2PACKEDPROT) {
280		AddDebugLogLineN(logPacketErrors,
281			wxT("Received OP_ED2KV2PACKEDPROT."));
282	}
283
284	uint32 nNewSize = size * 10 + 300;
285
286	if (nNewSize > uMaxDecompressedSize){
287		nNewSize = uMaxDecompressedSize;
288	}
289
290	byte* unpack = new byte[nNewSize];
291	uLongf unpackedsize = nNewSize;
292	uint16 result = uncompress(unpack, &unpackedsize, pBuffer, size);
293
294	if (result == Z_OK) {
295		wxASSERT( completebuffer == NULL );
296		wxASSERT( pBuffer != NULL );
297
298		size = unpackedsize;
299		delete[] pBuffer;
300		pBuffer = unpack;
301		prot = OP_EMULEPROT;
302		return true;
303	}
304
305	delete[] unpack;
306	return false;
307}
308
309
310void CPacket::Copy16ToDataBuffer(const void* data)
311{
312	md4cpy(pBuffer, data);
313}
314
315
316void CPacket::CopyUInt32ToDataBuffer(uint32 data, unsigned int offset)
317{
318	wxCHECK_RET(offset <= size - sizeof(uint32), wxT("Bad offset in CopyUInt32ToDataBuffer."));
319	PokeUInt32( pBuffer + offset, data );
320}
321// File_checked_for_headers
322