annotate src/gt_packet.c @ 0:d39e1d0d75b6

initial add
author paulo@hit-nxdomain.opendns.com
date Sat, 20 Feb 2010 21:18:28 -0800
parents
children
rev   line source
paulo@0 1 /*
paulo@0 2 * $Id: gt_packet.c,v 1.35 2004/04/17 06:05:53 hipnod Exp $
paulo@0 3 *
paulo@0 4 * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net)
paulo@0 5 *
paulo@0 6 * This program is free software; you can redistribute it and/or modify it
paulo@0 7 * under the terms of the GNU General Public License as published by the
paulo@0 8 * Free Software Foundation; either version 2, or (at your option) any
paulo@0 9 * later version.
paulo@0 10 *
paulo@0 11 * This program is distributed in the hope that it will be useful, but
paulo@0 12 * WITHOUT ANY WARRANTY; without even the implied warranty of
paulo@0 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
paulo@0 14 * General Public License for more details.
paulo@0 15 */
paulo@0 16
paulo@0 17 #include "gt_gnutella.h"
paulo@0 18
paulo@0 19 #include "gt_packet.h"
paulo@0 20
paulo@0 21 #include "gt_node.h"
paulo@0 22 #include "gt_netorg.h"
paulo@0 23
paulo@0 24 #include "gt_utils.h"
paulo@0 25
paulo@0 26 #include "gt_query_route.h"
paulo@0 27 #include "message/gt_message.h" /* gt_vendor_msg_get_{id,version} */
paulo@0 28
paulo@0 29 #include <stdarg.h>
paulo@0 30
paulo@0 31 /*****************************************************************************/
paulo@0 32
paulo@0 33 GtPacket *gt_packet_new (uint8_t cmd, uint8_t ttl, gt_guid_t *guid)
paulo@0 34 {
paulo@0 35 GtPacket *packet;
paulo@0 36 unsigned char *data;
paulo@0 37
paulo@0 38 if (!(packet = MALLOC (sizeof (GtPacket))))
paulo@0 39 return NULL;
paulo@0 40
paulo@0 41 if (!(data = MALLOC (GT_PACKET_INITIAL)))
paulo@0 42 {
paulo@0 43 free (packet);
paulo@0 44 return NULL;
paulo@0 45 }
paulo@0 46
paulo@0 47 packet->data = data;
paulo@0 48 packet->len = GNUTELLA_HDR_LEN;
paulo@0 49 packet->data_len = GT_PACKET_INITIAL;
paulo@0 50
paulo@0 51 /*
paulo@0 52 * Caller could provide GUID or request it be randomly initialized.
paulo@0 53 */
paulo@0 54 if (guid)
paulo@0 55 gt_packet_set_guid (packet, guid);
paulo@0 56 else
paulo@0 57 gt_guid_init ((gt_guid_t *)packet->data);
paulo@0 58
paulo@0 59 gt_packet_set_command (packet, cmd);
paulo@0 60 gt_packet_set_ttl (packet, ttl);
paulo@0 61 gt_packet_set_payload_len (packet, 0);
paulo@0 62 gt_packet_set_hops (packet, 0);
paulo@0 63
paulo@0 64 /* set the offset to start at the end of the header */
paulo@0 65 packet->offset = GNUTELLA_HDR_LEN;
paulo@0 66
paulo@0 67 return packet;
paulo@0 68 }
paulo@0 69
paulo@0 70 GtPacket *gt_packet_reply (GtPacket *src, uint8_t cmd)
paulo@0 71 {
paulo@0 72 GtPacket *packet;
paulo@0 73 uint8_t hops;
paulo@0 74 gt_guid_t *guid;
paulo@0 75
paulo@0 76 hops = gt_packet_hops (src);
paulo@0 77 guid = gt_packet_guid (src);
paulo@0 78
paulo@0 79 if (!(packet = gt_packet_new (cmd, hops + 1, guid)))
paulo@0 80 return NULL;
paulo@0 81
paulo@0 82 return packet;
paulo@0 83 }
paulo@0 84
paulo@0 85 GtPacket *gt_packet_vendor (const gt_vendor_msg_t *vmsg)
paulo@0 86 {
paulo@0 87 GtPacket *pkt;
paulo@0 88
paulo@0 89 if (!(pkt = gt_packet_new (GT_MSG_VENDOR, 1, NULL)))
paulo@0 90 return NULL;
paulo@0 91
paulo@0 92 gt_packet_put_ustr (pkt, vmsg->vendor_id, 4);
paulo@0 93 gt_packet_put_uint16 (pkt, vmsg->id);
paulo@0 94 gt_packet_put_uint16 (pkt, 1); /* vmsg version */
paulo@0 95
paulo@0 96 if (gt_packet_error (pkt))
paulo@0 97 {
paulo@0 98 gt_packet_free (pkt);
paulo@0 99 return NULL;
paulo@0 100 }
paulo@0 101
paulo@0 102 return pkt;
paulo@0 103 }
paulo@0 104
paulo@0 105 void gt_packet_free (GtPacket *packet)
paulo@0 106 {
paulo@0 107 if (!packet)
paulo@0 108 return;
paulo@0 109
paulo@0 110 free (packet->data);
paulo@0 111 free (packet);
paulo@0 112 }
paulo@0 113
paulo@0 114 /*****************************************************************************/
paulo@0 115
paulo@0 116 gt_guid_t *gt_packet_guid (GtPacket *packet)
paulo@0 117 {
paulo@0 118 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 119
paulo@0 120 return packet->data;
paulo@0 121 }
paulo@0 122
paulo@0 123 uint32_t gt_packet_payload_len (GtPacket *packet)
paulo@0 124 {
paulo@0 125 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 126
paulo@0 127 return get_payload_len (packet->data);
paulo@0 128 }
paulo@0 129
paulo@0 130 uint32_t gt_packet_command (GtPacket *packet)
paulo@0 131 {
paulo@0 132 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 133
paulo@0 134 return get_command (packet->data);
paulo@0 135 }
paulo@0 136
paulo@0 137 uint8_t gt_packet_hops (GtPacket *packet)
paulo@0 138 {
paulo@0 139 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 140
paulo@0 141 return get_hops (packet->data);
paulo@0 142 }
paulo@0 143
paulo@0 144 uint8_t gt_packet_ttl (GtPacket *packet)
paulo@0 145 {
paulo@0 146 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 147
paulo@0 148 return get_ttl (packet->data);
paulo@0 149 }
paulo@0 150
paulo@0 151 /*****************************************************************************/
paulo@0 152
paulo@0 153 void gt_packet_set_guid (GtPacket *packet, gt_guid_t *guid)
paulo@0 154 {
paulo@0 155 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 156
paulo@0 157 memcpy (packet->data, guid, 16);
paulo@0 158 }
paulo@0 159
paulo@0 160 void gt_packet_set_command (GtPacket *packet, uint8_t cmd)
paulo@0 161 {
paulo@0 162 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 163
paulo@0 164 get_command (packet->data) = cmd;
paulo@0 165 }
paulo@0 166
paulo@0 167 void gt_packet_set_ttl (GtPacket *packet, uint8_t ttl)
paulo@0 168 {
paulo@0 169 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 170
paulo@0 171 get_ttl (packet->data) = ttl;
paulo@0 172 }
paulo@0 173
paulo@0 174 void gt_packet_set_hops (GtPacket *packet, uint8_t hops)
paulo@0 175 {
paulo@0 176 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 177
paulo@0 178 get_hops (packet->data) = hops;
paulo@0 179 }
paulo@0 180
paulo@0 181 void gt_packet_set_payload_len (GtPacket *packet, uint32_t len)
paulo@0 182 {
paulo@0 183 assert (packet->data_len >= GNUTELLA_HDR_LEN);
paulo@0 184
paulo@0 185 len = htovl (len);
paulo@0 186
paulo@0 187 memcpy (packet->data + 19, &len, 4);
paulo@0 188 }
paulo@0 189
paulo@0 190 /*****************************************************************************/
paulo@0 191 /* functions to read data from packets */
paulo@0 192
paulo@0 193 static uint8_t gt_get8 (unsigned char *src)
paulo@0 194 {
paulo@0 195 return *src;
paulo@0 196 }
paulo@0 197
paulo@0 198 #define copy_bytes(src,sz,endian,swap,sizedvar_t,swap_net,swap_vax) \
paulo@0 199 sizedvar_t r; \
paulo@0 200 sizedvar_t v; \
paulo@0 201 sizedvar_t n; \
paulo@0 202 \
paulo@0 203 memcpy (&r, src, sz); \
paulo@0 204 \
paulo@0 205 n = swap_net (r); \
paulo@0 206 \
paulo@0 207 assert_at_compile (BIG == 0x01); \
paulo@0 208 if (endian & swap) \
paulo@0 209 r = n; \
paulo@0 210 \
paulo@0 211 v = swap_vax (r); \
paulo@0 212 \
paulo@0 213 assert_at_compile (LITTLE == 0x00); \
paulo@0 214 if (~endian & swap) \
paulo@0 215 r = v; \
paulo@0 216 \
paulo@0 217 return r;
paulo@0 218
paulo@0 219 static uint16_t gt_get16 (unsigned char *src, int endian, int swap)
paulo@0 220 {
paulo@0 221 copy_bytes (src, 2, endian, swap, uint16_t, ntohs, vtohs);
paulo@0 222 }
paulo@0 223
paulo@0 224 static uint32_t gt_get32 (unsigned char *src, int endian, int swap)
paulo@0 225 {
paulo@0 226 copy_bytes (src, 4, endian, swap, uint32_t, ntohl, vtohl);
paulo@0 227 }
paulo@0 228
paulo@0 229 /*****************************************************************************/
paulo@0 230
paulo@0 231 static BOOL gt_packet_resize (GtPacket *packet, size_t len)
paulo@0 232 {
paulo@0 233 size_t resize_len;
paulo@0 234 unsigned char *resized;
paulo@0 235
paulo@0 236 if (!packet)
paulo@0 237 return FALSE;
paulo@0 238
paulo@0 239 assert (len >= GNUTELLA_HDR_LEN);
paulo@0 240 assert (len < GT_PACKET_MAX);
paulo@0 241
paulo@0 242 /* the buffer we have allocated is already large enough */
paulo@0 243 if (packet->data_len >= len)
paulo@0 244 return TRUE;
paulo@0 245
paulo@0 246 /* determine an appropriate resize length */
paulo@0 247 for (resize_len = packet->data_len; resize_len < len; )
paulo@0 248 {
paulo@0 249 if (resize_len == 0)
paulo@0 250 resize_len = GT_PACKET_INITIAL;
paulo@0 251 else
paulo@0 252 resize_len *= 2;
paulo@0 253 }
paulo@0 254
paulo@0 255 if (!(resized = realloc (packet->data, resize_len)))
paulo@0 256 {
paulo@0 257 packet->error = TRUE;
paulo@0 258 return FALSE;
paulo@0 259 }
paulo@0 260
paulo@0 261 memset (resized + packet->data_len, 0, resize_len - packet->data_len);
paulo@0 262
paulo@0 263 /* modify the packet structure to reflect this resize */
paulo@0 264 packet->data_len = resize_len;
paulo@0 265 packet->data = resized;
paulo@0 266
paulo@0 267 return TRUE;
paulo@0 268 }
paulo@0 269
paulo@0 270 int gt_packet_error (GtPacket *packet)
paulo@0 271 {
paulo@0 272 return packet->error;
paulo@0 273 }
paulo@0 274
paulo@0 275 int gt_packet_seek (GtPacket *packet, int offset)
paulo@0 276 {
paulo@0 277 int old_offset;
paulo@0 278
paulo@0 279 /* should we be setting packet->error here? */
paulo@0 280 if (offset >= packet->len || offset < 0)
paulo@0 281 {
paulo@0 282 packet->error = TRUE;
paulo@0 283 return -1;
paulo@0 284 }
paulo@0 285
paulo@0 286 old_offset = packet->offset;
paulo@0 287 packet->offset = offset;
paulo@0 288
paulo@0 289 return old_offset;
paulo@0 290 }
paulo@0 291
paulo@0 292 GtPacket *gt_packet_unserialize (unsigned char *data, size_t len)
paulo@0 293 {
paulo@0 294 GtPacket *packet;
paulo@0 295
paulo@0 296 if (!(packet = gt_packet_new (0, 0, NULL)))
paulo@0 297 return NULL;
paulo@0 298
paulo@0 299 if (len >= GT_PACKET_MAX)
paulo@0 300 {
paulo@0 301 gt_packet_free (packet);
paulo@0 302 return NULL;
paulo@0 303 }
paulo@0 304
paulo@0 305 if (!gt_packet_resize (packet, len))
paulo@0 306 {
paulo@0 307 GIFT_ERROR (("error resizing packet"));
paulo@0 308 gt_packet_free (packet);
paulo@0 309 return NULL;
paulo@0 310 }
paulo@0 311
paulo@0 312 memcpy (packet->data, data, len);
paulo@0 313
paulo@0 314 packet->len = len;
paulo@0 315
paulo@0 316 /* Hmm, this should never happen, time to valgrind */
paulo@0 317 if (gt_packet_payload_len (packet) != len - GNUTELLA_HDR_LEN)
paulo@0 318 {
paulo@0 319 GIFT_ERROR (("corrupt packet"));
paulo@0 320 gt_packet_free (packet);
paulo@0 321 return NULL;
paulo@0 322 }
paulo@0 323
paulo@0 324 return packet;
paulo@0 325 }
paulo@0 326
paulo@0 327 /*****************************************************************************/
paulo@0 328
paulo@0 329 uint8_t gt_packet_get_uint8 (GtPacket *packet)
paulo@0 330 { return gt_packet_get_uint (packet, 1, LITTLE, FALSE); }
paulo@0 331
paulo@0 332 uint16_t gt_packet_get_uint16 (GtPacket *packet)
paulo@0 333 { return gt_packet_get_uint (packet, 2, LITTLE, TRUE); }
paulo@0 334
paulo@0 335 uint32_t gt_packet_get_uint32 (GtPacket *packet)
paulo@0 336 { return gt_packet_get_uint (packet, 4, LITTLE, TRUE); }
paulo@0 337
paulo@0 338 in_addr_t gt_packet_get_ip (GtPacket *packet)
paulo@0 339 { return gt_packet_get_uint (packet, 4, BIG, FALSE); }
paulo@0 340
paulo@0 341 in_port_t gt_packet_get_port (GtPacket *packet)
paulo@0 342 { return gt_packet_get_uint (packet, 2, LITTLE, TRUE); }
paulo@0 343
paulo@0 344 /*****************************************************************************/
paulo@0 345
paulo@0 346 uint32_t gt_packet_get_uint (GtPacket *packet, size_t size,
paulo@0 347 int endian, int swap)
paulo@0 348 {
paulo@0 349 uint32_t data32 = 0;
paulo@0 350 char *offs;
paulo@0 351
paulo@0 352 assert (packet);
paulo@0 353
paulo@0 354 /* check overrun */
paulo@0 355 if (packet->offset + size > packet->len)
paulo@0 356 {
paulo@0 357 packet->error = TRUE;
paulo@0 358 return 0;
paulo@0 359 }
paulo@0 360
paulo@0 361 offs = packet->data + packet->offset;
paulo@0 362
paulo@0 363 switch (size)
paulo@0 364 {
paulo@0 365 case 1:
paulo@0 366 data32 = (uint32_t)gt_get8 (offs);
paulo@0 367 break;
paulo@0 368 case 2:
paulo@0 369 data32 = (uint32_t)gt_get16 (offs, endian, swap);
paulo@0 370 break;
paulo@0 371 case 4:
paulo@0 372 data32 = gt_get32 (offs, endian, swap);
paulo@0 373 break;
paulo@0 374 default:
paulo@0 375 printf ("%s: wtf are you doing?\n", __PRETTY_FUNCTION__);
paulo@0 376 return data32;
paulo@0 377 }
paulo@0 378
paulo@0 379 packet->offset += size;
paulo@0 380
paulo@0 381 return data32;
paulo@0 382 }
paulo@0 383
paulo@0 384 /*****************************************************************************/
paulo@0 385
paulo@0 386 static int gt_packet_append (GtPacket *packet, const void *data, size_t size)
paulo@0 387 {
paulo@0 388 size_t required;
paulo@0 389
paulo@0 390 if (!packet || !data || size == 0)
paulo@0 391 return FALSE;
paulo@0 392
paulo@0 393 if (packet->data_len + size >= GT_PACKET_MAX)
paulo@0 394 {
paulo@0 395 packet->error = TRUE;
paulo@0 396 return FALSE;
paulo@0 397 }
paulo@0 398
paulo@0 399 /* determine the total required space to append size bytes */
paulo@0 400 required = packet->len + size;
paulo@0 401
paulo@0 402 /* if we can't resize, gracefully fail...the caller should determine
paulo@0 403 * how bad this truly is */
paulo@0 404 if (!gt_packet_resize (packet, required))
paulo@0 405 return FALSE;
paulo@0 406
paulo@0 407 /* append size bytes of data */
paulo@0 408 memcpy (packet->data + packet->len, data, size);
paulo@0 409
paulo@0 410 /* increment the length of this packet */
paulo@0 411 packet->len += size;
paulo@0 412
paulo@0 413 gt_packet_set_payload_len (packet, gt_packet_payload_len (packet) + size);
paulo@0 414 return TRUE;
paulo@0 415 }
paulo@0 416
paulo@0 417 int gt_packet_put_uint (GtPacket *packet, void *data, size_t size,
paulo@0 418 int endian, int swap)
paulo@0 419 {
paulo@0 420 int ret;
paulo@0 421 uint16_t unet16;
paulo@0 422 uint32_t unet32;
paulo@0 423
paulo@0 424 if (!data || size < 0 || size > sizeof (uint32_t))
paulo@0 425 return FALSE;
paulo@0 426
paulo@0 427 switch (size)
paulo@0 428 {
paulo@0 429 case 2:
paulo@0 430 unet16 = gt_get16 (data, endian, swap);
paulo@0 431 ret = gt_packet_append (packet, &unet16, size);
paulo@0 432 break;
paulo@0 433 case 4:
paulo@0 434 unet32 = gt_get32 (data, endian, swap);
paulo@0 435 ret = gt_packet_append (packet, &unet32, size);
paulo@0 436 break;
paulo@0 437 default:
paulo@0 438 ret = gt_packet_append (packet, data, size);
paulo@0 439 break;
paulo@0 440 }
paulo@0 441
paulo@0 442 return ret;
paulo@0 443 }
paulo@0 444
paulo@0 445 /*****************************************************************************/
paulo@0 446
paulo@0 447 int gt_packet_put_uint8 (GtPacket *packet, uint8_t byte)
paulo@0 448 { return gt_packet_put_uint (packet, &byte, 1, LITTLE, FALSE); }
paulo@0 449
paulo@0 450 int gt_packet_put_uint16 (GtPacket *packet, uint16_t bytes)
paulo@0 451 { return gt_packet_put_uint (packet, &bytes, 2, LITTLE, TRUE); }
paulo@0 452
paulo@0 453 int gt_packet_put_uint32 (GtPacket *packet, uint32_t bytes)
paulo@0 454 { return gt_packet_put_uint (packet, &bytes, 4, LITTLE, TRUE); }
paulo@0 455
paulo@0 456 int gt_packet_put_ip (GtPacket *packet, in_addr_t ip)
paulo@0 457 { return gt_packet_put_uint (packet, &ip, 4, BIG, FALSE); }
paulo@0 458
paulo@0 459 int gt_packet_put_port (GtPacket *packet, in_port_t port)
paulo@0 460 { return gt_packet_put_uint (packet, &port, 2, LITTLE, TRUE); }
paulo@0 461
paulo@0 462 int gt_packet_put_ustr (GtPacket *packet, const unsigned char *str, size_t len)
paulo@0 463 {
paulo@0 464 assert (len > 0);
paulo@0 465 return gt_packet_append (packet, str, len);
paulo@0 466 }
paulo@0 467
paulo@0 468 int gt_packet_put_str (GtPacket *packet, const char *str)
paulo@0 469 {
paulo@0 470 size_t len;
paulo@0 471
paulo@0 472 if (!str)
paulo@0 473 return gt_packet_put_uint8 (packet, 0);
paulo@0 474
paulo@0 475 len = strlen (str) + 1;
paulo@0 476 return gt_packet_put_ustr (packet, (const unsigned char *)str, len);
paulo@0 477 }
paulo@0 478
paulo@0 479 /*****************************************************************************/
paulo@0 480
paulo@0 481 /* checks for the gt_packet_get_array sentinel given the size. the sentinel is
paulo@0 482 * defined as a full element filled with zeroes */
paulo@0 483 static int array_sentinel (char *ptr, size_t size)
paulo@0 484 {
paulo@0 485 while (size--)
paulo@0 486 {
paulo@0 487 /* non-zero byte, this element couldnt be the sentinel */
paulo@0 488 if (*ptr != 0)
paulo@0 489 return FALSE;
paulo@0 490
paulo@0 491 ptr++;
paulo@0 492 }
paulo@0 493
paulo@0 494 return TRUE;
paulo@0 495 }
paulo@0 496
paulo@0 497 void *gt_packet_get_array (GtPacket *packet, size_t nmemb, size_t size,
paulo@0 498 int term, int endian, int swap)
paulo@0 499 {
paulo@0 500 char *start;
paulo@0 501 char *ptr;
paulo@0 502 char *end;
paulo@0 503 int n;
paulo@0 504
paulo@0 505 assert (packet);
paulo@0 506
paulo@0 507 /* we tried to read past the end of the packet */
paulo@0 508 if (packet->offset >= packet->len)
paulo@0 509 {
paulo@0 510 packet->error = TRUE;
paulo@0 511 return NULL;
paulo@0 512 }
paulo@0 513
paulo@0 514 start = packet->data + packet->offset;
paulo@0 515 end = packet->data + packet->len;
paulo@0 516
paulo@0 517 /* TODO - optimize compares inside this loop */
paulo@0 518 n = 0;
paulo@0 519 for (ptr = start; ptr + size < end; ptr += size, n++)
paulo@0 520 {
paulo@0 521 if (term && array_sentinel (ptr, size))
paulo@0 522 break;
paulo@0 523
paulo@0 524 if (nmemb > 0 && n >= nmemb)
paulo@0 525 break;
paulo@0 526
paulo@0 527 if (swap)
paulo@0 528 {
paulo@0 529 switch (size)
paulo@0 530 {
paulo@0 531 case 2:
paulo@0 532 net_put16 (ptr, gt_get16 (ptr, endian, swap));
paulo@0 533 break;
paulo@0 534 case 4:
paulo@0 535 net_put32 (ptr, gt_get32 (ptr, endian, swap));
paulo@0 536 break;
paulo@0 537 default:
paulo@0 538 assert (0);
paulo@0 539 break;
paulo@0 540 }
paulo@0 541 }
paulo@0 542 }
paulo@0 543
paulo@0 544 /* If the array was not null terminated, then terminate it now */
paulo@0 545 if (term && !array_sentinel (ptr, size))
paulo@0 546 {
paulo@0 547 uint32_t zero = 0;
paulo@0 548 size_t len;
paulo@0 549
paulo@0 550 /* this is the length of the array we read */
paulo@0 551 len = (ptr - start + size);
paulo@0 552
paulo@0 553 /* we must have hit the end of the packet */
paulo@0 554 assert (packet->offset + len == packet->len);
paulo@0 555
paulo@0 556 if (!gt_packet_resize (packet, packet->len + size))
paulo@0 557 {
paulo@0 558 packet->offset = packet->len;
paulo@0 559 return NULL;
paulo@0 560 }
paulo@0 561
paulo@0 562 /* Hrm, this changes the payload, which we really dont want to do. */
paulo@0 563 if (!gt_packet_append (packet, &zero, size))
paulo@0 564 {
paulo@0 565 packet->offset = packet->len;
paulo@0 566 return NULL;
paulo@0 567 }
paulo@0 568 }
paulo@0 569
paulo@0 570 /* invalid data...no sentinel found */
paulo@0 571 if (ptr + size > end)
paulo@0 572 {
paulo@0 573 packet->offset = packet->len;
paulo@0 574 return NULL;
paulo@0 575 }
paulo@0 576
paulo@0 577 /* ptr is at the sentinel right now, move one element out to calculate the
paulo@0 578 * next packet start */
paulo@0 579 if (term)
paulo@0 580 ptr += size;
paulo@0 581
paulo@0 582 /* this includes the sentinel now */
paulo@0 583 packet->offset += (ptr - start);
paulo@0 584
paulo@0 585 return start;
paulo@0 586 }
paulo@0 587
paulo@0 588 char *gt_packet_get_str (GtPacket *packet)
paulo@0 589 {
paulo@0 590 return gt_packet_get_array (packet, 0, 1, TRUE, FALSE, FALSE);
paulo@0 591 }
paulo@0 592
paulo@0 593 unsigned char *gt_packet_get_ustr (GtPacket *packet, size_t len)
paulo@0 594 {
paulo@0 595 return gt_packet_get_array (packet, len, 1, FALSE, FALSE, FALSE);
paulo@0 596 }
paulo@0 597
paulo@0 598 /******************************************************************************/
paulo@0 599
paulo@0 600 static char *packet_command_str (unsigned char cmd)
paulo@0 601 {
paulo@0 602 static char buf[16];
paulo@0 603
paulo@0 604 switch (cmd)
paulo@0 605 {
paulo@0 606 case GT_MSG_PING: return "PING";
paulo@0 607 case GT_MSG_PING_REPLY: return "PONG";
paulo@0 608 case GT_MSG_BYE: return "BYE";
paulo@0 609 case GT_MSG_QUERY_ROUTE: return "QROUTE";
paulo@0 610 case GT_MSG_VENDOR: return "VMSG";
paulo@0 611 case GT_MSG_VENDOR_STD: return "VMSG-S";
paulo@0 612 case GT_MSG_PUSH: return "PUSH";
paulo@0 613 case GT_MSG_QUERY: return "QUERY";
paulo@0 614 case GT_MSG_QUERY_REPLY: return "HITS";
paulo@0 615
paulo@0 616 default:
paulo@0 617 snprintf (buf, sizeof (buf), "[<%02hx>]", cmd);
paulo@0 618 return buf;
paulo@0 619 }
paulo@0 620 }
paulo@0 621
paulo@0 622 static void packet_log (char *data, int len, int sent, char *user_agent,
paulo@0 623 in_addr_t ip)
paulo@0 624 {
paulo@0 625 uint8_t cmd;
paulo@0 626 char user_buf[32];
paulo@0 627 char *file;
paulo@0 628 static FILE *ascii_log;
paulo@0 629
paulo@0 630 if (!ascii_log)
paulo@0 631 {
paulo@0 632 file = PACKET_ASCII_LOG;
paulo@0 633
paulo@0 634 if (!(ascii_log = fopen (file, "w")))
paulo@0 635 return;
paulo@0 636 }
paulo@0 637
paulo@0 638 cmd = get_command (data);
paulo@0 639
paulo@0 640 user_buf[0] = 0;
paulo@0 641
paulo@0 642 /* copy the first few chars of user_agent to make it line up */
paulo@0 643 if (user_agent)
paulo@0 644 {
paulo@0 645 strncpy (user_buf, user_agent, 21);
paulo@0 646 user_buf[21] = 0;
paulo@0 647 }
paulo@0 648
paulo@0 649 fprintf (ascii_log, "%2s %-6s sz: %-5hu peer: %-22s [%s]\n",
paulo@0 650 (sent ? "<=" : "=>"),
paulo@0 651 packet_command_str (cmd), len,
paulo@0 652 (user_buf[0] ? user_buf : "(None)"),
paulo@0 653 (ip == 0 ? "None" : net_ip_str (ip)));
paulo@0 654
paulo@0 655 fprint_hex (ascii_log, data, len);
paulo@0 656 }
paulo@0 657
paulo@0 658 void gt_packet_log (GtPacket *packet, TCPC *src, int sent)
paulo@0 659 {
paulo@0 660 char *user_agent;
paulo@0 661 in_addr_t ip;
paulo@0 662
paulo@0 663 if (!PACKET_DEBUG)
paulo@0 664 return;
paulo@0 665
paulo@0 666 user_agent = NULL;
paulo@0 667 ip = 0;
paulo@0 668
paulo@0 669 /* append the user-agent string to the packet log */
paulo@0 670 if (src)
paulo@0 671 {
paulo@0 672 ip = src->host;
paulo@0 673 user_agent = dataset_lookupstr (GT_NODE(src)->hdr, "user-agent");
paulo@0 674 }
paulo@0 675
paulo@0 676 packet_log (packet->data, packet->len, sent, user_agent, ip);
paulo@0 677 }
paulo@0 678
paulo@0 679 /******************************************************************************/
paulo@0 680
paulo@0 681 int gt_packet_send (TCPC *c, GtPacket *packet)
paulo@0 682 {
paulo@0 683 if (!c || c->fd < 0)
paulo@0 684 return -1;
paulo@0 685
paulo@0 686 if (!gt_node_send (GT_NODE(c), packet))
paulo@0 687 return -1;
paulo@0 688
paulo@0 689 return 0;
paulo@0 690 }
paulo@0 691
paulo@0 692 /******************************************************************************/
paulo@0 693
paulo@0 694 static int send_packetva (TCPC *c, uint8_t cmd,
paulo@0 695 gt_guid_t *guid, uint8_t ttl,
paulo@0 696 uint8_t hops, char *fmt, va_list args)
paulo@0 697 {
paulo@0 698 GtPacket *pkt;
paulo@0 699 char *p;
paulo@0 700 int short_fmt = FALSE;
paulo@0 701 int field_width = 0;
paulo@0 702 int ret;
paulo@0 703
paulo@0 704 if (!(pkt = gt_packet_new (cmd, ttl, guid)))
paulo@0 705 return -1;
paulo@0 706
paulo@0 707 for (p = fmt; *p; p++)
paulo@0 708 {
paulo@0 709 switch (*p)
paulo@0 710 {
paulo@0 711 case '%':
paulo@0 712 short_fmt = FALSE;
paulo@0 713 break;
paulo@0 714 case 'h':
paulo@0 715 short_fmt = TRUE;
paulo@0 716 break;
paulo@0 717 case 'l':
paulo@0 718 break;
paulo@0 719 case 'c':
paulo@0 720 {
paulo@0 721 uint8_t bits8 = (uint8_t) va_arg (args, int);
paulo@0 722 gt_packet_put_uint8 (pkt, bits8);
paulo@0 723 }
paulo@0 724 break;
paulo@0 725 case 'u':
paulo@0 726 if (short_fmt)
paulo@0 727 {
paulo@0 728 uint16_t bits16 = (uint16_t) va_arg (args, int);
paulo@0 729 gt_packet_put_uint16 (pkt, bits16);
paulo@0 730 }
paulo@0 731 else
paulo@0 732 {
paulo@0 733 uint32_t bits32 = (uint32_t) va_arg (args, int);
paulo@0 734 gt_packet_put_uint32 (pkt, bits32);
paulo@0 735 }
paulo@0 736 break;
paulo@0 737 case 's':
paulo@0 738 {
paulo@0 739 char *str = va_arg (args, char *);
paulo@0 740 gt_packet_put_str (pkt, str);
paulo@0 741 }
paulo@0 742 break;
paulo@0 743 case '0': case '1': case '2': case '3': case '4': case '5':
paulo@0 744 case '6': case '7': case '8': case '9':
paulo@0 745 field_width = field_width * 10 + (*p - '0');
paulo@0 746 break;
paulo@0 747 case '*':
paulo@0 748 field_width = va_arg (args, int);
paulo@0 749 break;
paulo@0 750 case 'p':
paulo@0 751 {
paulo@0 752 unsigned char *ustr = va_arg (args, unsigned char *);
paulo@0 753
paulo@0 754 gt_packet_put_ustr (pkt, ustr, field_width);
paulo@0 755 field_width = 0;
paulo@0 756 }
paulo@0 757 break;
paulo@0 758 default:
paulo@0 759 abort ();
paulo@0 760 break;
paulo@0 761 }
paulo@0 762 }
paulo@0 763
paulo@0 764 if (gt_packet_error (pkt))
paulo@0 765 {
paulo@0 766 gt_packet_free (pkt);
paulo@0 767 return -1;
paulo@0 768 }
paulo@0 769
paulo@0 770 ret = gt_packet_send (c, pkt);
paulo@0 771 gt_packet_free (pkt);
paulo@0 772
paulo@0 773 return ret;
paulo@0 774 }
paulo@0 775
paulo@0 776 int gt_packet_send_fmt (TCPC *c, uint8_t cmd,
paulo@0 777 gt_guid_t *guid, uint8_t ttl,
paulo@0 778 uint8_t hops, char *fmt, ...)
paulo@0 779 {
paulo@0 780 va_list args;
paulo@0 781 int ret;
paulo@0 782
paulo@0 783 va_start (args, fmt);
paulo@0 784 ret = send_packetva (c, cmd, guid, ttl, hops, fmt, args);
paulo@0 785 va_end (args);
paulo@0 786
paulo@0 787 return ret;
paulo@0 788 }
paulo@0 789
paulo@0 790 int gt_packet_reply_fmt (TCPC *c, GtPacket *packet,
paulo@0 791 uint8_t cmd, char *fmt, ...)
paulo@0 792 {
paulo@0 793 va_list args;
paulo@0 794 int ret;
paulo@0 795 size_t hops;
paulo@0 796 gt_guid_t *guid;
paulo@0 797
paulo@0 798 guid = gt_packet_guid (packet);
paulo@0 799 hops = gt_packet_hops (packet);
paulo@0 800
paulo@0 801 va_start (args, fmt);
paulo@0 802 ret = send_packetva (c, cmd, guid, hops + 1, 0, fmt, args);
paulo@0 803 va_end (args);
paulo@0 804
paulo@0 805 return ret;
paulo@0 806 }
paulo@0 807
paulo@0 808 /******************************************************************************/
paulo@0 809
paulo@0 810 int gt_packet_forward (GtPacket *packet, TCPC *c)
paulo@0 811 {
paulo@0 812 return -1;
paulo@0 813 }