LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
iperf_server.c
Go to the documentation of this file.
1 #include "lwip/debug.h"
2 #include "lwip/stats.h"
3 #include "lwip/tcp.h"
4 
5 /*---------------------------------------------------------------------------*/
6 /* local defines */
7 /*---------------------------------------------------------------------------*/
8 #define IPERF_SERVER_PORT 5001
9 
10 /*---------------------------------------------------------------------------*/
11 /* local data */
12 /*---------------------------------------------------------------------------*/
13 #if LWIP_TCP
14 
15 static struct tcp_pcb *iperf_pcb;
16 
17 enum iperfserver_states
18 {
19  ES_NONE = 0,
20  ES_ACCEPTED,
21  ES_RECEIVED,
22  ES_CLOSING
23 };
24 
25 struct iperfserver_state
26 {
27  u8_t state;
28  u8_t retries;
29  struct tcp_pcb *pcb;
30  /* pbuf (chain) to recycle */
31  struct pbuf *p;
32 };
33 
34 /*---------------------------------------------------------------------------*/
35 /* local functions */
36 /*---------------------------------------------------------------------------*/
37 static err_t iperfserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err);
38 static err_t iperfserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
39 static void iperfserver_error(void *arg, err_t err);
40 static err_t iperfserver_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
41 static void iperfserver_send(struct tcp_pcb *tpcb, struct iperfserver_state *es);
42 static void iperfserver_close(struct tcp_pcb *tpcb, struct iperfserver_state *es);
43 
44 void
45 iperf_server_init(void)
46 {
47  iperf_pcb = tcp_new();
48  if (iperf_pcb != NULL)
49  {
50  err_t err;
51 
52  err = tcp_bind(iperf_pcb, IP_ADDR_ANY, IPERF_SERVER_PORT);
53  if (err == ERR_OK)
54  {
55  iperf_pcb = tcp_listen(iperf_pcb);
56  tcp_accept(iperf_pcb, iperfserver_accept);
57  }
58  else
59  {
60  /* abort? output diagnostic? */
61  }
62  }
63  else
64  {
65  /* abort? output diagnostic? */
66  }
67 }
68 
69 
70 err_t
71 iperfserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
72 {
73  err_t ret_err;
74  struct iperfserver_state *es;
75 
76  LWIP_UNUSED_ARG(arg);
77  LWIP_UNUSED_ARG(err);
78 
79  /* commonly observed practive to call tcp_setprio(), why? */
80  tcp_setprio(newpcb, TCP_PRIO_MIN);
81 
82  es = (struct iperfserver_state *)mem_malloc(sizeof(struct iperfserver_state));
83  if (es != NULL)
84  {
85  es->state = ES_ACCEPTED;
86  es->pcb = newpcb;
87  es->retries = 0;
88  es->p = NULL;
89  /* pass newly allocated es to our callbacks */
90  tcp_arg(newpcb, es);
91  tcp_recv(newpcb, iperfserver_recv);
92  tcp_err(newpcb, iperfserver_error);
93 
94  ret_err = ERR_OK;
95  }
96  else
97  {
98  ret_err = ERR_MEM;
99  }
100  return ret_err;
101 }
102 
103 err_t
104 iperfserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
105 {
106  struct iperfserver_state *es;
107  err_t ret_err;
108  u16_t plen;
109 
110  LWIP_ASSERT("arg != NULL",arg != NULL);
111  es = (struct iperfserver_state *)arg;
112  if (p == NULL)
113  {
114  /* remote host closed connection */
115  es->state = ES_CLOSING;
116  iperfserver_close(tpcb, es);
117  ret_err = ERR_OK;
118  }
119  else if(err != ERR_OK)
120  {
121  /* cleanup, for unkown reason */
122  if (p != NULL)
123  {
124  es->p = NULL;
125  pbuf_free(p);
126  }
127  ret_err = err;
128  }
129  else if(es->state == ES_ACCEPTED)
130  {
131  es->p = p;
132  plen = es->p->len;
133  pbuf_free(es->p); //receive the package and discard it silently for testing reception bandwidth
134  tcp_recved(tpcb, plen);
135 
136  ret_err = ERR_OK;
137  }
138  else if(es->state == ES_CLOSING)
139  {
140  /* odd case, remote side closing twice, trash data */
141  tcp_recved(tpcb, p->tot_len);
142  es->p = NULL;
143  pbuf_free(p);
144  ret_err = ERR_OK;
145  }
146  else
147  {
148  /* unkown es->state, trash data */
149  tcp_recved(tpcb, p->tot_len);
150  es->p = NULL;
151  pbuf_free(p);
152  ret_err = ERR_OK;
153  }
154  return ret_err;
155 }
156 
157 void
158 iperfserver_error(void *arg, err_t err)
159 {
160  struct iperfserver_state *es;
161 
162  LWIP_UNUSED_ARG(err);
163 
164  es = (struct iperfserver_state *)arg;
165  if (es != NULL)
166  {
167  mem_free(es);
168  }
169 }
170 
171 err_t
172 iperfserver_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
173 {
174  struct iperfserver_state *es;
175 
176  LWIP_UNUSED_ARG(len);
177 
178  es = (struct iperfserver_state *)arg;
179  es->retries = 0;
180 
181  if(es->p != NULL)
182  {
183  /* still got pbufs to send */
184  tcp_sent(tpcb, iperfserver_sent);
185  iperfserver_send(tpcb, es);
186  }
187  else
188  {
189  /* no more pbufs to send */
190  if(es->state == ES_CLOSING)
191  {
192  iperfserver_close(tpcb, es);
193  }
194  }
195  return ERR_OK;
196 }
197 
198 void
199 iperfserver_send(struct tcp_pcb *tpcb, struct iperfserver_state *es)
200 {
201  struct pbuf *ptr;
202  err_t wr_err = ERR_OK;
203 
204  while ((wr_err == ERR_OK) &&
205  (es->p != NULL) &&
206  (es->p->len <= tcp_sndbuf(tpcb)))
207  {
208  ptr = es->p;
209 
210  /* enqueue data for transmission */
211  wr_err = tcp_write(tpcb, ptr->payload, ptr->len, TCP_WRITE_FLAG_COPY);
212  if (wr_err == ERR_OK)
213  {
214  u16_t plen;
215  u8_t freed;
216 
217  plen = ptr->len;
218  /* continue with next pbuf in chain (if any) */
219  es->p = ptr->next;
220  if(es->p != NULL)
221  {
222  /* new reference! */
223  pbuf_ref(es->p);
224  }
225  /* chop first pbuf from chain */
226  do
227  {
228  /* try hard to free pbuf */
229  freed = pbuf_free(ptr);
230  }
231  while(freed == 0);
232  /* we can read more data now */
233  tcp_recved(tpcb, plen);
234  }
235  else if(wr_err == ERR_MEM)
236  {
237  /* we are low on memory, try later / harder, defer to poll */
238  es->p = ptr;
239  }
240  else
241  {
242  /* other problem ?? */
243  }
244  }
245 }
246 
247 void
248 iperfserver_close(struct tcp_pcb *tpcb, struct iperfserver_state *es)
249 {
250  tcp_arg(tpcb, NULL);
251  tcp_sent(tpcb, NULL);
252  tcp_recv(tpcb, NULL);
253  tcp_err(tpcb, NULL);
254 
255 
256  if (es != NULL)
257  {
258  mem_free(es);
259  }
260  tcp_close(tpcb);
261 }
262 
263 #endif /* LWIP_TCP */
264 /*****************************************************************************/
265 /* END OF FILE */
266