Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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