xref: /nrf52832-nimble/rt-thread/components/net/uip/uip/psock.c (revision 104654410c56c573564690304ae786df310c91fc)
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 <[email protected]>
32  *
33  * $Id: psock.c,v 1.2 2006/06/12 08:00:30 adam Exp $
34  */
35 
36 #include <stdio.h>
37 #include <string.h>
38 
39 #include "uipopt.h"
40 #include "psock.h"
41 #include "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
buf_setup(struct psock_buf * buf,u8_t * bufptr,u16_t bufsize)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
buf_bufdata(struct psock_buf * buf,u16_t len,u8_t ** dataptr,u16_t * datalen)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
buf_bufto(register struct psock_buf * buf,u8_t endmarker,register u8_t ** dataptr,register u16_t * datalen)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
send_data(register struct psock * s)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
data_acked(register struct psock * s)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 /*---------------------------------------------------------------------------*/
PT_THREAD(psock_send (register struct psock * s,const char * buf,unsigned int len))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 /*---------------------------------------------------------------------------*/
PT_THREAD(psock_generator_send (register struct psock * s,unsigned short (* generate)(void *),void * arg))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 =(const u8_t*) 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
psock_datalen(struct psock * psock)247 psock_datalen(struct psock *psock)
248 {
249   return psock->bufsize - psock->buf.left;
250 }
251 /*---------------------------------------------------------------------------*/
252 char
psock_newdata(struct psock * s)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 /*---------------------------------------------------------------------------*/
PT_THREAD(psock_readto (register struct psock * psock,unsigned char c))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 /*---------------------------------------------------------------------------*/
PT_THREAD(psock_readbuf (register struct psock * psock))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       printf("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
psock_init(register struct psock * psock,char * buffer,unsigned int buffersize)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 /*---------------------------------------------------------------------------*/
339