~ubuntu-branches/ubuntu/karmic/gtk-gnutella/karmic

« back to all changes in this revision

Viewing changes to src/g2/packet.c

  • Committer: Bazaar Package Importer
  • Author(s): Anand Kumria
  • Date: 2005-08-04 11:32:05 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20050804113205-q746i4lgo3rtlegn
Tags: 0.95.4-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2004, Jeroen Asselman
 
3
 *
 
4
 *----------------------------------------------------------------------
 
5
 * This file is part of gtk-gnutella.
 
6
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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
 
19
 *  Foundation, Inc.:
 
20
 *      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
21
 *----------------------------------------------------------------------
 
22
 */
 
23
 
 
24
/**
 
25
 * @ingroup undoc
 
26
 * @file
 
27
 *
 
28
 * G2 packet parser / constructor.
 
29
 *
 
30
 * @author Jeroen Asselman
 
31
 * @date 2004
 
32
 */
 
33
 
 
34
#include <glib.h>
 
35
#include <stdlib.h>
 
36
#include <string.h>
 
37
#include <stdio.h>
 
38
 
 
39
#include "packet.h"
 
40
 
 
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);
 
44
 
 
45
/**
 
46
 * G2 New Packet.
 
47
 *
 
48
 * Creates a new G2 packet.
 
49
 */
 
50
g2packet_t *
 
51
g2_new_packet()
 
52
{
 
53
        return (g2packet_t *) malloc(sizeof(g2packet_t));
 
54
}
 
55
 
 
56
/**
 
57
 * G2 free packet.
 
58
 *
 
59
 * Frees a g2 packet and any associated memory. This will also
 
60
 * free a payload assigned.
 
61
 */
 
62
void
 
63
g2_free_packet(g2packet_t *packet)
 
64
{
 
65
        if (packet->name != NULL)
 
66
                free(packet->name);
 
67
 
 
68
        if (packet->orig_payload != NULL)
 
69
                free(packet->orig_payload);
 
70
 
 
71
        free(packet);
 
72
}
 
73
 
 
74
/***
 
75
 *** Parse packet functions
 
76
 ***/
 
77
 
 
78
/**
 
79
 * g2 parse header.
 
80
 *
 
81
 * Parse the packet header to extract length information.
 
82
 */
 
83
void
 
84
g2_parse_header(char **buffer, g2packet_t *packet)
 
85
{
 
86
        char *source    = *buffer;
 
87
        char len_length = ( *source & 0xC0 ) >> 6;
 
88
        char flags              = ( *source & 0x07 );
 
89
 
 
90
        packet->name_length     = (( *source & 0x38 ) >> 3) + 1;
 
91
 
 
92
        source++;
 
93
 
 
94
        packet->big_endian      = ( flags & 0x02 ) > 0;
 
95
        packet->compound        = ( flags & 0x04 ) > 0;
 
96
 
 
97
        if (packet->big_endian)
 
98
        {
 
99
                int i;
 
100
                for (i = 0; i < len_length; i++)
 
101
                {
 
102
                        packet->payload_length *= 0xFF;
 
103
                        packet->payload_length += *source++;
 
104
                }
 
105
        }
 
106
        else
 
107
        {
 
108
                int i;
 
109
                for (i = len_length; i > 0; i--)
 
110
                {
 
111
                        packet->payload_length += 0xFF;
 
112
                        packet->payload_length += *source++;
 
113
                }
 
114
        }
 
115
 
 
116
        if (packet->payload_length > 0)
 
117
        {
 
118
                packet->has_children = packet->compound;
 
119
        }
 
120
 
 
121
        *buffer = source;
 
122
}
 
123
 
 
124
/**
 
125
 * G2 Parse packet.
 
126
 *
 
127
 * Parse the g2 packet to retreive the start of the payload/children
 
128
 */
 
129
void
 
130
g2_parse_packet(char **buffer, g2packet_t *packet)
 
131
{
 
132
        char *source = *buffer;
 
133
 
 
134
        g2_parse_header(buffer, packet);
 
135
 
 
136
        packet->name = (char *) malloc(packet->name_length + 1);
 
137
        memcpy(packet->name, source, packet->name_length);
 
138
        *(packet->name + packet->name_length) = '\0';
 
139
 
 
140
        printf("[G2] '%s' %s children, payload length %d\n", packet->name,
 
141
                        packet->has_children ? "has" : "doesn't", packet->payload_length);
 
142
 
 
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;
 
147
}
 
148
 
 
149
/**
 
150
 * Get the packet name.
 
151
 *
 
152
 * Retreives the name of the packet.
 
153
 *
 
154
 * @return a name string.
 
155
 */
 
156
char *
 
157
g2_packet_get_name(g2packet_t *packet)
 
158
{
 
159
        return packet->name;
 
160
}
 
161
 
 
162
/**
 
163
 * Get the next child from the current packet.
 
164
 *
 
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
 
167
 * is returned.
 
168
 *
 
169
 * @return the child packet or NULL if no (more) child packets are available.
 
170
 */
 
171
g2packet_t *
 
172
g2_packet_get_next_child(g2packet_t *basepacket)
 
173
{
 
174
        g2packet_t *packet = NULL;
 
175
        char *before = basepacket->payload;
 
176
 
 
177
        if (!basepacket->compound)
 
178
                return NULL;
 
179
 
 
180
        g2_parse_packet(&basepacket->payload, packet);
 
181
        basepacket->payload_length -= basepacket->payload - before;
 
182
 
 
183
        if (basepacket->payload_length == 0 ||
 
184
                (*basepacket->payload == '0' && packet->payload_length != 0))
 
185
                basepacket->compound = FALSE;
 
186
 
 
187
        return packet;
 
188
}
 
189
 
 
190
/**
 
191
 * Get payload.
 
192
 *
 
193
 * After this it isn't possible anymore to retreive any children. As it will
 
194
 * fast skip them
 
195
 */
 
196
char *
 
197
g2_packet_get_payload(g2packet_t *packet, int *length)
 
198
{
 
199
        g2packet_t *packet_parser = g2_new_packet();
 
200
 
 
201
        /* Skip any children */
 
202
        while (packet->compound)
 
203
        {
 
204
                char *before = packet->payload;
 
205
 
 
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
 
208
 
 
209
                packet->payload_length -= (int) (packet->payload - before);
 
210
 
 
211
                if (packet->payload_length < 0)
 
212
                {
 
213
                        printf("[G2] Invalid packet\n");
 
214
 
 
215
                        g2_free_packet(packet_parser);
 
216
 
 
217
                        return NULL;
 
218
                }
 
219
 
 
220
                if (*packet->payload == '\0' || packet->payload_length == 0)
 
221
                        packet->compound = FALSE;
 
222
        }
 
223
 
 
224
        g2_free_packet(packet_parser);
 
225
 
 
226
        if (packet->payload_length == 0)
 
227
                return NULL;
 
228
 
 
229
        *length = packet->payload_length;
 
230
 
 
231
        return packet->payload;
 
232
}
 
233
 
 
234
/***
 
235
 *** Create packet functions
 
236
 ***/
 
237
 
 
238
/**
 
239
 * Add child to packet.
 
240
 *
 
241
 * Adds a child packet to the packet. Do _not_ add child packets after adding
 
242
 * a payload.
 
243
 *
 
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.
 
246
 */
 
247
void
 
248
g2_packet_add_child(g2packet_t *packet, g2packet_t *child)
 
249
{
 
250
        char *buffer = NULL;
 
251
        int length;
 
252
 
 
253
        buffer = g2_packet_pack(child, &length);
 
254
 
 
255
        if (packet->payload == NULL) {
 
256
                packet->orig_payload = (char *) malloc(length);
 
257
                packet->payload = packet->orig_payload;
 
258
        } else {
 
259
                int diff = packet->payload - packet->orig_payload;
 
260
 
 
261
                packet->orig_payload = (char *) realloc(packet->orig_payload,
 
262
                        packet->payload_length + length);
 
263
 
 
264
                /* Set payload to the new not used memory space */
 
265
                packet->payload = packet->orig_payload + diff + length;
 
266
        }
 
267
 
 
268
        memcpy(packet->payload, buffer, length);
 
269
        packet->has_children = TRUE;
 
270
        packet->payload_length += length;
 
271
 
 
272
        free(buffer);
 
273
        /* Payload points again to the newly added child */
 
274
}
 
275
 
 
276
/**
 
277
 * G2 Packet add payload.
 
278
 *
 
279
 * Adds a payload to the current packet. After this do _NOT_ add children
 
280
 * anymore.
 
281
 *
 
282
 * @param packet is a pointer to the packet to which the payload should be
 
283
 * added.
 
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.
 
286
 */
 
287
void
 
288
g2_packet_add_payload(g2packet_t *packet, char *payload, int length)
 
289
{
 
290
        if (packet->orig_payload != NULL) {
 
291
                int diff = packet->payload - packet->orig_payload;
 
292
                int extra = length + packet->has_children ? 1 : 0;
 
293
 
 
294
                packet->orig_payload = (char *) realloc(packet->orig_payload,
 
295
                        packet->payload_length + extra);
 
296
 
 
297
                packet->payload = packet->orig_payload + diff;
 
298
 
 
299
                if (packet->has_children)
 
300
                {
 
301
                        *packet->payload = '0';
 
302
                        packet->payload++;
 
303
                        packet->payload_length++;
 
304
                }
 
305
        }
 
306
 
 
307
        memcpy(packet->payload, payload, length);
 
308
        packet->payload_length += length;
 
309
 
 
310
        /* Payload now points to the newly added payload */
 
311
 
 
312
        g_assert(packet->orig_payload - packet->payload ==
 
313
                                packet->payload_length - length);
 
314
}
 
315
 
 
316
/**
 
317
 * G2 Packet pack.
 
318
 *
 
319
 * Construct a buffer from a G2Packet and return the newly allocated
 
320
 * buffer.
 
321
 *
 
322
 * @return a pointer to the buffer containing the packed G2Packet.
 
323
 */
 
324
char *
 
325
g2_packet_pack(g2packet_t *packet, int *length)
 
326
{
 
327
        *length = g2_packet_calc_new_length(packet);
 
328
        char *buffer = (char *) malloc(*length);
 
329
 
 
330
        g2_packet2buf(packet, buffer);
 
331
 
 
332
        return buffer;
 
333
}
 
334
 
 
335
/**
 
336
 * Calculate the lenlength field from a given length.
 
337
 */
 
338
static int
 
339
g2_packet_calc_lenlength(int length)
 
340
{
 
341
        if (length > 0xFFFFFF)
 
342
                return 4;
 
343
        if (length > 0xFFFF)
 
344
                return 3;
 
345
        if (length > 0xFF)
 
346
                return 2;
 
347
        if (length > 0x0)
 
348
                return 1;
 
349
        return 0;
 
350
}
 
351
 
 
352
/**
 
353
 * G2 Packet calculate length/
 
354
 *
 
355
 * Calculates the size that will be used by this G2Packet when transformed
 
356
 * to a buffer / char pointer.
 
357
 *
 
358
 * @return the length of the G2Packet when transformed to a buffer.
 
359
 */
 
360
int
 
361
g2_packet_calc_new_length(g2packet_t *packet)
 
362
{
 
363
        /* Control byte */
 
364
        int length = 1;
 
365
 
 
366
        /* name_length */
 
367
        length += packet->name_length;
 
368
 
 
369
        /* len_length */
 
370
        length += g2_packet_calc_lenlength(packet->payload_length);
 
371
 
 
372
        /* payload_length */
 
373
        length += packet->payload_length;
 
374
 
 
375
        return length;
 
376
}
 
377
 
 
378
/**
 
379
 * G2 Packet2buf.
 
380
 *
 
381
 * In the destination pointer a g2 packet is constructed from the given
 
382
 * G2Packet.
 
383
 * The destination should be at least the size retreived with
 
384
 * g2_packet_calc_new_length(packet).
 
385
 */
 
386
void
 
387
g2_packet2buf(g2packet_t *packet, char *destination)
 
388
{
 
389
        char len_length;
 
390
        int i;
 
391
 
 
392
        len_length =  g2_packet_calc_lenlength(packet->payload_length);
 
393
 
 
394
        if (packet->payload_length > 0)
 
395
        {
 
396
                packet->has_children = packet->compound;
 
397
        }
 
398
 
 
399
        if (len_length > 0)
 
400
                packet->compound = packet->has_children;
 
401
        else
 
402
                packet->compound = TRUE;
 
403
 
 
404
 
 
405
        *destination = '0';
 
406
        *destination |= (len_length << 6);
 
407
        *destination |= ((packet->name_length - 1) << 3);
 
408
 
 
409
        if (packet->compound)
 
410
                *destination |= 0x04;
 
411
        if (packet->big_endian)
 
412
                *destination |= 0x02;
 
413
 
 
414
        /* Advance to next byte, control byte is now finished. */
 
415
        destination++;
 
416
 
 
417
        /* Build name. */
 
418
        for (i = 0; i < packet->name_length; i++)
 
419
        {
 
420
                *destination = packet->name[i];
 
421
        destination++;
 
422
        }
 
423
 
 
424
        /* Insert payload length */
 
425
        *destination = packet->payload_length;
 
426
        if (!packet->big_endian)
 
427
                memmove(destination, destination + sizeof(int) - len_length, len_length);
 
428
 
 
429
        destination += len_length;
 
430
 
 
431
        memcpy(destination, packet->orig_payload, packet->payload_length);
 
432
}
 
433
 
 
434
/* vi: set ts=4 sw=4 cindent: */