view 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
line source
1 /*
2 * $Id: tx_stack.c,v 1.12 2004/04/17 06:07:33 hipnod Exp $
3 *
4 * Copyright (C) 2003 giFT project (gift.sourceforge.net)
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 */
17 #include "gt_gnutella.h"
18 #include "gt_packet.h" /* gt_packet_log XXX */
20 #include "io/tx_stack.h"
21 #include "io/tx_layer.h"
22 #include "io/io_buf.h"
24 /*****************************************************************************/
26 extern struct tx_layer_ops gt_tx_packet_ops;
27 extern struct tx_layer_ops gt_tx_deflate_ops;
28 extern struct tx_layer_ops gt_tx_link_ops;
30 /*****************************************************************************/
32 static struct use_tx_layer
33 {
34 const char *name;
35 struct tx_layer_ops *ops;
36 } tx_layers[] =
37 {
38 { "tx_link", &gt_tx_link_ops, },
39 { "tx_deflate", &gt_tx_deflate_ops },
40 { "tx_packet", &gt_tx_packet_ops },
41 };
43 /*****************************************************************************/
45 static void foreach_tx_child (struct tx_layer *tx,
46 void (*exec) (struct tx_layer *tx))
47 {
48 struct tx_layer *next;
50 while (tx != NULL)
51 {
52 /* grab the next element first so the callback can call free */
53 next = tx->lower;
55 exec (tx);
57 tx = next;
58 }
59 }
61 static struct tx_layer *tx_push_layer (struct tx_layer *below,
62 struct tx_layer *above)
63 {
64 if (above)
65 above->lower = below;
67 if (below)
68 below->upper = above;
70 return above;
71 }
73 static void destroy_tx (struct tx_layer *tx)
74 {
75 gt_tx_layer_free (tx);
76 }
78 static void disable_tx (struct tx_layer *tx)
79 {
80 gt_tx_layer_disable (tx);
81 }
83 static void disable_all_tx_layers (struct tx_layer *layers)
84 {
85 if (!layers)
86 return;
88 assert (layers->upper == NULL);
90 foreach_tx_child (layers, disable_tx);
91 }
93 static void free_all_tx_layers (struct tx_layer *layers)
94 {
95 if (!layers)
96 return;
98 disable_all_tx_layers (layers);
99 foreach_tx_child (layers, destroy_tx);
100 }
102 static struct tx_layer *alloc_tx_layers (GtTxStack *stack, BOOL tx_deflated)
103 {
104 struct tx_layer *new_layer;
105 struct tx_layer *layer = NULL;
106 int i;
108 for (i = 0; i < sizeof(tx_layers) / sizeof(tx_layers[0]); i++)
109 {
110 if (!strcmp (tx_layers[i].name, "tx_deflate") && !tx_deflated)
111 continue;
113 if (!(new_layer = gt_tx_layer_new (stack, tx_layers[i].name,
114 tx_layers[i].ops)))
115 {
116 foreach_tx_child (layer, destroy_tx);
117 return NULL;
118 }
120 layer = tx_push_layer (layer, new_layer);
121 }
123 return layer;
124 }
126 GtTxStack *gt_tx_stack_new (TCPC *c, BOOL tx_deflated)
127 {
128 struct gt_tx_stack *stack;
129 int size;
131 if (!(stack = NEW (struct gt_tx_stack)))
132 return NULL;
134 if (!(stack->layers = alloc_tx_layers (stack, tx_deflated)))
135 {
136 free (stack);
137 return NULL;
138 }
140 /* set the send buffer to a not too high value */
141 size = 256;
143 if (setsockopt (c->fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) != 0)
144 GT->DBGSOCK (GT, c, "Error setting sndbuf size: %s", GIFT_NETERROR());
146 stack->c = c;
147 stack->start_time = time (NULL);
149 return stack;
150 }
152 /*****************************************************************************/
154 void gt_tx_stack_free (GtTxStack *stack)
155 {
156 if (!stack)
157 return;
159 free_all_tx_layers (stack->layers);
160 FREE (stack);
161 }
163 void gt_tx_stack_abort (GtTxStack *stack)
164 {
165 stack->cleanup (stack, stack->udata);
166 }
168 /*****************************************************************************/
170 static void activate_tx (struct tx_layer *tx)
171 {
172 tx->ops->toggle (tx, FALSE);
173 }
175 /*
176 * Start sending data down the stack. Called asynchronously by the topmost
177 * layer.
178 */
179 void gt_tx_stack_activate (GtTxStack *stack)
180 {
181 foreach_tx_child (stack->layers, activate_tx);
182 }
184 static void deactivate_tx (struct tx_layer *tx)
185 {
186 tx->ops->toggle (tx, TRUE);
187 }
189 void gt_tx_stack_deactivate (GtTxStack *stack)
190 {
191 foreach_tx_child (stack->layers, deactivate_tx);
192 }
194 /*****************************************************************************/
196 BOOL gt_tx_stack_queue (GtTxStack *stack, const uint8_t *data, size_t len)
197 {
198 struct io_buf *io_buf;
199 struct tx_layer *tx;
200 uint8_t *ptr;
201 tx_status_t ret;
202 GtPacket pkt;
204 if (!(io_buf = io_buf_new (len)))
205 return FALSE;
207 ptr = io_buf_write_ptr (io_buf);
209 memcpy (ptr, data, len);
210 io_buf_push (io_buf, len);
212 tx = stack->layers;
214 /* send the data on its way down the stack */
215 if ((ret = tx->ops->queue (tx, io_buf)) != TX_OK)
216 {
217 GT->DBGSOCK (GT, stack->c, "bad txstatus: %d", ret);
218 gt_tx_stack_abort (stack);
219 return FALSE;
220 }
222 pkt.data = (unsigned char *)data;
223 pkt.len = len;
225 gt_packet_log (&pkt, stack->c, TRUE);
227 /*
228 * Activate the stack if not active already. NOTE: this actually
229 * sucks bad when using compression because we end up enabling, then
230 * disabling right away until some data is compressed by nagle timer.
231 */
232 gt_tx_stack_activate (stack);
234 return TRUE;
235 }
237 int gt_tx_stack_send (GtTxStack *stack, const uint8_t *data, size_t len)
238 {
239 int ret;
241 /* check if the file descriptor has an error */
242 if (net_sock_error (stack->c->fd))
243 return -1;
245 ret = tcp_send (stack->c, (unsigned char *)data, len);
247 return ret;
248 }
250 void gt_tx_stack_set_handler (GtTxStack *stack, GtTxStackCleanup cleanup,
251 void *udata)
252 {
253 stack->cleanup = cleanup;
254 stack->udata = udata;
255 }