/[lwip]/contrib/apps/tcpecho_raw/echo.c
ViewVC logotype

Contents of /contrib/apps/tcpecho_raw/echo.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations) (download)
Fri Mar 26 16:10:33 2010 UTC (13 years, 8 months ago) by goldsimon
Branch: MAIN
CVS Tags: cvs-repository-moved-to-git, STABLE-1_4_0, STABLE-1_4_0-RC2, STABLE-1_4_0-RC1, HEAD
Changes since 1.2: +4 -0 lines
File MIME type: text/plain
Fixed compilation with LWIP_UDP/LWIP_TCP disabled

1 /*
2 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25 * OF SUCH DAMAGE.
26 *
27 * This file is part of and a contribution to the lwIP TCP/IP stack.
28 *
29 * Credits go to Adam Dunkels (and the current maintainers) of this software.
30 *
31 * Christiaan Simons rewrote this file to get a more stable echo example.
32 */
33
34 /**
35 * @file
36 * TCP echo server example using raw API.
37 *
38 * Echos all bytes sent by connecting client,
39 * and passively closes when client is done.
40 *
41 */
42
43
44 #include "lwip/debug.h"
45 #include "lwip/stats.h"
46 #include "lwip/tcp.h"
47
48 #if LWIP_TCP
49
50 static struct tcp_pcb *echo_pcb;
51
52 enum echo_states
53 {
54 ES_NONE = 0,
55 ES_ACCEPTED,
56 ES_RECEIVED,
57 ES_CLOSING
58 };
59
60 struct echo_state
61 {
62 u8_t state;
63 u8_t retries;
64 struct tcp_pcb *pcb;
65 /* pbuf (chain) to recycle */
66 struct pbuf *p;
67 };
68
69 err_t echo_accept(void *arg, struct tcp_pcb *newpcb, err_t err);
70 err_t echo_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
71 void echo_error(void *arg, err_t err);
72 err_t echo_poll(void *arg, struct tcp_pcb *tpcb);
73 err_t echo_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
74 void echo_send(struct tcp_pcb *tpcb, struct echo_state *es);
75 void echo_close(struct tcp_pcb *tpcb, struct echo_state *es);
76
77 void
78 echo_init(void)
79 {
80 echo_pcb = tcp_new();
81 if (echo_pcb != NULL)
82 {
83 err_t err;
84
85 err = tcp_bind(echo_pcb, IP_ADDR_ANY, 7);
86 if (err == ERR_OK)
87 {
88 echo_pcb = tcp_listen(echo_pcb);
89 tcp_accept(echo_pcb, echo_accept);
90 }
91 else
92 {
93 /* abort? output diagnostic? */
94 }
95 }
96 else
97 {
98 /* abort? output diagnostic? */
99 }
100 }
101
102
103 err_t
104 echo_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
105 {
106 err_t ret_err;
107 struct echo_state *es;
108
109 LWIP_UNUSED_ARG(arg);
110 LWIP_UNUSED_ARG(err);
111
112 /* commonly observed practive to call tcp_setprio(), why? */
113 tcp_setprio(newpcb, TCP_PRIO_MIN);
114
115 es = (struct echo_state *)mem_malloc(sizeof(struct echo_state));
116 if (es != NULL)
117 {
118 es->state = ES_ACCEPTED;
119 es->pcb = newpcb;
120 es->retries = 0;
121 es->p = NULL;
122 /* pass newly allocated es to our callbacks */
123 tcp_arg(newpcb, es);
124 tcp_recv(newpcb, echo_recv);
125 tcp_err(newpcb, echo_error);
126 tcp_poll(newpcb, echo_poll, 0);
127 ret_err = ERR_OK;
128 }
129 else
130 {
131 ret_err = ERR_MEM;
132 }
133 return ret_err;
134 }
135
136 err_t
137 echo_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
138 {
139 struct echo_state *es;
140 err_t ret_err;
141
142 LWIP_ASSERT("arg != NULL",arg != NULL);
143 es = (struct echo_state *)arg;
144 if (p == NULL)
145 {
146 /* remote host closed connection */
147 es->state = ES_CLOSING;
148 if(es->p == NULL)
149 {
150 /* we're done sending, close it */
151 echo_close(tpcb, es);
152 }
153 else
154 {
155 /* we're not done yet */
156 tcp_sent(tpcb, echo_sent);
157 echo_send(tpcb, es);
158 }
159 ret_err = ERR_OK;
160 }
161 else if(err != ERR_OK)
162 {
163 /* cleanup, for unkown reason */
164 if (p != NULL)
165 {
166 es->p = NULL;
167 pbuf_free(p);
168 }
169 ret_err = err;
170 }
171 else if(es->state == ES_ACCEPTED)
172 {
173 /* first data chunk in p->payload */
174 es->state = ES_RECEIVED;
175 /* store reference to incoming pbuf (chain) */
176 es->p = p;
177 /* install send completion notifier */
178 tcp_sent(tpcb, echo_sent);
179 echo_send(tpcb, es);
180 ret_err = ERR_OK;
181 }
182 else if (es->state == ES_RECEIVED)
183 {
184 /* read some more data */
185 if(es->p == NULL)
186 {
187 es->p = p;
188 tcp_sent(tpcb, echo_sent);
189 echo_send(tpcb, es);
190 }
191 else
192 {
193 struct pbuf *ptr;
194
195 /* chain pbufs to the end of what we recv'ed previously */
196 ptr = es->p;
197 pbuf_chain(ptr,p);
198 }
199 ret_err = ERR_OK;
200 }
201 else if(es->state == ES_CLOSING)
202 {
203 /* odd case, remote side closing twice, trash data */
204 tcp_recved(tpcb, p->tot_len);
205 es->p = NULL;
206 pbuf_free(p);
207 ret_err = ERR_OK;
208 }
209 else
210 {
211 /* unkown es->state, trash data */
212 tcp_recved(tpcb, p->tot_len);
213 es->p = NULL;
214 pbuf_free(p);
215 ret_err = ERR_OK;
216 }
217 return ret_err;
218 }
219
220 void
221 echo_error(void *arg, err_t err)
222 {
223 struct echo_state *es;
224
225 LWIP_UNUSED_ARG(err);
226
227 es = (struct echo_state *)arg;
228 if (es != NULL)
229 {
230 mem_free(es);
231 }
232 }
233
234 err_t
235 echo_poll(void *arg, struct tcp_pcb *tpcb)
236 {
237 err_t ret_err;
238 struct echo_state *es;
239
240 es = (struct echo_state *)arg;
241 if (es != NULL)
242 {
243 if (es->p != NULL)
244 {
245 /* there is a remaining pbuf (chain) */
246 tcp_sent(tpcb, echo_sent);
247 echo_send(tpcb, es);
248 }
249 else
250 {
251 /* no remaining pbuf (chain) */
252 if(es->state == ES_CLOSING)
253 {
254 echo_close(tpcb, es);
255 }
256 }
257 ret_err = ERR_OK;
258 }
259 else
260 {
261 /* nothing to be done */
262 tcp_abort(tpcb);
263 ret_err = ERR_ABRT;
264 }
265 return ret_err;
266 }
267
268 err_t
269 echo_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
270 {
271 struct echo_state *es;
272
273 LWIP_UNUSED_ARG(len);
274
275 es = (struct echo_state *)arg;
276 es->retries = 0;
277
278 if(es->p != NULL)
279 {
280 /* still got pbufs to send */
281 tcp_sent(tpcb, echo_sent);
282 echo_send(tpcb, es);
283 }
284 else
285 {
286 /* no more pbufs to send */
287 if(es->state == ES_CLOSING)
288 {
289 echo_close(tpcb, es);
290 }
291 }
292 return ERR_OK;
293 }
294
295 void
296 echo_send(struct tcp_pcb *tpcb, struct echo_state *es)
297 {
298 struct pbuf *ptr;
299 err_t wr_err = ERR_OK;
300
301 while ((wr_err == ERR_OK) &&
302 (es->p != NULL) &&
303 (es->p->len <= tcp_sndbuf(tpcb)))
304 {
305 ptr = es->p;
306
307 /* enqueue data for transmission */
308 wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
309 if (wr_err == ERR_OK)
310 {
311 u16_t plen;
312 u8_t freed;
313
314 plen = ptr->len;
315 /* continue with next pbuf in chain (if any) */
316 es->p = ptr->next;
317 if(es->p != NULL)
318 {
319 /* new reference! */
320 pbuf_ref(es->p);
321 }
322 /* chop first pbuf from chain */
323 do
324 {
325 /* try hard to free pbuf */
326 freed = pbuf_free(ptr);
327 }
328 while(freed == 0);
329 /* we can read more data now */
330 tcp_recved(tpcb, plen);
331 }
332 else if(wr_err == ERR_MEM)
333 {
334 /* we are low on memory, try later / harder, defer to poll */
335 es->p = ptr;
336 }
337 else
338 {
339 /* other problem ?? */
340 }
341 }
342 }
343
344 void
345 echo_close(struct tcp_pcb *tpcb, struct echo_state *es)
346 {
347 tcp_arg(tpcb, NULL);
348 tcp_sent(tpcb, NULL);
349 tcp_recv(tpcb, NULL);
350 tcp_err(tpcb, NULL);
351 tcp_poll(tpcb, NULL, 0);
352
353 if (es != NULL)
354 {
355 mem_free(es);
356 }
357 tcp_close(tpcb);
358 }
359
360 #endif /* LWIP_TCP */

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26