Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:59901de07748 |
---|---|
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 */ | |
16 | |
17 #include "gt_gnutella.h" | |
18 #include "gt_packet.h" /* gt_packet_log XXX */ | |
19 | |
20 #include "io/tx_stack.h" | |
21 #include "io/tx_layer.h" | |
22 #include "io/io_buf.h" | |
23 | |
24 /*****************************************************************************/ | |
25 | |
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; | |
29 | |
30 /*****************************************************************************/ | |
31 | |
32 static struct use_tx_layer | |
33 { | |
34 const char *name; | |
35 struct tx_layer_ops *ops; | |
36 } tx_layers[] = | |
37 { | |
38 { "tx_link", >_tx_link_ops, }, | |
39 { "tx_deflate", >_tx_deflate_ops }, | |
40 { "tx_packet", >_tx_packet_ops }, | |
41 }; | |
42 | |
43 /*****************************************************************************/ | |
44 | |
45 static void foreach_tx_child (struct tx_layer *tx, | |
46 void (*exec) (struct tx_layer *tx)) | |
47 { | |
48 struct tx_layer *next; | |
49 | |
50 while (tx != NULL) | |
51 { | |
52 /* grab the next element first so the callback can call free */ | |
53 next = tx->lower; | |
54 | |
55 exec (tx); | |
56 | |
57 tx = next; | |
58 } | |
59 } | |
60 | |
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; | |
66 | |
67 if (below) | |
68 below->upper = above; | |
69 | |
70 return above; | |
71 } | |
72 | |
73 static void destroy_tx (struct tx_layer *tx) | |
74 { | |
75 gt_tx_layer_free (tx); | |
76 } | |
77 | |
78 static void disable_tx (struct tx_layer *tx) | |
79 { | |
80 gt_tx_layer_disable (tx); | |
81 } | |
82 | |
83 static void disable_all_tx_layers (struct tx_layer *layers) | |
84 { | |
85 if (!layers) | |
86 return; | |
87 | |
88 assert (layers->upper == NULL); | |
89 | |
90 foreach_tx_child (layers, disable_tx); | |
91 } | |
92 | |
93 static void free_all_tx_layers (struct tx_layer *layers) | |
94 { | |
95 if (!layers) | |
96 return; | |
97 | |
98 disable_all_tx_layers (layers); | |
99 foreach_tx_child (layers, destroy_tx); | |
100 } | |
101 | |
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; | |
107 | |
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; | |
112 | |
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 } | |
119 | |
120 layer = tx_push_layer (layer, new_layer); | |
121 } | |
122 | |
123 return layer; | |
124 } | |
125 | |
126 GtTxStack *gt_tx_stack_new (TCPC *c, BOOL tx_deflated) | |
127 { | |
128 struct gt_tx_stack *stack; | |
129 int size; | |
130 | |
131 if (!(stack = NEW (struct gt_tx_stack))) | |
132 return NULL; | |
133 | |
134 if (!(stack->layers = alloc_tx_layers (stack, tx_deflated))) | |
135 { | |
136 free (stack); | |
137 return NULL; | |
138 } | |
139 | |
140 /* set the send buffer to a not too high value */ | |
141 size = 256; | |
142 | |
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()); | |
145 | |
146 stack->c = c; | |
147 stack->start_time = time (NULL); | |
148 | |
149 return stack; | |
150 } | |
151 | |
152 /*****************************************************************************/ | |
153 | |
154 void gt_tx_stack_free (GtTxStack *stack) | |
155 { | |
156 if (!stack) | |
157 return; | |
158 | |
159 free_all_tx_layers (stack->layers); | |
160 FREE (stack); | |
161 } | |
162 | |
163 void gt_tx_stack_abort (GtTxStack *stack) | |
164 { | |
165 stack->cleanup (stack, stack->udata); | |
166 } | |
167 | |
168 /*****************************************************************************/ | |
169 | |
170 static void activate_tx (struct tx_layer *tx) | |
171 { | |
172 tx->ops->toggle (tx, FALSE); | |
173 } | |
174 | |
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 } | |
183 | |
184 static void deactivate_tx (struct tx_layer *tx) | |
185 { | |
186 tx->ops->toggle (tx, TRUE); | |
187 } | |
188 | |
189 void gt_tx_stack_deactivate (GtTxStack *stack) | |
190 { | |
191 foreach_tx_child (stack->layers, deactivate_tx); | |
192 } | |
193 | |
194 /*****************************************************************************/ | |
195 | |
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; | |
203 | |
204 if (!(io_buf = io_buf_new (len))) | |
205 return FALSE; | |
206 | |
207 ptr = io_buf_write_ptr (io_buf); | |
208 | |
209 memcpy (ptr, data, len); | |
210 io_buf_push (io_buf, len); | |
211 | |
212 tx = stack->layers; | |
213 | |
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 } | |
221 | |
222 pkt.data = (unsigned char *)data; | |
223 pkt.len = len; | |
224 | |
225 gt_packet_log (&pkt, stack->c, TRUE); | |
226 | |
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); | |
233 | |
234 return TRUE; | |
235 } | |
236 | |
237 int gt_tx_stack_send (GtTxStack *stack, const uint8_t *data, size_t len) | |
238 { | |
239 int ret; | |
240 | |
241 /* check if the file descriptor has an error */ | |
242 if (net_sock_error (stack->c->fd)) | |
243 return -1; | |
244 | |
245 ret = tcp_send (stack->c, (unsigned char *)data, len); | |
246 | |
247 return ret; | |
248 } | |
249 | |
250 void gt_tx_stack_set_handler (GtTxStack *stack, GtTxStackCleanup cleanup, | |
251 void *udata) | |
252 { | |
253 stack->cleanup = cleanup; | |
254 stack->udata = udata; | |
255 } |