rev |
line source |
paulo@0
|
1 /*
|
paulo@0
|
2 * $Id: rx_stack.c,v 1.8 2004/02/01 08:17:12 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_node.h"
|
paulo@0
|
19
|
paulo@0
|
20 #include "rx_stack.h"
|
paulo@0
|
21 #include "rx_layer.h"
|
paulo@0
|
22 #include "rx_link.h"
|
paulo@0
|
23 #include "rx_inflate.h"
|
paulo@0
|
24 #include "rx_packet.h"
|
paulo@0
|
25
|
paulo@0
|
26 /*****************************************************************************/
|
paulo@0
|
27
|
paulo@0
|
28 struct gt_rx_stack
|
paulo@0
|
29 {
|
paulo@0
|
30 TCPC *c;
|
paulo@0
|
31 BOOL inflated;
|
paulo@0
|
32
|
paulo@0
|
33 int depth; /* how deep in the stack we have
|
paulo@0
|
34 currently called into the stack */
|
paulo@0
|
35 BOOL aborted; /* one of our layers bailed out */
|
paulo@0
|
36 BOOL free_delayed; /* somebody called free during
|
paulo@0
|
37 message emission, and we delayed
|
paulo@0
|
38 it for later */
|
paulo@0
|
39 void *udata;
|
paulo@0
|
40 struct rx_layer *layers;
|
paulo@0
|
41
|
paulo@0
|
42 GtRxStackHandler handler;
|
paulo@0
|
43 GtRxStackCleanup cleanup;
|
paulo@0
|
44 };
|
paulo@0
|
45
|
paulo@0
|
46 static struct use_layer
|
paulo@0
|
47 {
|
paulo@0
|
48 const char *name;
|
paulo@0
|
49 struct rx_layer_ops *ops;
|
paulo@0
|
50 } layers[] =
|
paulo@0
|
51 {
|
paulo@0
|
52 { "rx_link", >_rx_link_ops },
|
paulo@0
|
53 { "rx_inflate", >_rx_inflate_ops },
|
paulo@0
|
54 { "rx_packet", >_rx_packet_ops },
|
paulo@0
|
55 };
|
paulo@0
|
56
|
paulo@0
|
57 /*****************************************************************************/
|
paulo@0
|
58
|
paulo@0
|
59 static void foreach_child (struct rx_layer *rx,
|
paulo@0
|
60 void (*exec)(struct rx_layer *rx, void *udata),
|
paulo@0
|
61 void *udata)
|
paulo@0
|
62 {
|
paulo@0
|
63 struct rx_layer *next;
|
paulo@0
|
64
|
paulo@0
|
65 while (rx != NULL)
|
paulo@0
|
66 {
|
paulo@0
|
67 /* grab the next element first so the callback can call free */
|
paulo@0
|
68 next = rx->lower;
|
paulo@0
|
69
|
paulo@0
|
70 exec (rx, udata);
|
paulo@0
|
71
|
paulo@0
|
72 rx = next;
|
paulo@0
|
73 }
|
paulo@0
|
74 }
|
paulo@0
|
75
|
paulo@0
|
76 static void disable_layer (struct rx_layer *rx, void *udata)
|
paulo@0
|
77 {
|
paulo@0
|
78 gt_rx_layer_disable (rx);
|
paulo@0
|
79 }
|
paulo@0
|
80
|
paulo@0
|
81 static void destroy_foreach (struct rx_layer *rx, void *udata)
|
paulo@0
|
82 {
|
paulo@0
|
83 gt_rx_layer_free (rx);
|
paulo@0
|
84 }
|
paulo@0
|
85
|
paulo@0
|
86 static void disable_all (GtRxStack *stack)
|
paulo@0
|
87 {
|
paulo@0
|
88 struct rx_layer *layers = stack->layers;
|
paulo@0
|
89
|
paulo@0
|
90 /* we must be at the top layer already */
|
paulo@0
|
91 assert (layers->upper == NULL);
|
paulo@0
|
92
|
paulo@0
|
93 foreach_child (layers, disable_layer, NULL);
|
paulo@0
|
94 }
|
paulo@0
|
95
|
paulo@0
|
96 /*****************************************************************************/
|
paulo@0
|
97
|
paulo@0
|
98 static struct rx_layer *push_layer (struct rx_layer *below,
|
paulo@0
|
99 struct rx_layer *above)
|
paulo@0
|
100 {
|
paulo@0
|
101 if (above)
|
paulo@0
|
102 above->lower = below;
|
paulo@0
|
103
|
paulo@0
|
104 if (below)
|
paulo@0
|
105 below->upper = above;
|
paulo@0
|
106
|
paulo@0
|
107 return above;
|
paulo@0
|
108 }
|
paulo@0
|
109
|
paulo@0
|
110 static void free_all_layers (GtRxStack *stack)
|
paulo@0
|
111 {
|
paulo@0
|
112 struct rx_layer *layers;
|
paulo@0
|
113
|
paulo@0
|
114 if (!stack)
|
paulo@0
|
115 return;
|
paulo@0
|
116
|
paulo@0
|
117 layers = stack->layers;
|
paulo@0
|
118
|
paulo@0
|
119 if (!layers)
|
paulo@0
|
120 return;
|
paulo@0
|
121
|
paulo@0
|
122 /* make sure we've stopped all processing on this layer */
|
paulo@0
|
123 disable_all (stack);
|
paulo@0
|
124
|
paulo@0
|
125 /* call each layer's destroy method */
|
paulo@0
|
126 foreach_child (layers, destroy_foreach, NULL);
|
paulo@0
|
127 }
|
paulo@0
|
128
|
paulo@0
|
129 static struct rx_layer *alloc_layers (GtRxStack *stack, TCPC *c,
|
paulo@0
|
130 BOOL rx_inflated)
|
paulo@0
|
131 {
|
paulo@0
|
132 struct rx_layer *layer = NULL;
|
paulo@0
|
133 struct rx_layer *new_layer = NULL;
|
paulo@0
|
134 void *udata = NULL;
|
paulo@0
|
135 int i;
|
paulo@0
|
136
|
paulo@0
|
137 for (i = 0; i < sizeof(layers) / sizeof(layers[0]); i++)
|
paulo@0
|
138 {
|
paulo@0
|
139 /* XXX */
|
paulo@0
|
140 if (!strcmp (layers[i].name, "rx_link"))
|
paulo@0
|
141 udata = c;
|
paulo@0
|
142
|
paulo@0
|
143 if (!strcmp (layers[i].name, "rx_inflate") && !rx_inflated)
|
paulo@0
|
144 continue;
|
paulo@0
|
145
|
paulo@0
|
146 if (!(new_layer = gt_rx_layer_new (stack, layers[i].name,
|
paulo@0
|
147 layers[i].ops, udata)))
|
paulo@0
|
148 {
|
paulo@0
|
149 foreach_child (layer, destroy_foreach, NULL);
|
paulo@0
|
150 return NULL;
|
paulo@0
|
151 }
|
paulo@0
|
152
|
paulo@0
|
153 layer = push_layer (layer, new_layer);
|
paulo@0
|
154 udata = NULL;
|
paulo@0
|
155 }
|
paulo@0
|
156
|
paulo@0
|
157 return layer;
|
paulo@0
|
158 }
|
paulo@0
|
159
|
paulo@0
|
160 /*****************************************************************************/
|
paulo@0
|
161
|
paulo@0
|
162 static void enable_layer (struct rx_layer *rx, void *udata)
|
paulo@0
|
163 {
|
paulo@0
|
164 gt_rx_layer_enable (rx);
|
paulo@0
|
165 }
|
paulo@0
|
166
|
paulo@0
|
167 GtRxStack *gt_rx_stack_new (GtNode *node, TCPC *c, BOOL rx_inflated)
|
paulo@0
|
168 {
|
paulo@0
|
169 GtRxStack *stack;
|
paulo@0
|
170 int size;
|
paulo@0
|
171
|
paulo@0
|
172 if (!(stack = NEW (GtRxStack)))
|
paulo@0
|
173 return NULL;
|
paulo@0
|
174
|
paulo@0
|
175 stack->c = c;
|
paulo@0
|
176 stack->inflated = rx_inflated;
|
paulo@0
|
177
|
paulo@0
|
178 if (!(stack->layers = alloc_layers (stack, c, rx_inflated)))
|
paulo@0
|
179 {
|
paulo@0
|
180 free (stack);
|
paulo@0
|
181 return NULL;
|
paulo@0
|
182 }
|
paulo@0
|
183
|
paulo@0
|
184 /* set the receive buf to a not large value */
|
paulo@0
|
185 size = 4096;
|
paulo@0
|
186
|
paulo@0
|
187 if (setsockopt (c->fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) != 0)
|
paulo@0
|
188 GT->DBGSOCK (GT, c, "Error setting rcvbuf size: %s", GIFT_NETERROR());
|
paulo@0
|
189
|
paulo@0
|
190 /* enable each layer */
|
paulo@0
|
191 foreach_child (stack->layers, enable_layer, NULL);
|
paulo@0
|
192
|
paulo@0
|
193 return stack;
|
paulo@0
|
194 }
|
paulo@0
|
195
|
paulo@0
|
196 /*****************************************************************************/
|
paulo@0
|
197
|
paulo@0
|
198 /*
|
paulo@0
|
199 * Cleanup handling. This is a bit tricky, because both the owner of the
|
paulo@0
|
200 * stack and the stack itself may want to free the stack, and they both have
|
paulo@0
|
201 * to coordinate so only one of them does the free().
|
paulo@0
|
202 *
|
paulo@0
|
203 * Also, the stack has to worry about the free happening whilst a message
|
paulo@0
|
204 * emission is taking place, and so has to unwind the stack to the top level
|
paulo@0
|
205 * to make sure it doesn't reference freed memory.
|
paulo@0
|
206 */
|
paulo@0
|
207
|
paulo@0
|
208 static void free_stack (GtRxStack *stack)
|
paulo@0
|
209 {
|
paulo@0
|
210 /*
|
paulo@0
|
211 * ->cleanup gets called from the lower layers, and only
|
paulo@0
|
212 * if something bad happened (socket close, etc).
|
paulo@0
|
213 */
|
paulo@0
|
214 free_all_layers (stack);
|
paulo@0
|
215 FREE (stack);
|
paulo@0
|
216 }
|
paulo@0
|
217
|
paulo@0
|
218 void gt_rx_stack_free (GtRxStack *stack)
|
paulo@0
|
219 {
|
paulo@0
|
220 if (!stack)
|
paulo@0
|
221 return;
|
paulo@0
|
222
|
paulo@0
|
223 /*
|
paulo@0
|
224 * If we in the middle of a reception when someone calls this function
|
paulo@0
|
225 * [say by calling gt_node_disconenct()], we can't free right now
|
paulo@0
|
226 * because the data structures are still in use in the reception stack.
|
paulo@0
|
227 *
|
paulo@0
|
228 * So we queue the removal in that case, by setting free_delayed and
|
paulo@0
|
229 * freeing when the stack unwinds, just like when waiting to notify the
|
paulo@0
|
230 * stack's listener about gt_rx_stack_abort().
|
paulo@0
|
231 */
|
paulo@0
|
232 if (stack->depth > 0)
|
paulo@0
|
233 {
|
paulo@0
|
234 /* we'll defer the real free until later */
|
paulo@0
|
235 stack->free_delayed = TRUE;
|
paulo@0
|
236
|
paulo@0
|
237 /* we must stop processing */
|
paulo@0
|
238 gt_rx_stack_abort (stack);
|
paulo@0
|
239
|
paulo@0
|
240 return;
|
paulo@0
|
241 }
|
paulo@0
|
242
|
paulo@0
|
243 free_stack (stack);
|
paulo@0
|
244 }
|
paulo@0
|
245
|
paulo@0
|
246 /* notify the user of the stack it's time to clean up this stack */
|
paulo@0
|
247 static void cleanup_notify (GtRxStack *stack)
|
paulo@0
|
248 {
|
paulo@0
|
249 /*
|
paulo@0
|
250 * First, we check if our owner tried to call ->free on us already.
|
paulo@0
|
251 * If so, we don't notify them because they already are well aware we are
|
paulo@0
|
252 * on our way to oblivion.
|
paulo@0
|
253 */
|
paulo@0
|
254 if (stack->free_delayed)
|
paulo@0
|
255 {
|
paulo@0
|
256 free_stack (stack);
|
paulo@0
|
257 return;
|
paulo@0
|
258 }
|
paulo@0
|
259
|
paulo@0
|
260 if (stack->aborted)
|
paulo@0
|
261 stack->cleanup (stack->udata);
|
paulo@0
|
262 }
|
paulo@0
|
263
|
paulo@0
|
264 void gt_rx_stack_recv_start (GtRxStack *stack)
|
paulo@0
|
265 {
|
paulo@0
|
266 assert (stack->depth >= 0);
|
paulo@0
|
267 stack->depth++;
|
paulo@0
|
268 }
|
paulo@0
|
269
|
paulo@0
|
270 void gt_rx_stack_recv_end (GtRxStack *stack)
|
paulo@0
|
271 {
|
paulo@0
|
272 assert (stack->depth > 0);
|
paulo@0
|
273
|
paulo@0
|
274 if (--stack->depth == 0)
|
paulo@0
|
275 cleanup_notify (stack);
|
paulo@0
|
276 }
|
paulo@0
|
277
|
paulo@0
|
278 /*
|
paulo@0
|
279 * RX layers call this function when something bad happens and they need
|
paulo@0
|
280 * to abort the stack processing.
|
paulo@0
|
281 *
|
paulo@0
|
282 * In other words, this is the "oh shit" function.
|
paulo@0
|
283 */
|
paulo@0
|
284 void gt_rx_stack_abort (GtRxStack *stack)
|
paulo@0
|
285 {
|
paulo@0
|
286 disable_all (stack);
|
paulo@0
|
287
|
paulo@0
|
288 /* set the flag indicated this stack has been aborted while processing */
|
paulo@0
|
289 stack->aborted = TRUE;
|
paulo@0
|
290
|
paulo@0
|
291 /*
|
paulo@0
|
292 * If we are in the middle of receiving some data, set stack->aborted
|
paulo@0
|
293 * so when the reception unwinds, we'll notify the owner of the
|
paulo@0
|
294 * stack's cleanup function.
|
paulo@0
|
295 */
|
paulo@0
|
296 if (stack->depth > 0)
|
paulo@0
|
297 return;
|
paulo@0
|
298
|
paulo@0
|
299 /*
|
paulo@0
|
300 * This can happen from the bottom layer, if it hasn't passed any data to
|
paulo@0
|
301 * upper layers yet. TODO: if the bottom layer was driven by the RX stack
|
paulo@0
|
302 * instead of rx_link, this wouldn't need to be here, i think..
|
paulo@0
|
303 */
|
paulo@0
|
304 cleanup_notify (stack);
|
paulo@0
|
305 }
|
paulo@0
|
306
|
paulo@0
|
307 void gt_rx_stack_set_handler (GtRxStack *stack, GtRxStackHandler handler,
|
paulo@0
|
308 GtRxStackCleanup cleanup, void *udata)
|
paulo@0
|
309 {
|
paulo@0
|
310 stack->udata = udata;
|
paulo@0
|
311 stack->handler = handler;
|
paulo@0
|
312 stack->cleanup = cleanup;
|
paulo@0
|
313
|
paulo@0
|
314 /*
|
paulo@0
|
315 * The topmost layer is rx_packet, so we can simply set the data.
|
paulo@0
|
316 */
|
paulo@0
|
317 gt_rx_packet_set_handler (stack->layers, handler, udata);
|
paulo@0
|
318 }
|