2
* Copyright (c) 2004, Jeroen Asselman
4
*----------------------------------------------------------------------
5
* This file is part of gtk-gnutella.
7
* gtk-gnutella is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* gtk-gnutella is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with gtk-gnutella; if not, write to the Free Software
20
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*----------------------------------------------------------------------
28
* G2 packet parser / constructor.
30
* @author Jeroen Asselman
41
char *g2_packet_pack(g2packet_t *packet, int *length);
42
int g2_packet_calc_new_length(g2packet_t *packet);
43
void g2_packet2buf(g2packet_t *packet, char *destination);
48
* Creates a new G2 packet.
53
return (g2packet_t *) malloc(sizeof(g2packet_t));
59
* Frees a g2 packet and any associated memory. This will also
60
* free a payload assigned.
63
g2_free_packet(g2packet_t *packet)
65
if (packet->name != NULL)
68
if (packet->orig_payload != NULL)
69
free(packet->orig_payload);
75
*** Parse packet functions
81
* Parse the packet header to extract length information.
84
g2_parse_header(char **buffer, g2packet_t *packet)
86
char *source = *buffer;
87
char len_length = ( *source & 0xC0 ) >> 6;
88
char flags = ( *source & 0x07 );
90
packet->name_length = (( *source & 0x38 ) >> 3) + 1;
94
packet->big_endian = ( flags & 0x02 ) > 0;
95
packet->compound = ( flags & 0x04 ) > 0;
97
if (packet->big_endian)
100
for (i = 0; i < len_length; i++)
102
packet->payload_length *= 0xFF;
103
packet->payload_length += *source++;
109
for (i = len_length; i > 0; i--)
111
packet->payload_length += 0xFF;
112
packet->payload_length += *source++;
116
if (packet->payload_length > 0)
118
packet->has_children = packet->compound;
127
* Parse the g2 packet to retreive the start of the payload/children
130
g2_parse_packet(char **buffer, g2packet_t *packet)
132
char *source = *buffer;
134
g2_parse_header(buffer, packet);
136
packet->name = (char *) malloc(packet->name_length + 1);
137
memcpy(packet->name, source, packet->name_length);
138
*(packet->name + packet->name_length) = '\0';
140
printf("[G2] '%s' %s children, payload length %d\n", packet->name,
141
packet->has_children ? "has" : "doesn't", packet->payload_length);
143
packet->payload = (char *) malloc(packet->payload_length);
144
packet->orig_payload = packet->payload;
145
memcpy(packet->payload, source, packet->payload_length);
146
source += packet->payload_length;
150
* Get the packet name.
152
* Retreives the name of the packet.
154
* @return a name string.
157
g2_packet_get_name(g2packet_t *packet)
163
* Get the next child from the current packet.
165
* Retreives the next child packet from the current packet and moves to the
166
* next child packet. Next time this function is called the next child packet
169
* @return the child packet or NULL if no (more) child packets are available.
172
g2_packet_get_next_child(g2packet_t *basepacket)
174
g2packet_t *packet = NULL;
175
char *before = basepacket->payload;
177
if (!basepacket->compound)
180
g2_parse_packet(&basepacket->payload, packet);
181
basepacket->payload_length -= basepacket->payload - before;
183
if (basepacket->payload_length == 0 ||
184
(*basepacket->payload == '0' && packet->payload_length != 0))
185
basepacket->compound = FALSE;
193
* After this it isn't possible anymore to retreive any children. As it will
197
g2_packet_get_payload(g2packet_t *packet, int *length)
199
g2packet_t *packet_parser = g2_new_packet();
201
/* Skip any children */
202
while (packet->compound)
204
char *before = packet->payload;
206
g2_parse_header(&packet->payload, packet_parser); // This advances after the header
207
packet->payload += packet_parser->payload_length; // This advances after the payload
209
packet->payload_length -= (int) (packet->payload - before);
211
if (packet->payload_length < 0)
213
printf("[G2] Invalid packet\n");
215
g2_free_packet(packet_parser);
220
if (*packet->payload == '\0' || packet->payload_length == 0)
221
packet->compound = FALSE;
224
g2_free_packet(packet_parser);
226
if (packet->payload_length == 0)
229
*length = packet->payload_length;
231
return packet->payload;
235
*** Create packet functions
239
* Add child to packet.
241
* Adds a child packet to the packet. Do _not_ add child packets after adding
244
* @param packet is a pointer to the packet to which the child should be added.
245
* @param child is a pointer to the packet to add.
248
g2_packet_add_child(g2packet_t *packet, g2packet_t *child)
253
buffer = g2_packet_pack(child, &length);
255
if (packet->payload == NULL) {
256
packet->orig_payload = (char *) malloc(length);
257
packet->payload = packet->orig_payload;
259
int diff = packet->payload - packet->orig_payload;
261
packet->orig_payload = (char *) realloc(packet->orig_payload,
262
packet->payload_length + length);
264
/* Set payload to the new not used memory space */
265
packet->payload = packet->orig_payload + diff + length;
268
memcpy(packet->payload, buffer, length);
269
packet->has_children = TRUE;
270
packet->payload_length += length;
273
/* Payload points again to the newly added child */
277
* G2 Packet add payload.
279
* Adds a payload to the current packet. After this do _NOT_ add children
282
* @param packet is a pointer to the packet to which the payload should be
284
* @param payload is a pointer to the payload which will be added to the packet.
285
* @param length is the length of the payload to add.
288
g2_packet_add_payload(g2packet_t *packet, char *payload, int length)
290
if (packet->orig_payload != NULL) {
291
int diff = packet->payload - packet->orig_payload;
292
int extra = length + packet->has_children ? 1 : 0;
294
packet->orig_payload = (char *) realloc(packet->orig_payload,
295
packet->payload_length + extra);
297
packet->payload = packet->orig_payload + diff;
299
if (packet->has_children)
301
*packet->payload = '0';
303
packet->payload_length++;
307
memcpy(packet->payload, payload, length);
308
packet->payload_length += length;
310
/* Payload now points to the newly added payload */
312
g_assert(packet->orig_payload - packet->payload ==
313
packet->payload_length - length);
319
* Construct a buffer from a G2Packet and return the newly allocated
322
* @return a pointer to the buffer containing the packed G2Packet.
325
g2_packet_pack(g2packet_t *packet, int *length)
327
*length = g2_packet_calc_new_length(packet);
328
char *buffer = (char *) malloc(*length);
330
g2_packet2buf(packet, buffer);
336
* Calculate the lenlength field from a given length.
339
g2_packet_calc_lenlength(int length)
341
if (length > 0xFFFFFF)
353
* G2 Packet calculate length/
355
* Calculates the size that will be used by this G2Packet when transformed
356
* to a buffer / char pointer.
358
* @return the length of the G2Packet when transformed to a buffer.
361
g2_packet_calc_new_length(g2packet_t *packet)
367
length += packet->name_length;
370
length += g2_packet_calc_lenlength(packet->payload_length);
373
length += packet->payload_length;
381
* In the destination pointer a g2 packet is constructed from the given
383
* The destination should be at least the size retreived with
384
* g2_packet_calc_new_length(packet).
387
g2_packet2buf(g2packet_t *packet, char *destination)
392
len_length = g2_packet_calc_lenlength(packet->payload_length);
394
if (packet->payload_length > 0)
396
packet->has_children = packet->compound;
400
packet->compound = packet->has_children;
402
packet->compound = TRUE;
406
*destination |= (len_length << 6);
407
*destination |= ((packet->name_length - 1) << 3);
409
if (packet->compound)
410
*destination |= 0x04;
411
if (packet->big_endian)
412
*destination |= 0x02;
414
/* Advance to next byte, control byte is now finished. */
418
for (i = 0; i < packet->name_length; i++)
420
*destination = packet->name[i];
424
/* Insert payload length */
425
*destination = packet->payload_length;
426
if (!packet->big_endian)
427
memmove(destination, destination + sizeof(int) - len_length, len_length);
429
destination += len_length;
431
memcpy(destination, packet->orig_payload, packet->payload_length);
434
/* vi: set ts=4 sw=4 cindent: */