paulo@0: /* paulo@0: * $Id: rx_link.c,v 1.7 2004/02/01 08:17:12 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_layer.h" paulo@0: #include "rx_link.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: struct rx_link paulo@0: { paulo@0: /* TODO when the tx stack is implemented also paulo@0: * right now cleanup is too hard */ paulo@0: #if 0 paulo@0: struct io_source *ios; paulo@0: #endif paulo@0: TCPC *c; paulo@0: input_id id; paulo@0: }; paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* Some macros for readability */ paulo@0: paulo@0: #define RX_LINK(rx) \ paulo@0: ((struct rx_link *)((rx)->udata)) paulo@0: paulo@0: #define IO_SOURCE(rx_link) \ paulo@0: ((rx_link)->ios) paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* TODO: implement cached allocation */ paulo@0: #define RX_LINK_BUFSIZE 512 paulo@0: paulo@0: /* paulo@0: * This implementation is for bootstrapping the code onto paulo@0: * the present system. paulo@0: * paulo@0: * The low-level details of what we are actually reading paulo@0: * from should be abstracted away. paulo@0: */ paulo@0: static void read_data (int fd, input_id id, struct rx_layer *rx) paulo@0: { paulo@0: struct rx_link *rx_link = RX_LINK(rx); paulo@0: struct io_buf *io_buf; paulo@0: ssize_t n; paulo@0: paulo@0: /* we're processing data, we'd better be enabled */ paulo@0: assert (rx->enabled); paulo@0: paulo@0: if (!(io_buf = io_buf_new (RX_LINK_BUFSIZE))) paulo@0: { paulo@0: gt_rx_stack_abort (rx->stack); paulo@0: return; paulo@0: } paulo@0: paulo@0: if ((n = tcp_recv (rx_link->c, io_buf_write_ptr (io_buf), paulo@0: RX_LINK_BUFSIZE)) <= 0) paulo@0: { paulo@0: if (IO_DEBUG) paulo@0: { paulo@0: if (n < 0) paulo@0: GT->DBGSOCK (GT, rx_link->c, "recv error: %s", GIFT_NETERROR()); paulo@0: else paulo@0: GT->DBGSOCK (GT, rx_link->c, "recv error: socket closed"); paulo@0: } paulo@0: paulo@0: io_buf_free (io_buf); paulo@0: gt_rx_stack_abort (rx->stack); paulo@0: return; paulo@0: } paulo@0: paulo@0: /* set the data as having been read */ paulo@0: io_buf_push (io_buf, n); paulo@0: paulo@0: /* paulo@0: * Pass the data up the stack. paulo@0: */ paulo@0: gt_rx_layer_recv (rx, io_buf); paulo@0: } paulo@0: paulo@0: #if 0 paulo@0: /* paulo@0: * Receive data from the I/O source, and pass it up the stack paulo@0: */ paulo@0: static void recv_data (struct io_source *ios, struct io_buf *io_buf) paulo@0: { paulo@0: struct rx_layer *rx; paulo@0: struct rx_link *rx_link; paulo@0: ssize_t n; paulo@0: paulo@0: rx = ios->recv_data; paulo@0: rx_link = RX_LINK(rx); paulo@0: paulo@0: /* paulo@0: * Pass the data to an upper layer. paulo@0: */ paulo@0: gt_rx_layer_recv (rx, io_buf); paulo@0: paulo@0: /* paulo@0: * ?? we have to free io_buf here ?? No. paulo@0: * gtk-gnutella passes off responsibility to the upper layers, paulo@0: * but why.. paulo@0: */ paulo@0: #if 0 paulo@0: return n; paulo@0: #endif paulo@0: /* paulo@0: * Think i may understand why gtk-gnutella does it that way now: paulo@0: * in the partial packet case there may be unread data on the packet, paulo@0: * so we have to store that partial packet data in the intermediate paulo@0: * layers. paulo@0: * paulo@0: * I still wonder if its possible to use a static buffer at each layer paulo@0: * though... paulo@0: */ paulo@0: } paulo@0: #endif paulo@0: paulo@0: static void init_input (struct rx_layer *rx, struct rx_link *rx_link) paulo@0: { paulo@0: assert (rx_link->id == 0); paulo@0: rx_link->id = input_add (rx_link->c->fd, rx, INPUT_READ, paulo@0: (InputCallback)read_data, 0); paulo@0: } paulo@0: paulo@0: static void free_input (struct rx_layer *rx, struct rx_link *rx_link) paulo@0: { paulo@0: /* paulo@0: * This could be called multiple times on cleanup, paulo@0: * so we don't assert the id is 0 here. paulo@0: */ paulo@0: if (rx_link->id) paulo@0: { paulo@0: input_remove (rx_link->id); paulo@0: rx_link->id = 0; paulo@0: } paulo@0: } paulo@0: paulo@0: static void rx_link_enable (struct rx_layer *rx) paulo@0: { paulo@0: struct rx_link *rx_link = RX_LINK(rx); paulo@0: paulo@0: #if 0 paulo@0: /* set the callback for getting data */ paulo@0: io_source_enable (IO_SOURCE(rx_link), IO_SOURCE_OP_RECV, recv_data, rx); paulo@0: #endif paulo@0: paulo@0: init_input (rx, rx_link); paulo@0: } paulo@0: paulo@0: static void rx_link_disable (struct rx_layer *rx) paulo@0: { paulo@0: struct rx_link *rx_link = RX_LINK(rx); paulo@0: paulo@0: #if 0 paulo@0: io_source_disable (IO_SOURCE(rx_link), IO_SOURCE_OP_RECV); paulo@0: #endif paulo@0: free_input (rx, rx_link); paulo@0: } paulo@0: paulo@0: static BOOL rx_link_init (struct rx_layer *rx, void *udata) paulo@0: { paulo@0: struct rx_link *rx_link; paulo@0: TCPC *c = (TCPC *) udata; /* ewwww */ paulo@0: paulo@0: if (!(rx_link = NEW (struct rx_link))) paulo@0: return FALSE; paulo@0: paulo@0: /* store the connection which we get from the upper layer...gross */ paulo@0: rx_link->c = c; paulo@0: paulo@0: /* store our data in the rx structure */ paulo@0: rx->udata = rx_link; paulo@0: paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: static void rx_link_destroy (struct rx_layer *rx) paulo@0: { paulo@0: struct rx_link *rx_link = RX_LINK(rx); paulo@0: paulo@0: /* paulo@0: * rx_link_disable() should be called first paulo@0: */ paulo@0: assert (rx_link->id == 0); paulo@0: paulo@0: /* paulo@0: * We would free the connection here, but its shared with paulo@0: * a GtNode that frees it also at the moment. paulo@0: */ paulo@0: #if 0 paulo@0: tcp_close (rx->c); paulo@0: #endif paulo@0: paulo@0: #if 0 paulo@0: io_source_free (rx_link->ios); paulo@0: #endif paulo@0: paulo@0: FREE (rx_link); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: struct rx_layer_ops gt_rx_link_ops = paulo@0: { paulo@0: rx_link_init, paulo@0: rx_link_destroy, paulo@0: rx_link_enable, paulo@0: rx_link_disable, paulo@0: NULL, /* rx_link_recv */ paulo@0: };