Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
diff src/io/rx_packet.c @ 0:d39e1d0d75b6
initial add
author | paulo@hit-nxdomain.opendns.com |
---|---|
date | Sat, 20 Feb 2010 21:18:28 -0800 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/io/rx_packet.c Sat Feb 20 21:18:28 2010 -0800 1.3 @@ -0,0 +1,289 @@ 1.4 +/* 1.5 + * $Id: rx_packet.c,v 1.7 2004/02/15 04:53:38 hipnod Exp $ 1.6 + * 1.7 + * Copyright (C) 2003 giFT project (gift.sourceforge.net) 1.8 + * 1.9 + * This program is free software; you can redistribute it and/or modify it 1.10 + * under the terms of the GNU General Public License as published by the 1.11 + * Free Software Foundation; either version 2, or (at your option) any 1.12 + * later version. 1.13 + * 1.14 + * This program is distributed in the hope that it will be useful, but 1.15 + * WITHOUT ANY WARRANTY; without even the implied warranty of 1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.17 + * General Public License for more details. 1.18 + */ 1.19 + 1.20 +#include "gt_gnutella.h" 1.21 + 1.22 +#include "rx_stack.h" 1.23 +#include "rx_layer.h" 1.24 + 1.25 +#include "gt_packet.h" 1.26 +#include "rx_packet.h" 1.27 + 1.28 +/*****************************************************************************/ 1.29 + 1.30 +struct rx_packet 1.31 +{ 1.32 + struct io_buf *partial; 1.33 + rx_packet_handler_t handler; 1.34 + void *udata; 1.35 +}; 1.36 + 1.37 +/*****************************************************************************/ 1.38 + 1.39 +#define RX_PACKET(rx) \ 1.40 + ((struct rx_packet *) ((rx)->udata)) 1.41 + 1.42 +/*****************************************************************************/ 1.43 + 1.44 +static void null_packet_handler (void *udata, GtPacket *packet) 1.45 +{ 1.46 + gt_packet_free (packet); 1.47 +} 1.48 + 1.49 +static BOOL rx_packet_init (struct rx_layer *rx, void *udata) 1.50 +{ 1.51 + struct rx_packet *rx_packet; 1.52 + 1.53 + if (!(rx_packet = NEW (struct rx_packet))) 1.54 + return FALSE; 1.55 + 1.56 + rx->udata = rx_packet; 1.57 + 1.58 + /* discard the packets received */ 1.59 + rx_packet->handler = null_packet_handler; 1.60 + return TRUE; 1.61 +} 1.62 + 1.63 +static void rx_packet_destroy (struct rx_layer *rx) 1.64 +{ 1.65 + struct rx_packet *rx_packet = RX_PACKET(rx); 1.66 + 1.67 + io_buf_free (rx_packet->partial); 1.68 + FREE (rx_packet); 1.69 +} 1.70 + 1.71 +static void rx_packet_disable (struct rx_layer *rx) 1.72 +{ 1.73 + /* NOP: lower layer will stop sending us data -- it'd better 1.74 + * stop now */ 1.75 +} 1.76 + 1.77 +static void rx_packet_enable (struct rx_layer *rx) 1.78 +{ 1.79 + /* NOP: the lower layer will start sending us data again */ 1.80 +} 1.81 + 1.82 +/*****************************************************************************/ 1.83 + 1.84 +static GtPacket *make_packet (struct rx_layer *rx, struct rx_packet *rx_packet, 1.85 + size_t packet_size) 1.86 +{ 1.87 + GtPacket *packet; 1.88 + struct io_buf *pbuf = rx_packet->partial; 1.89 + 1.90 + assert (io_buf_len (pbuf) == packet_size); 1.91 + assert (packet_size < GT_PACKET_MAX); 1.92 + 1.93 + /* construct a complete packet from the data in the binary buf */ 1.94 + packet = gt_packet_unserialize (pbuf->data, packet_size); 1.95 + 1.96 + /* 1.97 + * TODO: gt_packet_unserialize() currently copies the data, but should 1.98 + * really take ownership of the data in place. That would also allow the 1.99 + * null terminator in the io_buf to terminate the last string in the 1.100 + * packet, if any. 1.101 + */ 1.102 + io_buf_free (pbuf); 1.103 + rx_packet->partial = NULL; 1.104 + 1.105 + if (!packet) 1.106 + { 1.107 + gt_rx_stack_abort (rx->stack); 1.108 + return NULL; 1.109 + } 1.110 + 1.111 + return packet; 1.112 +} 1.113 + 1.114 +static BOOL fill_up_to (struct rx_layer *rx, struct io_buf *dst, 1.115 + struct io_buf *src, size_t fill_size) 1.116 +{ 1.117 + size_t new_len; 1.118 + size_t old_len; 1.119 + size_t len_to_read; 1.120 + 1.121 + old_len = io_buf_len (dst); 1.122 + new_len = io_buf_len (src); 1.123 + 1.124 + /* skip if we already have enough */ 1.125 + if (old_len >= fill_size) 1.126 + return TRUE; 1.127 + 1.128 + len_to_read = MIN (fill_size - old_len, new_len); 1.129 + 1.130 + /* ensure the packet has enough room */ 1.131 + if (!io_buf_resize (dst, old_len + len_to_read)) 1.132 + { 1.133 + gt_rx_stack_abort (rx->stack); 1.134 + return FALSE; 1.135 + } 1.136 + 1.137 + io_buf_copy (dst, src, len_to_read); 1.138 + 1.139 + if (io_buf_len (dst) >= fill_size) 1.140 + return TRUE; 1.141 + 1.142 + return FALSE; 1.143 +} 1.144 + 1.145 +static BOOL fill_header (struct rx_layer *rx, struct rx_packet *rx_packet, 1.146 + struct io_buf *io_buf) 1.147 +{ 1.148 + struct io_buf *dst = rx_packet->partial; 1.149 + struct io_buf *src = io_buf; 1.150 + 1.151 + if (!fill_up_to (rx, dst, src, GNUTELLA_HDR_LEN)) 1.152 + { 1.153 + /* this would fail if there was an alloc failure */ 1.154 + assert (io_buf_read_avail (io_buf) == 0); 1.155 + return FALSE; 1.156 + } 1.157 + 1.158 + return TRUE; 1.159 +} 1.160 + 1.161 +/* 1.162 + * We must read all the data the lower layer has sent and buffer 1.163 + * partial packets, because otherwise we would poll the CPU if the 1.164 + * packet were bigger than the buffer size of one of the layer 1.165 + * layers under this one. 1.166 + */ 1.167 +static BOOL read_packet (struct rx_layer *rx, struct rx_packet *rx_packet, 1.168 + struct io_buf *io_buf, GtPacket **ret) 1.169 +{ 1.170 + uint32_t payload_len; 1.171 + size_t partial_len; 1.172 + uint32_t packet_size; 1.173 + struct io_buf *partial = rx_packet->partial; 1.174 + GtPacket *pkt; 1.175 + 1.176 + *ret = NULL; 1.177 + 1.178 + partial_len = io_buf_len (partial); 1.179 + assert (partial_len >= GNUTELLA_HDR_LEN); 1.180 + 1.181 + /* 1.182 + * The partial packet is now at least 23 bytes. Look in the header for 1.183 + * the payload length so we know how much we need to read before the 1.184 + * packet is complete. 1.185 + */ 1.186 + payload_len = get_payload_len (partial->data); 1.187 + packet_size = payload_len + GNUTELLA_HDR_LEN; 1.188 + 1.189 + /* 1.190 + * Check for wraparound, and reset the packet size to its payload len. 1.191 + * Its likely we've experienced a protocol de-sync here. Set the size so 1.192 + * the connection will be closed. 1.193 + */ 1.194 + if (packet_size < GNUTELLA_HDR_LEN) 1.195 + packet_size = GT_PACKET_MAX; 1.196 + 1.197 + if (packet_size >= GT_PACKET_MAX) 1.198 + { 1.199 + if (IO_DEBUG) 1.200 + GT->dbg (GT, "received too large packet(%d)", packet_size); 1.201 + 1.202 + /* TODO: should send a BYE message here */ 1.203 + gt_rx_stack_abort (rx->stack); 1.204 + return FALSE; 1.205 + } 1.206 + 1.207 + if (!fill_up_to (rx, partial, io_buf, packet_size)) 1.208 + { 1.209 + /* this would fail if there was an alloc failure */ 1.210 + assert (io_buf_read_avail (io_buf) == 0); 1.211 + return FALSE; 1.212 + } 1.213 + 1.214 + /* yay, read a packet */ 1.215 + pkt = make_packet (rx, rx_packet, packet_size); 1.216 + *ret = pkt; 1.217 + 1.218 + return (pkt == NULL ? FALSE : TRUE); 1.219 +} 1.220 + 1.221 +/* 1.222 + * Receive a message buffer from the lower layer, parse it into as many 1.223 + * packets as it contains, and pass those to our handler function. 1.224 + * 1.225 + * This is meant to be the top layer of the rx stack only. 1.226 + * 1.227 + * TODO: A handler could be implemented as another layer, should think 1.228 + * about this approach instead. 1.229 + */ 1.230 +static void rx_packet_recv (struct rx_layer *rx, struct io_buf *io_buf) 1.231 +{ 1.232 + GtPacket *packet = NULL; 1.233 + struct rx_packet *rx_packet; 1.234 + 1.235 + rx_packet = RX_PACKET(rx); 1.236 + 1.237 + while (rx->enabled && io_buf_read_avail (io_buf) > 0) 1.238 + { 1.239 + /* allocate a new partial buffer, if one is not present yet */ 1.240 + if (!rx_packet->partial && 1.241 + !(rx_packet->partial = io_buf_new (GNUTELLA_HDR_LEN))) 1.242 + { 1.243 + gt_rx_stack_abort (rx->stack); 1.244 + break; 1.245 + } 1.246 + 1.247 + /* try to read the first 23 bytes */ 1.248 + if (!fill_header (rx, rx_packet, io_buf)) 1.249 + break; 1.250 + 1.251 + /* 1.252 + * Read the payload. If there arent enough bytes to complete the 1.253 + * packet, we finish it later. 1.254 + */ 1.255 + if (!read_packet (rx, rx_packet, io_buf, &packet)) 1.256 + { 1.257 + assert (packet == NULL); 1.258 + break; 1.259 + } 1.260 + 1.261 + assert (packet != NULL); 1.262 + (*rx_packet->handler) (rx_packet->udata, packet); 1.263 + 1.264 + /* freeing the packet here means the callback must make its own 1.265 + * provisions for storing the packet's data */ 1.266 + gt_packet_free (packet); 1.267 + packet = NULL; 1.268 + } 1.269 + 1.270 + io_buf_free (io_buf); 1.271 +} 1.272 + 1.273 +/*****************************************************************************/ 1.274 + 1.275 +struct rx_layer_ops gt_rx_packet_ops = 1.276 +{ 1.277 + rx_packet_init, 1.278 + rx_packet_destroy, 1.279 + rx_packet_enable, 1.280 + rx_packet_disable, 1.281 + rx_packet_recv, 1.282 +}; 1.283 + 1.284 +void gt_rx_packet_set_handler (struct rx_layer *rx, 1.285 + rx_packet_handler_t handler, 1.286 + void *udata) 1.287 +{ 1.288 + struct rx_packet *rx_packet = RX_PACKET(rx); 1.289 + 1.290 + rx_packet->handler = handler; 1.291 + rx_packet->udata = udata; 1.292 +}