Contiki-NG
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 /*---------------------------------------------------------------------------*/
70 static void
71 buf_setup(struct psock_buf *buf,
72  uint8_t *bufptr, uint16_t bufsize)
73 {
74  buf->ptr = bufptr;
75  buf->left = bufsize;
76 }
77 /*---------------------------------------------------------------------------*/
78 static uint8_t
79 buf_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 /*---------------------------------------------------------------------------*/
106 static uint8_t
107 buf_bufto(CC_REGISTER_ARG struct psock_buf *buf, uint8_t endmarker,
108  CC_REGISTER_ARG uint8_t **dataptr, CC_REGISTER_ARG 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 /*---------------------------------------------------------------------------*/
130 static char
131 data_is_sent_and_acked(CC_REGISTER_ARG 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 /*---------------------------------------------------------------------------*/
158 PT_THREAD(psock_send(CC_REGISTER_ARG 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 /*---------------------------------------------------------------------------*/
191 PT_THREAD(psock_generator_send(CC_REGISTER_ARG 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 /*---------------------------------------------------------------------------*/
225 uint16_t
226 psock_datalen(struct psock *psock)
227 {
228  return psock->bufsize - psock->buf.left;
229 }
230 /*---------------------------------------------------------------------------*/
231 char
232 psock_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 /*---------------------------------------------------------------------------*/
251 PT_THREAD(psock_readto(CC_REGISTER_ARG 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 /*---------------------------------------------------------------------------*/
278 PT_THREAD(psock_readbuf_len(CC_REGISTER_ARG 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 /*---------------------------------------------------------------------------*/
307 void
308 psock_init(CC_REGISTER_ARG 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 uip_mss()
Get the current maximum segment size that can be sent on the current connection.
Definition: uip.h:829
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Definition: pt.h:114
#define PT_WAIT_UNTIL(pt, condition)
Block and wait until condition is true.
Definition: pt.h:147
The representation of a protosocket.
Definition: psock.h:112
#define CC_REGISTER_ARG
Configure if the C compiler supports the "register" keyword for function arguments.
Definition: cc.h:58
#define PT_YIELD_UNTIL(pt, cond)
Yield from the protothread until a condition occurs.
Definition: pt.h:309
#define PT_RESTART(pt)
Restart the protothread.
Definition: pt.h:228
#define PT_INIT(pt)
Initialize a protothread.
Definition: pt.h:79
#define PT_END(pt)
Declare the end of a protothread.
Definition: pt.h:126
#define uip_newdata()
Is new incoming data available?
Definition: uip.h:729
Protosocket library header file.
#define PT_EXIT(pt)
Exit the protothread.
Definition: pt.h:245
#define PT_THREAD(name_args)
Declaration of a protothread.
Definition: pt.h:99
#define uip_acked()
Has previously sent data been acknowledged?
Definition: uip.h:740
void uip_send(const void *data, int len)
Send data on the current connection.
Definition: uip6.c:2336
#define uip_rexmit()
Do we need to retransmit previously data?
Definition: uip.h:794
void * uip_appdata
Pointer to the application data in the packet buffer.
Definition: uip6.c:168
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer...
Definition: uip.h:642