uc-sdk
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
echo.c
Go to the documentation of this file.
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 
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 */