paulo@0: /* paulo@0: * $Id: gt_packet.c,v 1.35 2004/04/17 06:05:53 hipnod Exp $ paulo@0: * paulo@0: * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net) paulo@0: * paulo@0: * This program is free software; you can redistribute it and/or modify it paulo@0: * under the terms of the GNU General Public License as published by the paulo@0: * Free Software Foundation; either version 2, or (at your option) any paulo@0: * later version. paulo@0: * paulo@0: * This program is distributed in the hope that it will be useful, but paulo@0: * WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU paulo@0: * General Public License for more details. paulo@0: */ paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: paulo@0: #include "gt_packet.h" paulo@0: paulo@0: #include "gt_node.h" paulo@0: #include "gt_netorg.h" paulo@0: paulo@0: #include "gt_utils.h" paulo@0: paulo@0: #include "gt_query_route.h" paulo@0: #include "message/gt_message.h" /* gt_vendor_msg_get_{id,version} */ paulo@0: paulo@0: #include paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: GtPacket *gt_packet_new (uint8_t cmd, uint8_t ttl, gt_guid_t *guid) paulo@0: { paulo@0: GtPacket *packet; paulo@0: unsigned char *data; paulo@0: paulo@0: if (!(packet = MALLOC (sizeof (GtPacket)))) paulo@0: return NULL; paulo@0: paulo@0: if (!(data = MALLOC (GT_PACKET_INITIAL))) paulo@0: { paulo@0: free (packet); paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: packet->data = data; paulo@0: packet->len = GNUTELLA_HDR_LEN; paulo@0: packet->data_len = GT_PACKET_INITIAL; paulo@0: paulo@0: /* paulo@0: * Caller could provide GUID or request it be randomly initialized. paulo@0: */ paulo@0: if (guid) paulo@0: gt_packet_set_guid (packet, guid); paulo@0: else paulo@0: gt_guid_init ((gt_guid_t *)packet->data); paulo@0: paulo@0: gt_packet_set_command (packet, cmd); paulo@0: gt_packet_set_ttl (packet, ttl); paulo@0: gt_packet_set_payload_len (packet, 0); paulo@0: gt_packet_set_hops (packet, 0); paulo@0: paulo@0: /* set the offset to start at the end of the header */ paulo@0: packet->offset = GNUTELLA_HDR_LEN; paulo@0: paulo@0: return packet; paulo@0: } paulo@0: paulo@0: GtPacket *gt_packet_reply (GtPacket *src, uint8_t cmd) paulo@0: { paulo@0: GtPacket *packet; paulo@0: uint8_t hops; paulo@0: gt_guid_t *guid; paulo@0: paulo@0: hops = gt_packet_hops (src); paulo@0: guid = gt_packet_guid (src); paulo@0: paulo@0: if (!(packet = gt_packet_new (cmd, hops + 1, guid))) paulo@0: return NULL; paulo@0: paulo@0: return packet; paulo@0: } paulo@0: paulo@0: GtPacket *gt_packet_vendor (const gt_vendor_msg_t *vmsg) paulo@0: { paulo@0: GtPacket *pkt; paulo@0: paulo@0: if (!(pkt = gt_packet_new (GT_MSG_VENDOR, 1, NULL))) paulo@0: return NULL; paulo@0: paulo@0: gt_packet_put_ustr (pkt, vmsg->vendor_id, 4); paulo@0: gt_packet_put_uint16 (pkt, vmsg->id); paulo@0: gt_packet_put_uint16 (pkt, 1); /* vmsg version */ paulo@0: paulo@0: if (gt_packet_error (pkt)) paulo@0: { paulo@0: gt_packet_free (pkt); paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: return pkt; paulo@0: } paulo@0: paulo@0: void gt_packet_free (GtPacket *packet) paulo@0: { paulo@0: if (!packet) paulo@0: return; paulo@0: paulo@0: free (packet->data); paulo@0: free (packet); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: gt_guid_t *gt_packet_guid (GtPacket *packet) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: return packet->data; paulo@0: } paulo@0: paulo@0: uint32_t gt_packet_payload_len (GtPacket *packet) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: return get_payload_len (packet->data); paulo@0: } paulo@0: paulo@0: uint32_t gt_packet_command (GtPacket *packet) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: return get_command (packet->data); paulo@0: } paulo@0: paulo@0: uint8_t gt_packet_hops (GtPacket *packet) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: return get_hops (packet->data); paulo@0: } paulo@0: paulo@0: uint8_t gt_packet_ttl (GtPacket *packet) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: return get_ttl (packet->data); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: void gt_packet_set_guid (GtPacket *packet, gt_guid_t *guid) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: memcpy (packet->data, guid, 16); paulo@0: } paulo@0: paulo@0: void gt_packet_set_command (GtPacket *packet, uint8_t cmd) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: get_command (packet->data) = cmd; paulo@0: } paulo@0: paulo@0: void gt_packet_set_ttl (GtPacket *packet, uint8_t ttl) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: get_ttl (packet->data) = ttl; paulo@0: } paulo@0: paulo@0: void gt_packet_set_hops (GtPacket *packet, uint8_t hops) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: get_hops (packet->data) = hops; paulo@0: } paulo@0: paulo@0: void gt_packet_set_payload_len (GtPacket *packet, uint32_t len) paulo@0: { paulo@0: assert (packet->data_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: len = htovl (len); paulo@0: paulo@0: memcpy (packet->data + 19, &len, 4); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: /* functions to read data from packets */ paulo@0: paulo@0: static uint8_t gt_get8 (unsigned char *src) paulo@0: { paulo@0: return *src; paulo@0: } paulo@0: paulo@0: #define copy_bytes(src,sz,endian,swap,sizedvar_t,swap_net,swap_vax) \ paulo@0: sizedvar_t r; \ paulo@0: sizedvar_t v; \ paulo@0: sizedvar_t n; \ paulo@0: \ paulo@0: memcpy (&r, src, sz); \ paulo@0: \ paulo@0: n = swap_net (r); \ paulo@0: \ paulo@0: assert_at_compile (BIG == 0x01); \ paulo@0: if (endian & swap) \ paulo@0: r = n; \ paulo@0: \ paulo@0: v = swap_vax (r); \ paulo@0: \ paulo@0: assert_at_compile (LITTLE == 0x00); \ paulo@0: if (~endian & swap) \ paulo@0: r = v; \ paulo@0: \ paulo@0: return r; paulo@0: paulo@0: static uint16_t gt_get16 (unsigned char *src, int endian, int swap) paulo@0: { paulo@0: copy_bytes (src, 2, endian, swap, uint16_t, ntohs, vtohs); paulo@0: } paulo@0: paulo@0: static uint32_t gt_get32 (unsigned char *src, int endian, int swap) paulo@0: { paulo@0: copy_bytes (src, 4, endian, swap, uint32_t, ntohl, vtohl); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static BOOL gt_packet_resize (GtPacket *packet, size_t len) paulo@0: { paulo@0: size_t resize_len; paulo@0: unsigned char *resized; paulo@0: paulo@0: if (!packet) paulo@0: return FALSE; paulo@0: paulo@0: assert (len >= GNUTELLA_HDR_LEN); paulo@0: assert (len < GT_PACKET_MAX); paulo@0: paulo@0: /* the buffer we have allocated is already large enough */ paulo@0: if (packet->data_len >= len) paulo@0: return TRUE; paulo@0: paulo@0: /* determine an appropriate resize length */ paulo@0: for (resize_len = packet->data_len; resize_len < len; ) paulo@0: { paulo@0: if (resize_len == 0) paulo@0: resize_len = GT_PACKET_INITIAL; paulo@0: else paulo@0: resize_len *= 2; paulo@0: } paulo@0: paulo@0: if (!(resized = realloc (packet->data, resize_len))) paulo@0: { paulo@0: packet->error = TRUE; paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: memset (resized + packet->data_len, 0, resize_len - packet->data_len); paulo@0: paulo@0: /* modify the packet structure to reflect this resize */ paulo@0: packet->data_len = resize_len; paulo@0: packet->data = resized; paulo@0: paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: int gt_packet_error (GtPacket *packet) paulo@0: { paulo@0: return packet->error; paulo@0: } paulo@0: paulo@0: int gt_packet_seek (GtPacket *packet, int offset) paulo@0: { paulo@0: int old_offset; paulo@0: paulo@0: /* should we be setting packet->error here? */ paulo@0: if (offset >= packet->len || offset < 0) paulo@0: { paulo@0: packet->error = TRUE; paulo@0: return -1; paulo@0: } paulo@0: paulo@0: old_offset = packet->offset; paulo@0: packet->offset = offset; paulo@0: paulo@0: return old_offset; paulo@0: } paulo@0: paulo@0: GtPacket *gt_packet_unserialize (unsigned char *data, size_t len) paulo@0: { paulo@0: GtPacket *packet; paulo@0: paulo@0: if (!(packet = gt_packet_new (0, 0, NULL))) paulo@0: return NULL; paulo@0: paulo@0: if (len >= GT_PACKET_MAX) paulo@0: { paulo@0: gt_packet_free (packet); paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: if (!gt_packet_resize (packet, len)) paulo@0: { paulo@0: GIFT_ERROR (("error resizing packet")); paulo@0: gt_packet_free (packet); paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: memcpy (packet->data, data, len); paulo@0: paulo@0: packet->len = len; paulo@0: paulo@0: /* Hmm, this should never happen, time to valgrind */ paulo@0: if (gt_packet_payload_len (packet) != len - GNUTELLA_HDR_LEN) paulo@0: { paulo@0: GIFT_ERROR (("corrupt packet")); paulo@0: gt_packet_free (packet); paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: return packet; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: uint8_t gt_packet_get_uint8 (GtPacket *packet) paulo@0: { return gt_packet_get_uint (packet, 1, LITTLE, FALSE); } paulo@0: paulo@0: uint16_t gt_packet_get_uint16 (GtPacket *packet) paulo@0: { return gt_packet_get_uint (packet, 2, LITTLE, TRUE); } paulo@0: paulo@0: uint32_t gt_packet_get_uint32 (GtPacket *packet) paulo@0: { return gt_packet_get_uint (packet, 4, LITTLE, TRUE); } paulo@0: paulo@0: in_addr_t gt_packet_get_ip (GtPacket *packet) paulo@0: { return gt_packet_get_uint (packet, 4, BIG, FALSE); } paulo@0: paulo@0: in_port_t gt_packet_get_port (GtPacket *packet) paulo@0: { return gt_packet_get_uint (packet, 2, LITTLE, TRUE); } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: uint32_t gt_packet_get_uint (GtPacket *packet, size_t size, paulo@0: int endian, int swap) paulo@0: { paulo@0: uint32_t data32 = 0; paulo@0: char *offs; paulo@0: paulo@0: assert (packet); paulo@0: paulo@0: /* check overrun */ paulo@0: if (packet->offset + size > packet->len) paulo@0: { paulo@0: packet->error = TRUE; paulo@0: return 0; paulo@0: } paulo@0: paulo@0: offs = packet->data + packet->offset; paulo@0: paulo@0: switch (size) paulo@0: { paulo@0: case 1: paulo@0: data32 = (uint32_t)gt_get8 (offs); paulo@0: break; paulo@0: case 2: paulo@0: data32 = (uint32_t)gt_get16 (offs, endian, swap); paulo@0: break; paulo@0: case 4: paulo@0: data32 = gt_get32 (offs, endian, swap); paulo@0: break; paulo@0: default: paulo@0: printf ("%s: wtf are you doing?\n", __PRETTY_FUNCTION__); paulo@0: return data32; paulo@0: } paulo@0: paulo@0: packet->offset += size; paulo@0: paulo@0: return data32; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static int gt_packet_append (GtPacket *packet, const void *data, size_t size) paulo@0: { paulo@0: size_t required; paulo@0: paulo@0: if (!packet || !data || size == 0) paulo@0: return FALSE; paulo@0: paulo@0: if (packet->data_len + size >= GT_PACKET_MAX) paulo@0: { paulo@0: packet->error = TRUE; paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: /* determine the total required space to append size bytes */ paulo@0: required = packet->len + size; paulo@0: paulo@0: /* if we can't resize, gracefully fail...the caller should determine paulo@0: * how bad this truly is */ paulo@0: if (!gt_packet_resize (packet, required)) paulo@0: return FALSE; paulo@0: paulo@0: /* append size bytes of data */ paulo@0: memcpy (packet->data + packet->len, data, size); paulo@0: paulo@0: /* increment the length of this packet */ paulo@0: packet->len += size; paulo@0: paulo@0: gt_packet_set_payload_len (packet, gt_packet_payload_len (packet) + size); paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: int gt_packet_put_uint (GtPacket *packet, void *data, size_t size, paulo@0: int endian, int swap) paulo@0: { paulo@0: int ret; paulo@0: uint16_t unet16; paulo@0: uint32_t unet32; paulo@0: paulo@0: if (!data || size < 0 || size > sizeof (uint32_t)) paulo@0: return FALSE; paulo@0: paulo@0: switch (size) paulo@0: { paulo@0: case 2: paulo@0: unet16 = gt_get16 (data, endian, swap); paulo@0: ret = gt_packet_append (packet, &unet16, size); paulo@0: break; paulo@0: case 4: paulo@0: unet32 = gt_get32 (data, endian, swap); paulo@0: ret = gt_packet_append (packet, &unet32, size); paulo@0: break; paulo@0: default: paulo@0: ret = gt_packet_append (packet, data, size); paulo@0: break; paulo@0: } paulo@0: paulo@0: return ret; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: int gt_packet_put_uint8 (GtPacket *packet, uint8_t byte) paulo@0: { return gt_packet_put_uint (packet, &byte, 1, LITTLE, FALSE); } paulo@0: paulo@0: int gt_packet_put_uint16 (GtPacket *packet, uint16_t bytes) paulo@0: { return gt_packet_put_uint (packet, &bytes, 2, LITTLE, TRUE); } paulo@0: paulo@0: int gt_packet_put_uint32 (GtPacket *packet, uint32_t bytes) paulo@0: { return gt_packet_put_uint (packet, &bytes, 4, LITTLE, TRUE); } paulo@0: paulo@0: int gt_packet_put_ip (GtPacket *packet, in_addr_t ip) paulo@0: { return gt_packet_put_uint (packet, &ip, 4, BIG, FALSE); } paulo@0: paulo@0: int gt_packet_put_port (GtPacket *packet, in_port_t port) paulo@0: { return gt_packet_put_uint (packet, &port, 2, LITTLE, TRUE); } paulo@0: paulo@0: int gt_packet_put_ustr (GtPacket *packet, const unsigned char *str, size_t len) paulo@0: { paulo@0: assert (len > 0); paulo@0: return gt_packet_append (packet, str, len); paulo@0: } paulo@0: paulo@0: int gt_packet_put_str (GtPacket *packet, const char *str) paulo@0: { paulo@0: size_t len; paulo@0: paulo@0: if (!str) paulo@0: return gt_packet_put_uint8 (packet, 0); paulo@0: paulo@0: len = strlen (str) + 1; paulo@0: return gt_packet_put_ustr (packet, (const unsigned char *)str, len); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* checks for the gt_packet_get_array sentinel given the size. the sentinel is paulo@0: * defined as a full element filled with zeroes */ paulo@0: static int array_sentinel (char *ptr, size_t size) paulo@0: { paulo@0: while (size--) paulo@0: { paulo@0: /* non-zero byte, this element couldnt be the sentinel */ paulo@0: if (*ptr != 0) paulo@0: return FALSE; paulo@0: paulo@0: ptr++; paulo@0: } paulo@0: paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: void *gt_packet_get_array (GtPacket *packet, size_t nmemb, size_t size, paulo@0: int term, int endian, int swap) paulo@0: { paulo@0: char *start; paulo@0: char *ptr; paulo@0: char *end; paulo@0: int n; paulo@0: paulo@0: assert (packet); paulo@0: paulo@0: /* we tried to read past the end of the packet */ paulo@0: if (packet->offset >= packet->len) paulo@0: { paulo@0: packet->error = TRUE; paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: start = packet->data + packet->offset; paulo@0: end = packet->data + packet->len; paulo@0: paulo@0: /* TODO - optimize compares inside this loop */ paulo@0: n = 0; paulo@0: for (ptr = start; ptr + size < end; ptr += size, n++) paulo@0: { paulo@0: if (term && array_sentinel (ptr, size)) paulo@0: break; paulo@0: paulo@0: if (nmemb > 0 && n >= nmemb) paulo@0: break; paulo@0: paulo@0: if (swap) paulo@0: { paulo@0: switch (size) paulo@0: { paulo@0: case 2: paulo@0: net_put16 (ptr, gt_get16 (ptr, endian, swap)); paulo@0: break; paulo@0: case 4: paulo@0: net_put32 (ptr, gt_get32 (ptr, endian, swap)); paulo@0: break; paulo@0: default: paulo@0: assert (0); paulo@0: break; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: /* If the array was not null terminated, then terminate it now */ paulo@0: if (term && !array_sentinel (ptr, size)) paulo@0: { paulo@0: uint32_t zero = 0; paulo@0: size_t len; paulo@0: paulo@0: /* this is the length of the array we read */ paulo@0: len = (ptr - start + size); paulo@0: paulo@0: /* we must have hit the end of the packet */ paulo@0: assert (packet->offset + len == packet->len); paulo@0: paulo@0: if (!gt_packet_resize (packet, packet->len + size)) paulo@0: { paulo@0: packet->offset = packet->len; paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: /* Hrm, this changes the payload, which we really dont want to do. */ paulo@0: if (!gt_packet_append (packet, &zero, size)) paulo@0: { paulo@0: packet->offset = packet->len; paulo@0: return NULL; paulo@0: } paulo@0: } paulo@0: paulo@0: /* invalid data...no sentinel found */ paulo@0: if (ptr + size > end) paulo@0: { paulo@0: packet->offset = packet->len; paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: /* ptr is at the sentinel right now, move one element out to calculate the paulo@0: * next packet start */ paulo@0: if (term) paulo@0: ptr += size; paulo@0: paulo@0: /* this includes the sentinel now */ paulo@0: packet->offset += (ptr - start); paulo@0: paulo@0: return start; paulo@0: } paulo@0: paulo@0: char *gt_packet_get_str (GtPacket *packet) paulo@0: { paulo@0: return gt_packet_get_array (packet, 0, 1, TRUE, FALSE, FALSE); paulo@0: } paulo@0: paulo@0: unsigned char *gt_packet_get_ustr (GtPacket *packet, size_t len) paulo@0: { paulo@0: return gt_packet_get_array (packet, len, 1, FALSE, FALSE, FALSE); paulo@0: } paulo@0: paulo@0: /******************************************************************************/ paulo@0: paulo@0: static char *packet_command_str (unsigned char cmd) paulo@0: { paulo@0: static char buf[16]; paulo@0: paulo@0: switch (cmd) paulo@0: { paulo@0: case GT_MSG_PING: return "PING"; paulo@0: case GT_MSG_PING_REPLY: return "PONG"; paulo@0: case GT_MSG_BYE: return "BYE"; paulo@0: case GT_MSG_QUERY_ROUTE: return "QROUTE"; paulo@0: case GT_MSG_VENDOR: return "VMSG"; paulo@0: case GT_MSG_VENDOR_STD: return "VMSG-S"; paulo@0: case GT_MSG_PUSH: return "PUSH"; paulo@0: case GT_MSG_QUERY: return "QUERY"; paulo@0: case GT_MSG_QUERY_REPLY: return "HITS"; paulo@0: paulo@0: default: paulo@0: snprintf (buf, sizeof (buf), "[<%02hx>]", cmd); paulo@0: return buf; paulo@0: } paulo@0: } paulo@0: paulo@0: static void packet_log (char *data, int len, int sent, char *user_agent, paulo@0: in_addr_t ip) paulo@0: { paulo@0: uint8_t cmd; paulo@0: char user_buf[32]; paulo@0: char *file; paulo@0: static FILE *ascii_log; paulo@0: paulo@0: if (!ascii_log) paulo@0: { paulo@0: file = PACKET_ASCII_LOG; paulo@0: paulo@0: if (!(ascii_log = fopen (file, "w"))) paulo@0: return; paulo@0: } paulo@0: paulo@0: cmd = get_command (data); paulo@0: paulo@0: user_buf[0] = 0; paulo@0: paulo@0: /* copy the first few chars of user_agent to make it line up */ paulo@0: if (user_agent) paulo@0: { paulo@0: strncpy (user_buf, user_agent, 21); paulo@0: user_buf[21] = 0; paulo@0: } paulo@0: paulo@0: fprintf (ascii_log, "%2s %-6s sz: %-5hu peer: %-22s [%s]\n", paulo@0: (sent ? "<=" : "=>"), paulo@0: packet_command_str (cmd), len, paulo@0: (user_buf[0] ? user_buf : "(None)"), paulo@0: (ip == 0 ? "None" : net_ip_str (ip))); paulo@0: paulo@0: fprint_hex (ascii_log, data, len); paulo@0: } paulo@0: paulo@0: void gt_packet_log (GtPacket *packet, TCPC *src, int sent) paulo@0: { paulo@0: char *user_agent; paulo@0: in_addr_t ip; paulo@0: paulo@0: if (!PACKET_DEBUG) paulo@0: return; paulo@0: paulo@0: user_agent = NULL; paulo@0: ip = 0; paulo@0: paulo@0: /* append the user-agent string to the packet log */ paulo@0: if (src) paulo@0: { paulo@0: ip = src->host; paulo@0: user_agent = dataset_lookupstr (GT_NODE(src)->hdr, "user-agent"); paulo@0: } paulo@0: paulo@0: packet_log (packet->data, packet->len, sent, user_agent, ip); paulo@0: } paulo@0: paulo@0: /******************************************************************************/ paulo@0: paulo@0: int gt_packet_send (TCPC *c, GtPacket *packet) paulo@0: { paulo@0: if (!c || c->fd < 0) paulo@0: return -1; paulo@0: paulo@0: if (!gt_node_send (GT_NODE(c), packet)) paulo@0: return -1; paulo@0: paulo@0: return 0; paulo@0: } paulo@0: paulo@0: /******************************************************************************/ paulo@0: paulo@0: static int send_packetva (TCPC *c, uint8_t cmd, paulo@0: gt_guid_t *guid, uint8_t ttl, paulo@0: uint8_t hops, char *fmt, va_list args) paulo@0: { paulo@0: GtPacket *pkt; paulo@0: char *p; paulo@0: int short_fmt = FALSE; paulo@0: int field_width = 0; paulo@0: int ret; paulo@0: paulo@0: if (!(pkt = gt_packet_new (cmd, ttl, guid))) paulo@0: return -1; paulo@0: paulo@0: for (p = fmt; *p; p++) paulo@0: { paulo@0: switch (*p) paulo@0: { paulo@0: case '%': paulo@0: short_fmt = FALSE; paulo@0: break; paulo@0: case 'h': paulo@0: short_fmt = TRUE; paulo@0: break; paulo@0: case 'l': paulo@0: break; paulo@0: case 'c': paulo@0: { paulo@0: uint8_t bits8 = (uint8_t) va_arg (args, int); paulo@0: gt_packet_put_uint8 (pkt, bits8); paulo@0: } paulo@0: break; paulo@0: case 'u': paulo@0: if (short_fmt) paulo@0: { paulo@0: uint16_t bits16 = (uint16_t) va_arg (args, int); paulo@0: gt_packet_put_uint16 (pkt, bits16); paulo@0: } paulo@0: else paulo@0: { paulo@0: uint32_t bits32 = (uint32_t) va_arg (args, int); paulo@0: gt_packet_put_uint32 (pkt, bits32); paulo@0: } paulo@0: break; paulo@0: case 's': paulo@0: { paulo@0: char *str = va_arg (args, char *); paulo@0: gt_packet_put_str (pkt, str); paulo@0: } paulo@0: break; paulo@0: case '0': case '1': case '2': case '3': case '4': case '5': paulo@0: case '6': case '7': case '8': case '9': paulo@0: field_width = field_width * 10 + (*p - '0'); paulo@0: break; paulo@0: case '*': paulo@0: field_width = va_arg (args, int); paulo@0: break; paulo@0: case 'p': paulo@0: { paulo@0: unsigned char *ustr = va_arg (args, unsigned char *); paulo@0: paulo@0: gt_packet_put_ustr (pkt, ustr, field_width); paulo@0: field_width = 0; paulo@0: } paulo@0: break; paulo@0: default: paulo@0: abort (); paulo@0: break; paulo@0: } paulo@0: } paulo@0: paulo@0: if (gt_packet_error (pkt)) paulo@0: { paulo@0: gt_packet_free (pkt); paulo@0: return -1; paulo@0: } paulo@0: paulo@0: ret = gt_packet_send (c, pkt); paulo@0: gt_packet_free (pkt); paulo@0: paulo@0: return ret; paulo@0: } paulo@0: paulo@0: int gt_packet_send_fmt (TCPC *c, uint8_t cmd, paulo@0: gt_guid_t *guid, uint8_t ttl, paulo@0: uint8_t hops, char *fmt, ...) paulo@0: { paulo@0: va_list args; paulo@0: int ret; paulo@0: paulo@0: va_start (args, fmt); paulo@0: ret = send_packetva (c, cmd, guid, ttl, hops, fmt, args); paulo@0: va_end (args); paulo@0: paulo@0: return ret; paulo@0: } paulo@0: paulo@0: int gt_packet_reply_fmt (TCPC *c, GtPacket *packet, paulo@0: uint8_t cmd, char *fmt, ...) paulo@0: { paulo@0: va_list args; paulo@0: int ret; paulo@0: size_t hops; paulo@0: gt_guid_t *guid; paulo@0: paulo@0: guid = gt_packet_guid (packet); paulo@0: hops = gt_packet_hops (packet); paulo@0: paulo@0: va_start (args, fmt); paulo@0: ret = send_packetva (c, cmd, guid, hops + 1, 0, fmt, args); paulo@0: va_end (args); paulo@0: paulo@0: return ret; paulo@0: } paulo@0: paulo@0: /******************************************************************************/ paulo@0: paulo@0: int gt_packet_forward (GtPacket *packet, TCPC *c) paulo@0: { paulo@0: return -1; paulo@0: }