Contiki-NG
Loading...
Searching...
No Matches
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 Contiki operating system.
30 *
31 * Author: Adam Dunkels <adam@sics.se>
32 *
33 */
34
35#include <string.h>
36
37#include "net/ipv6/psock.h"
38
39#define STATE_NONE 0
40#define STATE_ACKED 1
41#define STATE_READ 2
42#define STATE_BLOCKED_NEWDATA 3
43#define STATE_BLOCKED_CLOSE 4
44#define STATE_BLOCKED_SEND 5
45#define STATE_DATA_SENT 6
46
47/*
48 * Return value of the buffering functions that indicates that a
49 * buffer was not filled by incoming data.
50 *
51 */
52#define BUF_NOT_FULL 0
53#define BUF_NOT_FOUND 0
54
55/*
56 * Return value of the buffering functions that indicates that a
57 * buffer was completely filled by incoming data.
58 *
59 */
60#define BUF_FULL 1
61
62/*
63 * Return value of the buffering functions that indicates that an
64 * end-marker byte was found.
65 *
66 */
67#define BUF_FOUND 2
68
69/*---------------------------------------------------------------------------*/
70static void
71buf_setup(struct psock_buf *buf,
72 uint8_t *bufptr, uint16_t bufsize)
73{
74 buf->ptr = bufptr;
75 buf->left = bufsize;
76}
77/*---------------------------------------------------------------------------*/
78static uint8_t
79buf_bufdata(struct psock_buf *buf, uint16_t len,
80 uint8_t **dataptr, uint16_t *datalen)
81{
82 if(*datalen < buf->left) {
83 memcpy(buf->ptr, *dataptr, *datalen);
84 buf->ptr += *datalen;
85 buf->left -= *datalen;
86 *dataptr += *datalen;
87 *datalen = 0;
88 return BUF_NOT_FULL;
89 } else if(*datalen == buf->left) {
90 memcpy(buf->ptr, *dataptr, *datalen);
91 buf->ptr += *datalen;
92 buf->left = 0;
93 *dataptr += *datalen;
94 *datalen = 0;
95 return BUF_FULL;
96 } else {
97 memcpy(buf->ptr, *dataptr, buf->left);
98 buf->ptr += buf->left;
99 *datalen -= buf->left;
100 *dataptr += buf->left;
101 buf->left = 0;
102 return BUF_FULL;
103 }
104}
105/*---------------------------------------------------------------------------*/
106static uint8_t
107buf_bufto(struct psock_buf *buf, uint8_t endmarker,
108 uint8_t **dataptr, uint16_t *datalen)
109{
110 uint8_t c;
111 while(buf->left > 0 && *datalen > 0) {
112 c = *buf->ptr = **dataptr;
113 ++*dataptr;
114 ++buf->ptr;
115 --*datalen;
116 --buf->left;
117
118 if(c == endmarker) {
119 return BUF_FOUND;
120 }
121 }
122
123 if(*datalen == 0) {
124 return BUF_NOT_FOUND;
125 }
126
127 return BUF_FULL;
128}
129/*---------------------------------------------------------------------------*/
130static char
131data_is_sent_and_acked(struct psock *s)
132{
133 /* If data has previously been sent, and the data has been acked, we
134 increase the send pointer and call send_data() to send more
135 data. */
136 if(s->state != STATE_DATA_SENT || uip_rexmit()) {
137 if(s->sendlen > uip_mss()) {
138 uip_send(s->sendptr, uip_mss());
139 } else {
140 uip_send(s->sendptr, s->sendlen);
141 }
142 s->state = STATE_DATA_SENT;
143 return 0;
144 } else if(s->state == STATE_DATA_SENT && uip_acked()) {
145 if(s->sendlen > uip_mss()) {
146 s->sendlen -= uip_mss();
147 s->sendptr += uip_mss();
148 } else {
149 s->sendptr += s->sendlen;
150 s->sendlen = 0;
151 }
152 s->state = STATE_ACKED;
153 return 1;
154 }
155 return 0;
156}
157/*---------------------------------------------------------------------------*/
158PT_THREAD(psock_send(struct psock *s, const uint8_t *buf,
159 unsigned int len))
160{
161 PT_BEGIN(&s->psockpt);
162
163 /* If there is no data to send, we exit immediately. */
164 if(len == 0) {
165 PT_EXIT(&s->psockpt);
166 }
167
168 /* Save the length of and a pointer to the data that is to be
169 sent. */
170 s->sendptr = buf;
171 s->sendlen = len;
172
173 s->state = STATE_NONE;
174
175 /* We loop here until all data is sent. The s->sendlen variable is
176 updated by the data_sent() function. */
177 while(s->sendlen > 0) {
178
179 /*
180 * The protothread will wait here until all data has been
181 * acknowledged and sent (data_is_acked_and_send() returns 1).
182 */
183 PT_WAIT_UNTIL(&s->psockpt, data_is_sent_and_acked(s));
184 }
185
186 s->state = STATE_NONE;
187
188 PT_END(&s->psockpt);
189}
190/*---------------------------------------------------------------------------*/
191PT_THREAD(psock_generator_send(struct psock *s,
192 unsigned short (*generate)(void *), void *arg))
193{
194 PT_BEGIN(&s->psockpt);
195
196 /* Ensure that there is a generator function to call. */
197 if(generate == NULL) {
198 PT_EXIT(&s->psockpt);
199 }
200
201 s->state = STATE_NONE;
202 do {
203 /* Call the generator function to generate the data in the
204 uip_appdata buffer. */
205 s->sendlen = generate(arg);
206 s->sendptr = uip_appdata;
207
208 if(s->sendlen > uip_mss()) {
209 uip_send(s->sendptr, uip_mss());
210 } else {
211 uip_send(s->sendptr, s->sendlen);
212 }
213 s->state = STATE_DATA_SENT;
214
215 /* Wait until all data is sent and acknowledged. */
216 // if (!s->sendlen) break; //useful debugging aid
217 PT_YIELD_UNTIL(&s->psockpt, uip_acked() || uip_rexmit());
218 } while(!uip_acked());
219
220 s->state = STATE_NONE;
221
222 PT_END(&s->psockpt);
223}
224/*---------------------------------------------------------------------------*/
225uint16_t
226psock_datalen(struct psock *psock)
227{
228 return psock->bufsize - psock->buf.left;
229}
230/*---------------------------------------------------------------------------*/
231char
232psock_newdata(struct psock *s)
233{
234 if(s->readlen > 0) {
235 /* There is data in the uip_appdata buffer that has not yet been
236 read with the PSOCK_READ functions. */
237 return 1;
238 } else if(s->state == STATE_READ) {
239 /* All data in uip_appdata buffer already consumed. */
240 s->state = STATE_BLOCKED_NEWDATA;
241 return 0;
242 } else if(uip_newdata()) {
243 /* There is new data that has not been consumed. */
244 return 1;
245 } else {
246 /* There is no new data. */
247 return 0;
248 }
249}
250/*---------------------------------------------------------------------------*/
251PT_THREAD(psock_readto(struct psock *psock, unsigned char c))
252{
253 PT_BEGIN(&psock->psockpt);
254
255 buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
256
257 /* XXX: Should add buf_checkmarker() before do{} loop, if
258 incoming data has been handled while waiting for a write. */
259
260 do {
261 if(psock->readlen == 0) {
262 PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
263 psock->state = STATE_READ;
264 psock->readptr = (uint8_t *)uip_appdata;
265 psock->readlen = uip_datalen();
266 }
267 } while(buf_bufto(&psock->buf, c,
268 &psock->readptr,
269 &psock->readlen) == BUF_NOT_FOUND);
270
271 if(psock_datalen(psock) == 0) {
272 psock->state = STATE_NONE;
273 PT_RESTART(&psock->psockpt);
274 }
275 PT_END(&psock->psockpt);
276}
277/*---------------------------------------------------------------------------*/
278PT_THREAD(psock_readbuf_len(struct psock *psock, uint16_t len))
279{
280 PT_BEGIN(&psock->psockpt);
281
282 buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
283
284 /* XXX: Should add buf_checkmarker() before do{} loop, if
285 incoming data has been handled while waiting for a write. */
286
287 /* read len bytes or to end of data */
288 do {
289 if(psock->readlen == 0) {
290 PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
291 psock->state = STATE_READ;
292 psock->readptr = (uint8_t *)uip_appdata;
293 psock->readlen = uip_datalen();
294 }
295 } while(buf_bufdata(&psock->buf, psock->bufsize,
296 &psock->readptr, &psock->readlen) == BUF_NOT_FULL &&
297 psock_datalen(psock) < len);
298
299 if(psock_datalen(psock) == 0) {
300 psock->state = STATE_NONE;
301 PT_RESTART(&psock->psockpt);
302 }
303 PT_END(&psock->psockpt);
304}
305
306/*---------------------------------------------------------------------------*/
307void
308psock_init(struct psock *psock,
309 uint8_t *buffer, unsigned int buffersize)
310{
311 psock->state = STATE_NONE;
312 psock->readlen = 0;
313 psock->bufptr = buffer;
314 psock->bufsize = buffersize;
315 buf_setup(&psock->buf, buffer, buffersize);
316 PT_INIT(&psock->pt);
317 PT_INIT(&psock->psockpt);
318}
319/*---------------------------------------------------------------------------*/
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Definition pt.h:280
#define PT_THREAD(name_args)
Declaration of a protothread.
Definition pt.h:265
#define PT_END(pt)
Declare the end of a protothread.
Definition pt.h:292
#define PT_EXIT(pt)
Exit the protothread.
Definition pt.h:411
#define PT_WAIT_UNTIL(pt, condition)
Block and wait until condition is true.
Definition pt.h:313
#define PT_RESTART(pt)
Restart the protothread.
Definition pt.h:394
#define PT_YIELD_UNTIL(pt, cond)
Yield from the protothread until a condition occurs.
Definition pt.h:475
#define PT_INIT(pt)
Initialize a protothread.
Definition pt.h:245
void * uip_appdata
Pointer to the application data in the packet buffer.
Definition uip6.c:148
void uip_send(const void *data, int len)
Send data on the current connection.
Definition uip6.c:2353
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer.
Definition uip.h:593
#define uip_newdata()
Is new incoming data available?
Definition uip.h:680
#define uip_rexmit()
Do we need to retransmit previously data?
Definition uip.h:745
#define uip_mss()
Get the current maximum segment size that can be sent on the current connection.
Definition uip.h:780
#define uip_acked()
Has previously sent data been acknowledged?
Definition uip.h:691
Protosocket library header file.
The representation of a protosocket.
Definition psock.h:112