]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/uIP/uip-1.0/uip/psock.c
6b5920f787064f030b25703cb1550e70b413da22
[freertos] / Demo / Common / ethernet / uIP / uip-1.0 / uip / 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   if(*datalen < buf->left) {\r
87     memcpy(buf->ptr, *dataptr, *datalen);\r
88     buf->ptr += *datalen;\r
89     buf->left -= *datalen;\r
90     *dataptr += *datalen;\r
91     *datalen = 0;\r
92     return BUF_NOT_FULL;\r
93   } else if(*datalen == buf->left) {\r
94     memcpy(buf->ptr, *dataptr, *datalen);\r
95     buf->ptr += *datalen;\r
96     buf->left = 0;\r
97     *dataptr += *datalen;\r
98     *datalen = 0;\r
99     return BUF_FULL;\r
100   } else {\r
101     memcpy(buf->ptr, *dataptr, buf->left);\r
102     buf->ptr += buf->left;\r
103     *datalen -= buf->left;\r
104     *dataptr += buf->left;\r
105     buf->left = 0;\r
106     return BUF_FULL;\r
107   }\r
108 }\r
109 /*---------------------------------------------------------------------------*/\r
110 static u8_t\r
111 buf_bufto(register struct psock_buf *buf, u8_t endmarker,\r
112           register u8_t **dataptr, register u16_t *datalen)\r
113 {\r
114   u8_t c;\r
115   while(buf->left > 0 && *datalen > 0) {\r
116     c = *buf->ptr = **dataptr;\r
117     ++*dataptr;\r
118     ++buf->ptr;\r
119     --*datalen;\r
120     --buf->left;\r
121     \r
122     if(c == endmarker) {\r
123       return BUF_FOUND;\r
124     }\r
125   }\r
126 \r
127   if(*datalen == 0) {\r
128     return BUF_NOT_FOUND;\r
129   }\r
130 \r
131   while(*datalen > 0) {\r
132     c = **dataptr;\r
133     --*datalen;\r
134     ++*dataptr;\r
135     \r
136     if(c == endmarker) {\r
137       return BUF_FOUND | BUF_FULL;\r
138     }\r
139   }\r
140   \r
141   return BUF_FULL;\r
142 }\r
143 /*---------------------------------------------------------------------------*/\r
144 static char\r
145 send_data(register struct psock *s)\r
146 {\r
147   if(s->state != STATE_DATA_SENT || uip_rexmit()) {\r
148     if(s->sendlen > uip_mss()) {\r
149       uip_send(s->sendptr, uip_mss());\r
150     } else {\r
151       uip_send(s->sendptr, s->sendlen);\r
152     }\r
153     s->state = STATE_DATA_SENT;\r
154     return 1;\r
155   }\r
156   return 0;\r
157 }\r
158 /*---------------------------------------------------------------------------*/\r
159 static char\r
160 data_acked(register struct psock *s)\r
161 {\r
162   if(s->state == STATE_DATA_SENT && uip_acked()) {\r
163     if(s->sendlen > uip_mss()) {\r
164       s->sendlen -= uip_mss();\r
165       s->sendptr += uip_mss();\r
166     } else {\r
167       s->sendptr += s->sendlen;\r
168       s->sendlen = 0;\r
169     }\r
170     s->state = STATE_ACKED;\r
171     return 1;\r
172   }\r
173   return 0;\r
174 }\r
175 /*---------------------------------------------------------------------------*/\r
176 PT_THREAD(psock_send(register struct psock *s, const char *buf,\r
177                      unsigned int len))\r
178 {\r
179   PT_BEGIN(&s->psockpt);\r
180 \r
181   /* If there is no data to send, we exit immediately. */\r
182   if(len == 0) {\r
183     PT_EXIT(&s->psockpt);\r
184   }\r
185 \r
186   /* Save the length of and a pointer to the data that is to be\r
187      sent. */\r
188   s->sendptr = buf;\r
189   s->sendlen = len;\r
190 \r
191   s->state = STATE_NONE;\r
192 \r
193   /* We loop here until all data is sent. The s->sendlen variable is\r
194      updated by the data_sent() function. */\r
195   while(s->sendlen > 0) {\r
196 \r
197     /*\r
198      * The condition for this PT_WAIT_UNTIL is a little tricky: the\r
199      * protothread will wait here until all data has been acknowledged\r
200      * (data_acked() returns true) and until all data has been sent\r
201      * (send_data() returns true). The two functions data_acked() and\r
202      * send_data() must be called in succession to ensure that all\r
203      * data is sent. Therefore the & operator is used instead of the\r
204      * && operator, which would cause only the data_acked() function\r
205      * to be called when it returns false.\r
206      */\r
207     PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));\r
208   }\r
209 \r
210   s->state = STATE_NONE;\r
211   \r
212   PT_END(&s->psockpt);\r
213 }\r
214 /*---------------------------------------------------------------------------*/\r
215 PT_THREAD(psock_generator_send(register struct psock *s,\r
216                                unsigned short (*generate)(void *), void *arg))\r
217 {\r
218   PT_BEGIN(&s->psockpt);\r
219 \r
220   /* Ensure that there is a generator function to call. */\r
221   if(generate == NULL) {\r
222     PT_EXIT(&s->psockpt);\r
223   }\r
224 \r
225   /* Call the generator function to generate the data in the\r
226      uip_appdata buffer. */\r
227   s->sendlen = generate(arg);\r
228   s->sendptr = uip_appdata;\r
229 \r
230   s->state = STATE_NONE;  \r
231   do {\r
232     /* Call the generator function again if we are called to perform a\r
233        retransmission. */\r
234     if(uip_rexmit()) {\r
235       generate(arg);\r
236     }\r
237     /* Wait until all data is sent and acknowledged. */\r
238     PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));\r
239   } while(s->sendlen > 0);\r
240   \r
241   s->state = STATE_NONE;\r
242   \r
243   PT_END(&s->psockpt);\r
244 }\r
245 /*---------------------------------------------------------------------------*/\r
246 u16_t\r
247 psock_datalen(struct psock *psock)\r
248 {\r
249   return psock->bufsize - psock->buf.left;\r
250 }\r
251 /*---------------------------------------------------------------------------*/\r
252 char\r
253 psock_newdata(struct psock *s)\r
254 {\r
255   if(s->readlen > 0) {\r
256     /* There is data in the uip_appdata buffer that has not yet been\r
257        read with the PSOCK_READ functions. */\r
258     return 1;\r
259   } else if(s->state == STATE_READ) {\r
260     /* All data in uip_appdata buffer already consumed. */\r
261     s->state = STATE_BLOCKED_NEWDATA;\r
262     return 0;\r
263   } else if(uip_newdata()) {\r
264     /* There is new data that has not been consumed. */\r
265     return 1;\r
266   } else {\r
267     /* There is no new data. */\r
268     return 0;\r
269   }\r
270 }\r
271 /*---------------------------------------------------------------------------*/\r
272 PT_THREAD(psock_readto(register struct psock *psock, unsigned char c))\r
273 {\r
274   PT_BEGIN(&psock->psockpt);\r
275 \r
276   buf_setup(&psock->buf, psock->bufptr, psock->bufsize);\r
277   \r
278   /* XXX: Should add buf_checkmarker() before do{} loop, if\r
279      incoming data has been handled while waiting for a write. */\r
280 \r
281   do {\r
282     if(psock->readlen == 0) {\r
283       PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));\r
284       psock->state = STATE_READ;\r
285       psock->readptr = (u8_t *)uip_appdata;\r
286       psock->readlen = uip_datalen();\r
287     }\r
288   } while((buf_bufto(&psock->buf, c,\r
289                      &psock->readptr,\r
290                      &psock->readlen) & BUF_FOUND) == 0);\r
291   \r
292   if(psock_datalen(psock) == 0) {\r
293     psock->state = STATE_NONE;\r
294     PT_RESTART(&psock->psockpt);\r
295   }\r
296   PT_END(&psock->psockpt);\r
297 }\r
298 /*---------------------------------------------------------------------------*/\r
299 PT_THREAD(psock_readbuf(register struct psock *psock))\r
300 {\r
301   PT_BEGIN(&psock->psockpt);\r
302 \r
303   buf_setup(&psock->buf, psock->bufptr, psock->bufsize);\r
304   \r
305   /* XXX: Should add buf_checkmarker() before do{} loop, if\r
306      incoming data has been handled while waiting for a write. */\r
307 \r
308   do {\r
309     if(psock->readlen == 0) {\r
310       PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));\r
311       printf("Waited for newdata\n");\r
312       psock->state = STATE_READ;\r
313       psock->readptr = (u8_t *)uip_appdata;\r
314       psock->readlen = uip_datalen();\r
315     }\r
316   } while(buf_bufdata(&psock->buf, psock->bufsize,\r
317                          &psock->readptr,\r
318                          &psock->readlen) != BUF_FULL);\r
319 \r
320   if(psock_datalen(psock) == 0) {\r
321     psock->state = STATE_NONE;\r
322     PT_RESTART(&psock->psockpt);\r
323   }\r
324   PT_END(&psock->psockpt);\r
325 }\r
326 /*---------------------------------------------------------------------------*/\r
327 void\r
328 psock_init(register struct psock *psock, char *buffer, unsigned int buffersize)\r
329 {\r
330   psock->state = STATE_NONE;\r
331   psock->readlen = 0;\r
332   psock->bufptr = buffer;\r
333   psock->bufsize = buffersize;\r
334   buf_setup(&psock->buf, buffer, buffersize);\r
335   PT_INIT(&psock->pt);\r
336   PT_INIT(&psock->psockpt);\r
337 }\r
338 /*---------------------------------------------------------------------------*/\r