/[lwip]/contrib/ports/unix/proj/minimal/echo.c
ViewVC logotype

Diff of /contrib/ports/unix/proj/minimal/echo.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5

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