annotate src/io/tx_stack.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: tx_stack.c,v 1.12 2004/04/17 06:07:33 hipnod Exp $
paulo@0 3 *
paulo@0 4 * Copyright (C) 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 #include "gt_packet.h" /* gt_packet_log XXX */
paulo@0 19
paulo@0 20 #include "io/tx_stack.h"
paulo@0 21 #include "io/tx_layer.h"
paulo@0 22 #include "io/io_buf.h"
paulo@0 23
paulo@0 24 /*****************************************************************************/
paulo@0 25
paulo@0 26 extern struct tx_layer_ops gt_tx_packet_ops;
paulo@0 27 extern struct tx_layer_ops gt_tx_deflate_ops;
paulo@0 28 extern struct tx_layer_ops gt_tx_link_ops;
paulo@0 29
paulo@0 30 /*****************************************************************************/
paulo@0 31
paulo@0 32 static struct use_tx_layer
paulo@0 33 {
paulo@0 34 const char *name;
paulo@0 35 struct tx_layer_ops *ops;
paulo@0 36 } tx_layers[] =
paulo@0 37 {
paulo@0 38 { "tx_link", &gt_tx_link_ops, },
paulo@0 39 { "tx_deflate", &gt_tx_deflate_ops },
paulo@0 40 { "tx_packet", &gt_tx_packet_ops },
paulo@0 41 };
paulo@0 42
paulo@0 43 /*****************************************************************************/
paulo@0 44
paulo@0 45 static void foreach_tx_child (struct tx_layer *tx,
paulo@0 46 void (*exec) (struct tx_layer *tx))
paulo@0 47 {
paulo@0 48 struct tx_layer *next;
paulo@0 49
paulo@0 50 while (tx != NULL)
paulo@0 51 {
paulo@0 52 /* grab the next element first so the callback can call free */
paulo@0 53 next = tx->lower;
paulo@0 54
paulo@0 55 exec (tx);
paulo@0 56
paulo@0 57 tx = next;
paulo@0 58 }
paulo@0 59 }
paulo@0 60
paulo@0 61 static struct tx_layer *tx_push_layer (struct tx_layer *below,
paulo@0 62 struct tx_layer *above)
paulo@0 63 {
paulo@0 64 if (above)
paulo@0 65 above->lower = below;
paulo@0 66
paulo@0 67 if (below)
paulo@0 68 below->upper = above;
paulo@0 69
paulo@0 70 return above;
paulo@0 71 }
paulo@0 72
paulo@0 73 static void destroy_tx (struct tx_layer *tx)
paulo@0 74 {
paulo@0 75 gt_tx_layer_free (tx);
paulo@0 76 }
paulo@0 77
paulo@0 78 static void disable_tx (struct tx_layer *tx)
paulo@0 79 {
paulo@0 80 gt_tx_layer_disable (tx);
paulo@0 81 }
paulo@0 82
paulo@0 83 static void disable_all_tx_layers (struct tx_layer *layers)
paulo@0 84 {
paulo@0 85 if (!layers)
paulo@0 86 return;
paulo@0 87
paulo@0 88 assert (layers->upper == NULL);
paulo@0 89
paulo@0 90 foreach_tx_child (layers, disable_tx);
paulo@0 91 }
paulo@0 92
paulo@0 93 static void free_all_tx_layers (struct tx_layer *layers)
paulo@0 94 {
paulo@0 95 if (!layers)
paulo@0 96 return;
paulo@0 97
paulo@0 98 disable_all_tx_layers (layers);
paulo@0 99 foreach_tx_child (layers, destroy_tx);
paulo@0 100 }
paulo@0 101
paulo@0 102 static struct tx_layer *alloc_tx_layers (GtTxStack *stack, BOOL tx_deflated)
paulo@0 103 {
paulo@0 104 struct tx_layer *new_layer;
paulo@0 105 struct tx_layer *layer = NULL;
paulo@0 106 int i;
paulo@0 107
paulo@0 108 for (i = 0; i < sizeof(tx_layers) / sizeof(tx_layers[0]); i++)
paulo@0 109 {
paulo@0 110 if (!strcmp (tx_layers[i].name, "tx_deflate") && !tx_deflated)
paulo@0 111 continue;
paulo@0 112
paulo@0 113 if (!(new_layer = gt_tx_layer_new (stack, tx_layers[i].name,
paulo@0 114 tx_layers[i].ops)))
paulo@0 115 {
paulo@0 116 foreach_tx_child (layer, destroy_tx);
paulo@0 117 return NULL;
paulo@0 118 }
paulo@0 119
paulo@0 120 layer = tx_push_layer (layer, new_layer);
paulo@0 121 }
paulo@0 122
paulo@0 123 return layer;
paulo@0 124 }
paulo@0 125
paulo@0 126 GtTxStack *gt_tx_stack_new (TCPC *c, BOOL tx_deflated)
paulo@0 127 {
paulo@0 128 struct gt_tx_stack *stack;
paulo@0 129 int size;
paulo@0 130
paulo@0 131 if (!(stack = NEW (struct gt_tx_stack)))
paulo@0 132 return NULL;
paulo@0 133
paulo@0 134 if (!(stack->layers = alloc_tx_layers (stack, tx_deflated)))
paulo@0 135 {
paulo@0 136 free (stack);
paulo@0 137 return NULL;
paulo@0 138 }
paulo@0 139
paulo@0 140 /* set the send buffer to a not too high value */
paulo@0 141 size = 256;
paulo@0 142
paulo@0 143 if (setsockopt (c->fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) != 0)
paulo@0 144 GT->DBGSOCK (GT, c, "Error setting sndbuf size: %s", GIFT_NETERROR());
paulo@0 145
paulo@0 146 stack->c = c;
paulo@0 147 stack->start_time = time (NULL);
paulo@0 148
paulo@0 149 return stack;
paulo@0 150 }
paulo@0 151
paulo@0 152 /*****************************************************************************/
paulo@0 153
paulo@0 154 void gt_tx_stack_free (GtTxStack *stack)
paulo@0 155 {
paulo@0 156 if (!stack)
paulo@0 157 return;
paulo@0 158
paulo@0 159 free_all_tx_layers (stack->layers);
paulo@0 160 FREE (stack);
paulo@0 161 }
paulo@0 162
paulo@0 163 void gt_tx_stack_abort (GtTxStack *stack)
paulo@0 164 {
paulo@0 165 stack->cleanup (stack, stack->udata);
paulo@0 166 }
paulo@0 167
paulo@0 168 /*****************************************************************************/
paulo@0 169
paulo@0 170 static void activate_tx (struct tx_layer *tx)
paulo@0 171 {
paulo@0 172 tx->ops->toggle (tx, FALSE);
paulo@0 173 }
paulo@0 174
paulo@0 175 /*
paulo@0 176 * Start sending data down the stack. Called asynchronously by the topmost
paulo@0 177 * layer.
paulo@0 178 */
paulo@0 179 void gt_tx_stack_activate (GtTxStack *stack)
paulo@0 180 {
paulo@0 181 foreach_tx_child (stack->layers, activate_tx);
paulo@0 182 }
paulo@0 183
paulo@0 184 static void deactivate_tx (struct tx_layer *tx)
paulo@0 185 {
paulo@0 186 tx->ops->toggle (tx, TRUE);
paulo@0 187 }
paulo@0 188
paulo@0 189 void gt_tx_stack_deactivate (GtTxStack *stack)
paulo@0 190 {
paulo@0 191 foreach_tx_child (stack->layers, deactivate_tx);
paulo@0 192 }
paulo@0 193
paulo@0 194 /*****************************************************************************/
paulo@0 195
paulo@0 196 BOOL gt_tx_stack_queue (GtTxStack *stack, const uint8_t *data, size_t len)
paulo@0 197 {
paulo@0 198 struct io_buf *io_buf;
paulo@0 199 struct tx_layer *tx;
paulo@0 200 uint8_t *ptr;
paulo@0 201 tx_status_t ret;
paulo@0 202 GtPacket pkt;
paulo@0 203
paulo@0 204 if (!(io_buf = io_buf_new (len)))
paulo@0 205 return FALSE;
paulo@0 206
paulo@0 207 ptr = io_buf_write_ptr (io_buf);
paulo@0 208
paulo@0 209 memcpy (ptr, data, len);
paulo@0 210 io_buf_push (io_buf, len);
paulo@0 211
paulo@0 212 tx = stack->layers;
paulo@0 213
paulo@0 214 /* send the data on its way down the stack */
paulo@0 215 if ((ret = tx->ops->queue (tx, io_buf)) != TX_OK)
paulo@0 216 {
paulo@0 217 GT->DBGSOCK (GT, stack->c, "bad txstatus: %d", ret);
paulo@0 218 gt_tx_stack_abort (stack);
paulo@0 219 return FALSE;
paulo@0 220 }
paulo@0 221
paulo@0 222 pkt.data = (unsigned char *)data;
paulo@0 223 pkt.len = len;
paulo@0 224
paulo@0 225 gt_packet_log (&pkt, stack->c, TRUE);
paulo@0 226
paulo@0 227 /*
paulo@0 228 * Activate the stack if not active already. NOTE: this actually
paulo@0 229 * sucks bad when using compression because we end up enabling, then
paulo@0 230 * disabling right away until some data is compressed by nagle timer.
paulo@0 231 */
paulo@0 232 gt_tx_stack_activate (stack);
paulo@0 233
paulo@0 234 return TRUE;
paulo@0 235 }
paulo@0 236
paulo@0 237 int gt_tx_stack_send (GtTxStack *stack, const uint8_t *data, size_t len)
paulo@0 238 {
paulo@0 239 int ret;
paulo@0 240
paulo@0 241 /* check if the file descriptor has an error */
paulo@0 242 if (net_sock_error (stack->c->fd))
paulo@0 243 return -1;
paulo@0 244
paulo@0 245 ret = tcp_send (stack->c, (unsigned char *)data, len);
paulo@0 246
paulo@0 247 return ret;
paulo@0 248 }
paulo@0 249
paulo@0 250 void gt_tx_stack_set_handler (GtTxStack *stack, GtTxStackCleanup cleanup,
paulo@0 251 void *udata)
paulo@0 252 {
paulo@0 253 stack->cleanup = cleanup;
paulo@0 254 stack->udata = udata;
paulo@0 255 }