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", >_tx_link_ops, },
|
paulo@0
|
39 { "tx_deflate", >_tx_deflate_ops },
|
paulo@0
|
40 { "tx_packet", >_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 }
|