]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_LPC1768_GCC_RedSuite/src/webserver/psock.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / CORTEX_LPC1768_GCC_RedSuite / src / webserver / psock.c
1 /*\r
2  * Copyright (c) 2004, Swedish Institute of Computer Science.\r
3  * All rights reserved.\r
4  *\r
5  * Redistribution and use in source and binary forms, with or without\r
6  * modification, are permitted provided that the following conditions\r
7  * are met:\r
8  * 1. Redistributions of source code must retain the above copyright\r
9  *    notice, this list of conditions and the following disclaimer.\r
10  * 2. Redistributions in binary form must reproduce the above copyright\r
11  *    notice, this list of conditions and the following disclaimer in the\r
12  *    documentation and/or other materials provided with the distribution.\r
13  * 3. Neither the name of the Institute nor the names of its contributors\r
14  *    may be used to endorse or promote products derived from this software\r
15  *    without specific prior written permission.\r
16  *\r
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND\r
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE\r
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
27  * SUCH DAMAGE.\r
28  *\r
29  * This file is part of the uIP TCP/IP stack\r
30  *\r
31  * Author: Adam Dunkels <adam@sics.se>\r
32  *\r
33  * $Id: psock.c,v 1.2 2006/06/12 08:00:30 adam Exp $\r
34  */\r
35 \r
36 #include <stdio.h>\r
37 #include <string.h>\r
38 \r
39 #include "uipopt.h"\r
40 #include "psock.h"\r
41 #include "uip.h"\r
42 \r
43 #define STATE_NONE 0\r
44 #define STATE_ACKED 1\r
45 #define STATE_READ 2\r
46 #define STATE_BLOCKED_NEWDATA 3\r
47 #define STATE_BLOCKED_CLOSE 4\r
48 #define STATE_BLOCKED_SEND 5\r
49 #define STATE_DATA_SENT 6\r
50 \r
51 /*\r
52  * Return value of the buffering functions that indicates that a\r
53  * buffer was not filled by incoming data.\r
54  *\r
55  */\r
56 #define BUF_NOT_FULL 0\r
57 #define BUF_NOT_FOUND 0\r
58 \r
59 /*\r
60  * Return value of the buffering functions that indicates that a\r
61  * buffer was completely filled by incoming data.\r
62  *\r
63  */\r
64 #define BUF_FULL 1\r
65 \r
66 /*\r
67  * Return value of the buffering functions that indicates that an\r
68  * end-marker byte was found.\r
69  *\r
70  */\r
71 #define BUF_FOUND 2\r
72 \r
73 /*---------------------------------------------------------------------------*/\r
74 static void\r
75 buf_setup(struct psock_buf *buf,\r
76           u8_t *bufptr, u16_t bufsize)\r
77 {\r
78   buf->ptr = bufptr;\r
79   buf->left = bufsize;\r
80 }\r
81 /*---------------------------------------------------------------------------*/\r
82 static u8_t\r
83 buf_bufdata(struct psock_buf *buf, u16_t len,\r
84             u8_t **dataptr, u16_t *datalen)\r
85 {\r
86   ( void ) len;\r
87   if(*datalen < buf->left) {\r
88     memcpy(buf->ptr, *dataptr, *datalen);\r
89     buf->ptr += *datalen;\r
90     buf->left -= *datalen;\r
91     *dataptr += *datalen;\r
92     *datalen = 0;\r
93     return BUF_NOT_FULL;\r
94   } else if(*datalen == buf->left) {\r
95     memcpy(buf->ptr, *dataptr, *datalen);\r
96     buf->ptr += *datalen;\r
97     buf->left = 0;\r
98     *dataptr += *datalen;\r
99     *datalen = 0;\r
100     return BUF_FULL;\r
101   } else {\r
102     memcpy(buf->ptr, *dataptr, buf->left);\r
103     buf->ptr += buf->left;\r
104     *datalen -= buf->left;\r
105     *dataptr += buf->left;\r
106     buf->left = 0;\r
107     return BUF_FULL;\r
108   }\r
109 }\r
110 /*---------------------------------------------------------------------------*/\r
111 static u8_t\r
112 buf_bufto(register struct psock_buf *buf, u8_t endmarker,\r
113           register u8_t **dataptr, register u16_t *datalen)\r
114 {\r
115   u8_t c;\r
116   while(buf->left > 0 && *datalen > 0) {\r
117     c = *buf->ptr = **dataptr;\r
118     ++*dataptr;\r
119     ++buf->ptr;\r
120     --*datalen;\r
121     --buf->left;\r
122     \r
123     if(c == endmarker) {\r
124       return BUF_FOUND;\r
125     }\r
126   }\r
127 \r
128   if(*datalen == 0) {\r
129     return BUF_NOT_FOUND;\r
130   }\r
131 \r
132   while(*datalen > 0) {\r
133     c = **dataptr;\r
134     --*datalen;\r
135     ++*dataptr;\r
136     \r
137     if(c == endmarker) {\r
138       return BUF_FOUND | BUF_FULL;\r
139     }\r
140   }\r
141   \r
142   return BUF_FULL;\r
143 }\r
144 /*---------------------------------------------------------------------------*/\r
145 static char\r
146 send_data(register struct psock *s)\r
147 {\r
148   if(s->state != STATE_DATA_SENT || uip_rexmit()) {\r
149     if(s->sendlen > uip_mss()) {\r
150       uip_send(s->sendptr, uip_mss());\r
151     } else {\r
152       uip_send(s->sendptr, s->sendlen);\r
153     }\r
154     s->state = STATE_DATA_SENT;\r
155     return 1;\r
156   }\r
157   return 0;\r
158 }\r
159 /*---------------------------------------------------------------------------*/\r
160 static char\r
161 data_acked(register struct psock *s)\r
162 {\r
163   if(s->state == STATE_DATA_SENT && uip_acked()) {\r
164     if(s->sendlen > uip_mss()) {\r
165       s->sendlen -= uip_mss();\r
166       s->sendptr += uip_mss();\r
167     } else {\r
168       s->sendptr += s->sendlen;\r
169       s->sendlen = 0;\r
170     }\r
171     s->state = STATE_ACKED;\r
172     return 1;\r
173   }\r
174   return 0;\r
175 }\r
176 /*---------------------------------------------------------------------------*/\r
177 PT_THREAD(psock_send(register struct psock *s, const char *buf,\r
178                      unsigned int len))\r
179 {\r
180   PT_BEGIN(&s->psockpt);\r
181 \r
182   /* If there is no data to send, we exit immediately. */\r
183   if(len == 0) {\r
184     PT_EXIT(&s->psockpt);\r
185   }\r
186 \r
187   /* Save the length of and a pointer to the data that is to be\r
188      sent. */\r
189   s->sendptr = (unsigned char*)buf;\r
190   s->sendlen = len;\r
191 \r
192   s->state = STATE_NONE;\r
193 \r
194   /* We loop here until all data is sent. The s->sendlen variable is\r
195      updated by the data_sent() function. */\r
196   while(s->sendlen > 0) {\r
197 \r
198     /*\r
199      * The condition for this PT_WAIT_UNTIL is a little tricky: the\r
200      * protothread will wait here until all data has been acknowledged\r
201      * (data_acked() returns true) and until all data has been sent\r
202      * (send_data() returns true). The two functions data_acked() and\r
203      * send_data() must be called in succession to ensure that all\r
204      * data is sent. Therefore the & operator is used instead of the\r
205      * && operator, which would cause only the data_acked() function\r
206      * to be called when it returns false.\r
207      */\r
208     PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));\r
209   }\r
210 \r
211   s->state = STATE_NONE;\r
212   \r
213   PT_END(&s->psockpt);\r
214 }\r
215 /*---------------------------------------------------------------------------*/\r
216 PT_THREAD(psock_generator_send(register struct psock *s,\r
217                                unsigned short (*generate)(void *), void *arg))\r
218 {\r
219   PT_BEGIN(&s->psockpt);\r
220 \r
221   /* Ensure that there is a generator function to call. */\r
222   if(generate == NULL) {\r
223     PT_EXIT(&s->psockpt);\r
224   }\r
225 \r
226   /* Call the generator function to generate the data in the\r
227      uip_appdata buffer. */\r
228   s->sendlen = generate(arg);\r
229   s->sendptr = uip_appdata;\r
230 \r
231   s->state = STATE_NONE;  \r
232   do {\r
233     /* Call the generator function again if we are called to perform a\r
234        retransmission. */\r
235     if(uip_rexmit()) {\r
236       generate(arg);\r
237     }\r
238     /* Wait until all data is sent and acknowledged. */\r
239     PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));\r
240   } while(s->sendlen > 0);\r
241   \r
242   s->state = STATE_NONE;\r
243   \r
244   PT_END(&s->psockpt);\r
245 }\r
246 /*---------------------------------------------------------------------------*/\r
247 u16_t\r
248 psock_datalen(struct psock *psock)\r
249 {\r
250   return psock->bufsize - psock->buf.left;\r
251 }\r
252 /*---------------------------------------------------------------------------*/\r
253 char\r
254 psock_newdata(struct psock *s)\r
255 {\r
256   if(s->readlen > 0) {\r
257     /* There is data in the uip_appdata buffer that has not yet been\r
258        read with the PSOCK_READ functions. */\r
259     return 1;\r
260   } else if(s->state == STATE_READ) {\r
261     /* All data in uip_appdata buffer already consumed. */\r
262     s->state = STATE_BLOCKED_NEWDATA;\r
263     return 0;\r
264   } else if(uip_newdata()) {\r
265     /* There is new data that has not been consumed. */\r
266     return 1;\r
267   } else {\r
268     /* There is no new data. */\r
269     return 0;\r
270   }\r
271 }\r
272 /*---------------------------------------------------------------------------*/\r
273 PT_THREAD(psock_readto(register struct psock *psock, unsigned char c))\r
274 {\r
275   PT_BEGIN(&psock->psockpt);\r
276 \r
277   buf_setup(&psock->buf, (unsigned char*)psock->bufptr, psock->bufsize);\r
278   \r
279   /* XXX: Should add buf_checkmarker() before do{} loop, if\r
280      incoming data has been handled while waiting for a write. */\r
281 \r
282   do {\r
283     if(psock->readlen == 0) {\r
284       PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));\r
285       psock->state = STATE_READ;\r
286       psock->readptr = (u8_t *)uip_appdata;\r
287       psock->readlen = uip_datalen();\r
288     }\r
289   } while((buf_bufto(&psock->buf, c,\r
290                      &psock->readptr,\r
291                      &psock->readlen) & BUF_FOUND) == 0);\r
292   \r
293   if(psock_datalen(psock) == 0) {\r
294     psock->state = STATE_NONE;\r
295     PT_RESTART(&psock->psockpt);\r
296   }\r
297   PT_END(&psock->psockpt);\r
298 }\r
299 /*---------------------------------------------------------------------------*/\r
300 PT_THREAD(psock_readbuf(register struct psock *psock))\r
301 {\r
302   PT_BEGIN(&psock->psockpt);\r
303 \r
304   buf_setup(&psock->buf, (unsigned char * ) psock->bufptr, psock->bufsize);\r
305   \r
306   /* XXX: Should add buf_checkmarker() before do{} loop, if\r
307      incoming data has been handled while waiting for a write. */\r
308 \r
309   do {\r
310     if(psock->readlen == 0) {\r
311       PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));\r
312       printf("Waited for newdata\n");\r
313       psock->state = STATE_READ;\r
314       psock->readptr = (u8_t *)uip_appdata;\r
315       psock->readlen = uip_datalen();\r
316     }\r
317   } while(buf_bufdata(&psock->buf, psock->bufsize,\r
318                          &psock->readptr,\r
319                          &psock->readlen) != BUF_FULL);\r
320 \r
321   if(psock_datalen(psock) == 0) {\r
322     psock->state = STATE_NONE;\r
323     PT_RESTART(&psock->psockpt);\r
324   }\r
325   PT_END(&psock->psockpt);\r
326 }\r
327 /*---------------------------------------------------------------------------*/\r
328 void\r
329 psock_init(register struct psock *psock, char *buffer, unsigned int buffersize)\r
330 {\r
331   psock->state = STATE_NONE;\r
332   psock->readlen = 0;\r
333   psock->bufptr = buffer;\r
334   psock->bufsize = buffersize;\r
335   buf_setup(&psock->buf, (unsigned char*) buffer, buffersize);\r
336   PT_INIT(&psock->pt);\r
337   PT_INIT(&psock->psockpt);\r
338 }\r
339 /*---------------------------------------------------------------------------*/\r