paulo@0: /* paulo@0: * $Id: rx_packet.c,v 1.7 2004/02/15 04:53:38 hipnod Exp $ paulo@0: * paulo@0: * Copyright (C) 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 "rx_stack.h" paulo@0: #include "rx_layer.h" paulo@0: paulo@0: #include "gt_packet.h" paulo@0: #include "rx_packet.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: struct rx_packet paulo@0: { paulo@0: struct io_buf *partial; paulo@0: rx_packet_handler_t handler; paulo@0: void *udata; paulo@0: }; paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: #define RX_PACKET(rx) \ paulo@0: ((struct rx_packet *) ((rx)->udata)) paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static void null_packet_handler (void *udata, GtPacket *packet) paulo@0: { paulo@0: gt_packet_free (packet); paulo@0: } paulo@0: paulo@0: static BOOL rx_packet_init (struct rx_layer *rx, void *udata) paulo@0: { paulo@0: struct rx_packet *rx_packet; paulo@0: paulo@0: if (!(rx_packet = NEW (struct rx_packet))) paulo@0: return FALSE; paulo@0: paulo@0: rx->udata = rx_packet; paulo@0: paulo@0: /* discard the packets received */ paulo@0: rx_packet->handler = null_packet_handler; paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: static void rx_packet_destroy (struct rx_layer *rx) paulo@0: { paulo@0: struct rx_packet *rx_packet = RX_PACKET(rx); paulo@0: paulo@0: io_buf_free (rx_packet->partial); paulo@0: FREE (rx_packet); paulo@0: } paulo@0: paulo@0: static void rx_packet_disable (struct rx_layer *rx) paulo@0: { paulo@0: /* NOP: lower layer will stop sending us data -- it'd better paulo@0: * stop now */ paulo@0: } paulo@0: paulo@0: static void rx_packet_enable (struct rx_layer *rx) paulo@0: { paulo@0: /* NOP: the lower layer will start sending us data again */ paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static GtPacket *make_packet (struct rx_layer *rx, struct rx_packet *rx_packet, paulo@0: size_t packet_size) paulo@0: { paulo@0: GtPacket *packet; paulo@0: struct io_buf *pbuf = rx_packet->partial; paulo@0: paulo@0: assert (io_buf_len (pbuf) == packet_size); paulo@0: assert (packet_size < GT_PACKET_MAX); paulo@0: paulo@0: /* construct a complete packet from the data in the binary buf */ paulo@0: packet = gt_packet_unserialize (pbuf->data, packet_size); paulo@0: paulo@0: /* paulo@0: * TODO: gt_packet_unserialize() currently copies the data, but should paulo@0: * really take ownership of the data in place. That would also allow the paulo@0: * null terminator in the io_buf to terminate the last string in the paulo@0: * packet, if any. paulo@0: */ paulo@0: io_buf_free (pbuf); paulo@0: rx_packet->partial = NULL; paulo@0: paulo@0: if (!packet) paulo@0: { paulo@0: gt_rx_stack_abort (rx->stack); paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: return packet; paulo@0: } paulo@0: paulo@0: static BOOL fill_up_to (struct rx_layer *rx, struct io_buf *dst, paulo@0: struct io_buf *src, size_t fill_size) paulo@0: { paulo@0: size_t new_len; paulo@0: size_t old_len; paulo@0: size_t len_to_read; paulo@0: paulo@0: old_len = io_buf_len (dst); paulo@0: new_len = io_buf_len (src); paulo@0: paulo@0: /* skip if we already have enough */ paulo@0: if (old_len >= fill_size) paulo@0: return TRUE; paulo@0: paulo@0: len_to_read = MIN (fill_size - old_len, new_len); paulo@0: paulo@0: /* ensure the packet has enough room */ paulo@0: if (!io_buf_resize (dst, old_len + len_to_read)) paulo@0: { paulo@0: gt_rx_stack_abort (rx->stack); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: io_buf_copy (dst, src, len_to_read); paulo@0: paulo@0: if (io_buf_len (dst) >= fill_size) paulo@0: return TRUE; paulo@0: paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: static BOOL fill_header (struct rx_layer *rx, struct rx_packet *rx_packet, paulo@0: struct io_buf *io_buf) paulo@0: { paulo@0: struct io_buf *dst = rx_packet->partial; paulo@0: struct io_buf *src = io_buf; paulo@0: paulo@0: if (!fill_up_to (rx, dst, src, GNUTELLA_HDR_LEN)) paulo@0: { paulo@0: /* this would fail if there was an alloc failure */ paulo@0: assert (io_buf_read_avail (io_buf) == 0); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: /* paulo@0: * We must read all the data the lower layer has sent and buffer paulo@0: * partial packets, because otherwise we would poll the CPU if the paulo@0: * packet were bigger than the buffer size of one of the layer paulo@0: * layers under this one. paulo@0: */ paulo@0: static BOOL read_packet (struct rx_layer *rx, struct rx_packet *rx_packet, paulo@0: struct io_buf *io_buf, GtPacket **ret) paulo@0: { paulo@0: uint32_t payload_len; paulo@0: size_t partial_len; paulo@0: uint32_t packet_size; paulo@0: struct io_buf *partial = rx_packet->partial; paulo@0: GtPacket *pkt; paulo@0: paulo@0: *ret = NULL; paulo@0: paulo@0: partial_len = io_buf_len (partial); paulo@0: assert (partial_len >= GNUTELLA_HDR_LEN); paulo@0: paulo@0: /* paulo@0: * The partial packet is now at least 23 bytes. Look in the header for paulo@0: * the payload length so we know how much we need to read before the paulo@0: * packet is complete. paulo@0: */ paulo@0: payload_len = get_payload_len (partial->data); paulo@0: packet_size = payload_len + GNUTELLA_HDR_LEN; paulo@0: paulo@0: /* paulo@0: * Check for wraparound, and reset the packet size to its payload len. paulo@0: * Its likely we've experienced a protocol de-sync here. Set the size so paulo@0: * the connection will be closed. paulo@0: */ paulo@0: if (packet_size < GNUTELLA_HDR_LEN) paulo@0: packet_size = GT_PACKET_MAX; paulo@0: paulo@0: if (packet_size >= GT_PACKET_MAX) paulo@0: { paulo@0: if (IO_DEBUG) paulo@0: GT->dbg (GT, "received too large packet(%d)", packet_size); paulo@0: paulo@0: /* TODO: should send a BYE message here */ paulo@0: gt_rx_stack_abort (rx->stack); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: if (!fill_up_to (rx, partial, io_buf, packet_size)) paulo@0: { paulo@0: /* this would fail if there was an alloc failure */ paulo@0: assert (io_buf_read_avail (io_buf) == 0); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: /* yay, read a packet */ paulo@0: pkt = make_packet (rx, rx_packet, packet_size); paulo@0: *ret = pkt; paulo@0: paulo@0: return (pkt == NULL ? FALSE : TRUE); paulo@0: } paulo@0: paulo@0: /* paulo@0: * Receive a message buffer from the lower layer, parse it into as many paulo@0: * packets as it contains, and pass those to our handler function. paulo@0: * paulo@0: * This is meant to be the top layer of the rx stack only. paulo@0: * paulo@0: * TODO: A handler could be implemented as another layer, should think paulo@0: * about this approach instead. paulo@0: */ paulo@0: static void rx_packet_recv (struct rx_layer *rx, struct io_buf *io_buf) paulo@0: { paulo@0: GtPacket *packet = NULL; paulo@0: struct rx_packet *rx_packet; paulo@0: paulo@0: rx_packet = RX_PACKET(rx); paulo@0: paulo@0: while (rx->enabled && io_buf_read_avail (io_buf) > 0) paulo@0: { paulo@0: /* allocate a new partial buffer, if one is not present yet */ paulo@0: if (!rx_packet->partial && paulo@0: !(rx_packet->partial = io_buf_new (GNUTELLA_HDR_LEN))) paulo@0: { paulo@0: gt_rx_stack_abort (rx->stack); paulo@0: break; paulo@0: } paulo@0: paulo@0: /* try to read the first 23 bytes */ paulo@0: if (!fill_header (rx, rx_packet, io_buf)) paulo@0: break; paulo@0: paulo@0: /* paulo@0: * Read the payload. If there arent enough bytes to complete the paulo@0: * packet, we finish it later. paulo@0: */ paulo@0: if (!read_packet (rx, rx_packet, io_buf, &packet)) paulo@0: { paulo@0: assert (packet == NULL); paulo@0: break; paulo@0: } paulo@0: paulo@0: assert (packet != NULL); paulo@0: (*rx_packet->handler) (rx_packet->udata, packet); paulo@0: paulo@0: /* freeing the packet here means the callback must make its own paulo@0: * provisions for storing the packet's data */ paulo@0: gt_packet_free (packet); paulo@0: packet = NULL; paulo@0: } paulo@0: paulo@0: io_buf_free (io_buf); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: struct rx_layer_ops gt_rx_packet_ops = paulo@0: { paulo@0: rx_packet_init, paulo@0: rx_packet_destroy, paulo@0: rx_packet_enable, paulo@0: rx_packet_disable, paulo@0: rx_packet_recv, paulo@0: }; paulo@0: paulo@0: void gt_rx_packet_set_handler (struct rx_layer *rx, paulo@0: rx_packet_handler_t handler, paulo@0: void *udata) paulo@0: { paulo@0: struct rx_packet *rx_packet = RX_PACKET(rx); paulo@0: paulo@0: rx_packet->handler = handler; paulo@0: rx_packet->udata = udata; paulo@0: }