• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "lwip/opt.h"
44 #include "lwip/debug.h"
45 #include "lwip/stats.h"
46 #include "lwip/tcp.h"
47 #include "tcpecho_raw.h"
48 
49 #if LWIP_TCP && LWIP_CALLBACK_API
50 
51 static struct tcp_pcb *tcpecho_raw_pcb;
52 
53 enum tcpecho_raw_states
54 {
55   ES_NONE = 0,
56   ES_ACCEPTED,
57   ES_RECEIVED,
58   ES_CLOSING
59 };
60 
61 struct tcpecho_raw_state
62 {
63   u8_t state;
64   u8_t retries;
65   struct tcp_pcb *pcb;
66   /* pbuf (chain) to recycle */
67   struct pbuf *p;
68 };
69 
70 static void
tcpecho_raw_free(struct tcpecho_raw_state * es)71 tcpecho_raw_free(struct tcpecho_raw_state *es)
72 {
73   if (es != NULL) {
74     if (es->p) {
75       /* free the buffer chain if present */
76       pbuf_free(es->p);
77     }
78 
79     mem_free(es);
80   }
81 }
82 
83 static void
tcpecho_raw_close(struct tcp_pcb * tpcb,struct tcpecho_raw_state * es)84 tcpecho_raw_close(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es)
85 {
86   tcp_arg(tpcb, NULL);
87   tcp_sent(tpcb, NULL);
88   tcp_recv(tpcb, NULL);
89   tcp_err(tpcb, NULL);
90   tcp_poll(tpcb, NULL, 0);
91 
92   tcpecho_raw_free(es);
93 
94   tcp_close(tpcb);
95 }
96 
97 static void
tcpecho_raw_send(struct tcp_pcb * tpcb,struct tcpecho_raw_state * es)98 tcpecho_raw_send(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es)
99 {
100   struct pbuf *ptr;
101   err_t wr_err = ERR_OK;
102 
103   while ((wr_err == ERR_OK) &&
104          (es->p != NULL) &&
105          (es->p->len <= tcp_sndbuf(tpcb))) {
106     ptr = es->p;
107 
108     /* enqueue data for transmission */
109     wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
110     if (wr_err == ERR_OK) {
111       u16_t plen;
112 
113       plen = ptr->len;
114       /* continue with next pbuf in chain (if any) */
115       es->p = ptr->next;
116       if(es->p != NULL) {
117         /* new reference! */
118         pbuf_ref(es->p);
119       }
120       /* chop first pbuf from chain */
121       pbuf_free(ptr);
122       /* we can read more data now */
123       tcp_recved(tpcb, plen);
124     } else if(wr_err == ERR_MEM) {
125       /* we are low on memory, try later / harder, defer to poll */
126       es->p = ptr;
127     } else {
128       /* other problem ?? */
129     }
130   }
131 }
132 
133 static void
tcpecho_raw_error(void * arg,err_t err)134 tcpecho_raw_error(void *arg, err_t err)
135 {
136   struct tcpecho_raw_state *es;
137 
138   LWIP_UNUSED_ARG(err);
139 
140   es = (struct tcpecho_raw_state *)arg;
141 
142   tcpecho_raw_free(es);
143 }
144 
145 static err_t
tcpecho_raw_poll(void * arg,struct tcp_pcb * tpcb)146 tcpecho_raw_poll(void *arg, struct tcp_pcb *tpcb)
147 {
148   err_t ret_err;
149   struct tcpecho_raw_state *es;
150 
151   es = (struct tcpecho_raw_state *)arg;
152   if (es != NULL) {
153     if (es->p != NULL) {
154       /* there is a remaining pbuf (chain)  */
155       tcpecho_raw_send(tpcb, es);
156     } else {
157       /* no remaining pbuf (chain)  */
158       if(es->state == ES_CLOSING) {
159         tcpecho_raw_close(tpcb, es);
160       }
161     }
162     ret_err = ERR_OK;
163   } else {
164     /* nothing to be done */
165     tcp_abort(tpcb);
166     ret_err = ERR_ABRT;
167   }
168   return ret_err;
169 }
170 
171 static err_t
tcpecho_raw_sent(void * arg,struct tcp_pcb * tpcb,u16_t len)172 tcpecho_raw_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
173 {
174   struct tcpecho_raw_state *es;
175 
176   LWIP_UNUSED_ARG(len);
177 
178   es = (struct tcpecho_raw_state *)arg;
179   es->retries = 0;
180 
181   if(es->p != NULL) {
182     /* still got pbufs to send */
183     tcp_sent(tpcb, tcpecho_raw_sent);
184     tcpecho_raw_send(tpcb, es);
185   } else {
186     /* no more pbufs to send */
187     if(es->state == ES_CLOSING) {
188       tcpecho_raw_close(tpcb, es);
189     }
190   }
191   return ERR_OK;
192 }
193 
194 static err_t
tcpecho_raw_recv(void * arg,struct tcp_pcb * tpcb,struct pbuf * p,err_t err)195 tcpecho_raw_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
196 {
197   struct tcpecho_raw_state *es;
198   err_t ret_err;
199 
200   LWIP_ASSERT("arg != NULL",arg != NULL);
201   es = (struct tcpecho_raw_state *)arg;
202   if (p == NULL) {
203     /* remote host closed connection */
204     es->state = ES_CLOSING;
205     if(es->p == NULL) {
206       /* we're done sending, close it */
207       tcpecho_raw_close(tpcb, es);
208     } else {
209       /* we're not done yet */
210       tcpecho_raw_send(tpcb, es);
211     }
212     ret_err = ERR_OK;
213   } else if(err != ERR_OK) {
214     /* cleanup, for unknown reason */
215     LWIP_ASSERT("no pbuf expected here", p == NULL);
216     ret_err = err;
217   }
218   else if(es->state == ES_ACCEPTED) {
219     /* first data chunk in p->payload */
220     es->state = ES_RECEIVED;
221     /* store reference to incoming pbuf (chain) */
222     es->p = p;
223     tcpecho_raw_send(tpcb, es);
224     ret_err = ERR_OK;
225   } else if (es->state == ES_RECEIVED) {
226     /* read some more data */
227     if(es->p == NULL) {
228       es->p = p;
229       tcpecho_raw_send(tpcb, es);
230     } else {
231       struct pbuf *ptr;
232 
233       /* chain pbufs to the end of what we recv'ed previously  */
234       ptr = es->p;
235       pbuf_cat(ptr,p);
236     }
237     ret_err = ERR_OK;
238   } else {
239     /* unknown es->state, trash data  */
240     tcp_recved(tpcb, p->tot_len);
241     pbuf_free(p);
242     ret_err = ERR_OK;
243   }
244   return ret_err;
245 }
246 
247 static err_t
tcpecho_raw_accept(void * arg,struct tcp_pcb * newpcb,err_t err)248 tcpecho_raw_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
249 {
250   err_t ret_err;
251   struct tcpecho_raw_state *es;
252 
253   LWIP_UNUSED_ARG(arg);
254   if ((err != ERR_OK) || (newpcb == NULL)) {
255     return ERR_VAL;
256   }
257 
258   /* Unless this pcb should have NORMAL priority, set its priority now.
259      When running out of pcbs, low priority pcbs can be aborted to create
260      new pcbs of higher priority. */
261   tcp_setprio(newpcb, TCP_PRIO_MIN);
262 
263   es = (struct tcpecho_raw_state *)mem_malloc(sizeof(struct tcpecho_raw_state));
264   if (es != NULL) {
265     es->state = ES_ACCEPTED;
266     es->pcb = newpcb;
267     es->retries = 0;
268     es->p = NULL;
269     /* pass newly allocated es to our callbacks */
270     tcp_arg(newpcb, es);
271     tcp_recv(newpcb, tcpecho_raw_recv);
272     tcp_err(newpcb, tcpecho_raw_error);
273     tcp_poll(newpcb, tcpecho_raw_poll, 0);
274     tcp_sent(newpcb, tcpecho_raw_sent);
275     ret_err = ERR_OK;
276   } else {
277     ret_err = ERR_MEM;
278   }
279   return ret_err;
280 }
281 
282 void
tcpecho_raw_init(void)283 tcpecho_raw_init(void)
284 {
285   tcpecho_raw_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
286   if (tcpecho_raw_pcb != NULL) {
287     err_t err;
288 
289     err = tcp_bind(tcpecho_raw_pcb, IP_ANY_TYPE, 7);
290     if (err == ERR_OK) {
291       tcpecho_raw_pcb = tcp_listen(tcpecho_raw_pcb);
292       tcp_accept(tcpecho_raw_pcb, tcpecho_raw_accept);
293     } else {
294       /* abort? output diagnostic? */
295     }
296   } else {
297     /* abort? output diagnostic? */
298   }
299 }
300 
301 #endif /* LWIP_TCP && LWIP_CALLBACK_API */
302