Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
comparison src/io/rx_packet.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:d3a1c2459d22 |
---|---|
1 /* | |
2 * $Id: rx_packet.c,v 1.7 2004/02/15 04:53:38 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 | |
19 #include "rx_stack.h" | |
20 #include "rx_layer.h" | |
21 | |
22 #include "gt_packet.h" | |
23 #include "rx_packet.h" | |
24 | |
25 /*****************************************************************************/ | |
26 | |
27 struct rx_packet | |
28 { | |
29 struct io_buf *partial; | |
30 rx_packet_handler_t handler; | |
31 void *udata; | |
32 }; | |
33 | |
34 /*****************************************************************************/ | |
35 | |
36 #define RX_PACKET(rx) \ | |
37 ((struct rx_packet *) ((rx)->udata)) | |
38 | |
39 /*****************************************************************************/ | |
40 | |
41 static void null_packet_handler (void *udata, GtPacket *packet) | |
42 { | |
43 gt_packet_free (packet); | |
44 } | |
45 | |
46 static BOOL rx_packet_init (struct rx_layer *rx, void *udata) | |
47 { | |
48 struct rx_packet *rx_packet; | |
49 | |
50 if (!(rx_packet = NEW (struct rx_packet))) | |
51 return FALSE; | |
52 | |
53 rx->udata = rx_packet; | |
54 | |
55 /* discard the packets received */ | |
56 rx_packet->handler = null_packet_handler; | |
57 return TRUE; | |
58 } | |
59 | |
60 static void rx_packet_destroy (struct rx_layer *rx) | |
61 { | |
62 struct rx_packet *rx_packet = RX_PACKET(rx); | |
63 | |
64 io_buf_free (rx_packet->partial); | |
65 FREE (rx_packet); | |
66 } | |
67 | |
68 static void rx_packet_disable (struct rx_layer *rx) | |
69 { | |
70 /* NOP: lower layer will stop sending us data -- it'd better | |
71 * stop now */ | |
72 } | |
73 | |
74 static void rx_packet_enable (struct rx_layer *rx) | |
75 { | |
76 /* NOP: the lower layer will start sending us data again */ | |
77 } | |
78 | |
79 /*****************************************************************************/ | |
80 | |
81 static GtPacket *make_packet (struct rx_layer *rx, struct rx_packet *rx_packet, | |
82 size_t packet_size) | |
83 { | |
84 GtPacket *packet; | |
85 struct io_buf *pbuf = rx_packet->partial; | |
86 | |
87 assert (io_buf_len (pbuf) == packet_size); | |
88 assert (packet_size < GT_PACKET_MAX); | |
89 | |
90 /* construct a complete packet from the data in the binary buf */ | |
91 packet = gt_packet_unserialize (pbuf->data, packet_size); | |
92 | |
93 /* | |
94 * TODO: gt_packet_unserialize() currently copies the data, but should | |
95 * really take ownership of the data in place. That would also allow the | |
96 * null terminator in the io_buf to terminate the last string in the | |
97 * packet, if any. | |
98 */ | |
99 io_buf_free (pbuf); | |
100 rx_packet->partial = NULL; | |
101 | |
102 if (!packet) | |
103 { | |
104 gt_rx_stack_abort (rx->stack); | |
105 return NULL; | |
106 } | |
107 | |
108 return packet; | |
109 } | |
110 | |
111 static BOOL fill_up_to (struct rx_layer *rx, struct io_buf *dst, | |
112 struct io_buf *src, size_t fill_size) | |
113 { | |
114 size_t new_len; | |
115 size_t old_len; | |
116 size_t len_to_read; | |
117 | |
118 old_len = io_buf_len (dst); | |
119 new_len = io_buf_len (src); | |
120 | |
121 /* skip if we already have enough */ | |
122 if (old_len >= fill_size) | |
123 return TRUE; | |
124 | |
125 len_to_read = MIN (fill_size - old_len, new_len); | |
126 | |
127 /* ensure the packet has enough room */ | |
128 if (!io_buf_resize (dst, old_len + len_to_read)) | |
129 { | |
130 gt_rx_stack_abort (rx->stack); | |
131 return FALSE; | |
132 } | |
133 | |
134 io_buf_copy (dst, src, len_to_read); | |
135 | |
136 if (io_buf_len (dst) >= fill_size) | |
137 return TRUE; | |
138 | |
139 return FALSE; | |
140 } | |
141 | |
142 static BOOL fill_header (struct rx_layer *rx, struct rx_packet *rx_packet, | |
143 struct io_buf *io_buf) | |
144 { | |
145 struct io_buf *dst = rx_packet->partial; | |
146 struct io_buf *src = io_buf; | |
147 | |
148 if (!fill_up_to (rx, dst, src, GNUTELLA_HDR_LEN)) | |
149 { | |
150 /* this would fail if there was an alloc failure */ | |
151 assert (io_buf_read_avail (io_buf) == 0); | |
152 return FALSE; | |
153 } | |
154 | |
155 return TRUE; | |
156 } | |
157 | |
158 /* | |
159 * We must read all the data the lower layer has sent and buffer | |
160 * partial packets, because otherwise we would poll the CPU if the | |
161 * packet were bigger than the buffer size of one of the layer | |
162 * layers under this one. | |
163 */ | |
164 static BOOL read_packet (struct rx_layer *rx, struct rx_packet *rx_packet, | |
165 struct io_buf *io_buf, GtPacket **ret) | |
166 { | |
167 uint32_t payload_len; | |
168 size_t partial_len; | |
169 uint32_t packet_size; | |
170 struct io_buf *partial = rx_packet->partial; | |
171 GtPacket *pkt; | |
172 | |
173 *ret = NULL; | |
174 | |
175 partial_len = io_buf_len (partial); | |
176 assert (partial_len >= GNUTELLA_HDR_LEN); | |
177 | |
178 /* | |
179 * The partial packet is now at least 23 bytes. Look in the header for | |
180 * the payload length so we know how much we need to read before the | |
181 * packet is complete. | |
182 */ | |
183 payload_len = get_payload_len (partial->data); | |
184 packet_size = payload_len + GNUTELLA_HDR_LEN; | |
185 | |
186 /* | |
187 * Check for wraparound, and reset the packet size to its payload len. | |
188 * Its likely we've experienced a protocol de-sync here. Set the size so | |
189 * the connection will be closed. | |
190 */ | |
191 if (packet_size < GNUTELLA_HDR_LEN) | |
192 packet_size = GT_PACKET_MAX; | |
193 | |
194 if (packet_size >= GT_PACKET_MAX) | |
195 { | |
196 if (IO_DEBUG) | |
197 GT->dbg (GT, "received too large packet(%d)", packet_size); | |
198 | |
199 /* TODO: should send a BYE message here */ | |
200 gt_rx_stack_abort (rx->stack); | |
201 return FALSE; | |
202 } | |
203 | |
204 if (!fill_up_to (rx, partial, io_buf, packet_size)) | |
205 { | |
206 /* this would fail if there was an alloc failure */ | |
207 assert (io_buf_read_avail (io_buf) == 0); | |
208 return FALSE; | |
209 } | |
210 | |
211 /* yay, read a packet */ | |
212 pkt = make_packet (rx, rx_packet, packet_size); | |
213 *ret = pkt; | |
214 | |
215 return (pkt == NULL ? FALSE : TRUE); | |
216 } | |
217 | |
218 /* | |
219 * Receive a message buffer from the lower layer, parse it into as many | |
220 * packets as it contains, and pass those to our handler function. | |
221 * | |
222 * This is meant to be the top layer of the rx stack only. | |
223 * | |
224 * TODO: A handler could be implemented as another layer, should think | |
225 * about this approach instead. | |
226 */ | |
227 static void rx_packet_recv (struct rx_layer *rx, struct io_buf *io_buf) | |
228 { | |
229 GtPacket *packet = NULL; | |
230 struct rx_packet *rx_packet; | |
231 | |
232 rx_packet = RX_PACKET(rx); | |
233 | |
234 while (rx->enabled && io_buf_read_avail (io_buf) > 0) | |
235 { | |
236 /* allocate a new partial buffer, if one is not present yet */ | |
237 if (!rx_packet->partial && | |
238 !(rx_packet->partial = io_buf_new (GNUTELLA_HDR_LEN))) | |
239 { | |
240 gt_rx_stack_abort (rx->stack); | |
241 break; | |
242 } | |
243 | |
244 /* try to read the first 23 bytes */ | |
245 if (!fill_header (rx, rx_packet, io_buf)) | |
246 break; | |
247 | |
248 /* | |
249 * Read the payload. If there arent enough bytes to complete the | |
250 * packet, we finish it later. | |
251 */ | |
252 if (!read_packet (rx, rx_packet, io_buf, &packet)) | |
253 { | |
254 assert (packet == NULL); | |
255 break; | |
256 } | |
257 | |
258 assert (packet != NULL); | |
259 (*rx_packet->handler) (rx_packet->udata, packet); | |
260 | |
261 /* freeing the packet here means the callback must make its own | |
262 * provisions for storing the packet's data */ | |
263 gt_packet_free (packet); | |
264 packet = NULL; | |
265 } | |
266 | |
267 io_buf_free (io_buf); | |
268 } | |
269 | |
270 /*****************************************************************************/ | |
271 | |
272 struct rx_layer_ops gt_rx_packet_ops = | |
273 { | |
274 rx_packet_init, | |
275 rx_packet_destroy, | |
276 rx_packet_enable, | |
277 rx_packet_disable, | |
278 rx_packet_recv, | |
279 }; | |
280 | |
281 void gt_rx_packet_set_handler (struct rx_layer *rx, | |
282 rx_packet_handler_t handler, | |
283 void *udata) | |
284 { | |
285 struct rx_packet *rx_packet = RX_PACKET(rx); | |
286 | |
287 rx_packet->handler = handler; | |
288 rx_packet->udata = udata; | |
289 } |