psock.c

00001 /*
00002  * Copyright (c) 2004, Swedish Institute of Computer Science.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  *
00031  * Author: Adam Dunkels <adam@sics.se>
00032  *
00033  * $Id: psock.c,v 1.12 2010/06/15 14:19:22 nifi Exp $
00034  */
00035 
00036 #include <string.h>
00037 
00038 #include "net/psock.h"
00039 
00040 #define STATE_NONE 0
00041 #define STATE_ACKED 1
00042 #define STATE_READ 2
00043 #define STATE_BLOCKED_NEWDATA 3
00044 #define STATE_BLOCKED_CLOSE 4
00045 #define STATE_BLOCKED_SEND 5
00046 #define STATE_DATA_SENT 6
00047 
00048 /*
00049  * Return value of the buffering functions that indicates that a
00050  * buffer was not filled by incoming data.
00051  *
00052  */
00053 #define BUF_NOT_FULL 0
00054 #define BUF_NOT_FOUND 0
00055 
00056 /*
00057  * Return value of the buffering functions that indicates that a
00058  * buffer was completely filled by incoming data.
00059  *
00060  */
00061 #define BUF_FULL 1
00062 
00063 /*
00064  * Return value of the buffering functions that indicates that an
00065  * end-marker byte was found.
00066  *
00067  */
00068 #define BUF_FOUND 2
00069 
00070 /*---------------------------------------------------------------------------*/
00071 static void
00072 buf_setup(struct psock_buf *buf,
00073           u8_t *bufptr, u16_t bufsize)
00074 {
00075   buf->ptr = bufptr;
00076   buf->left = bufsize;
00077 }
00078 /*---------------------------------------------------------------------------*/
00079 static u8_t
00080 buf_bufdata(struct psock_buf *buf, u16_t len,
00081             u8_t **dataptr, u16_t *datalen)
00082 {
00083   if(*datalen < buf->left) {
00084     memcpy(buf->ptr, *dataptr, *datalen);
00085     buf->ptr += *datalen;
00086     buf->left -= *datalen;
00087     *dataptr += *datalen;
00088     *datalen = 0;
00089     return BUF_NOT_FULL;
00090   } else if(*datalen == buf->left) {
00091     memcpy(buf->ptr, *dataptr, *datalen);
00092     buf->ptr += *datalen;
00093     buf->left = 0;
00094     *dataptr += *datalen;
00095     *datalen = 0;
00096     return BUF_FULL;
00097   } else {
00098     memcpy(buf->ptr, *dataptr, buf->left);
00099     buf->ptr += buf->left;
00100     *datalen -= buf->left;
00101     *dataptr += buf->left;
00102     buf->left = 0;
00103     return BUF_FULL;
00104   }
00105 }
00106 /*---------------------------------------------------------------------------*/
00107 static u8_t
00108 buf_bufto(CC_REGISTER_ARG struct psock_buf *buf, u8_t endmarker,
00109           CC_REGISTER_ARG u8_t **dataptr, CC_REGISTER_ARG u16_t *datalen)
00110 {
00111   u8_t c;
00112   while(buf->left > 0 && *datalen > 0) {
00113     c = *buf->ptr = **dataptr;
00114     ++*dataptr;
00115     ++buf->ptr;
00116     --*datalen;
00117     --buf->left;
00118     
00119     if(c == endmarker) {
00120       return BUF_FOUND;
00121     }
00122   }
00123 
00124   if(*datalen == 0) {
00125     return BUF_NOT_FOUND;
00126   }
00127 
00128   while(*datalen > 0) {
00129     c = **dataptr;
00130     --*datalen;
00131     ++*dataptr;
00132     
00133     if(c == endmarker) {
00134       return BUF_FOUND | BUF_FULL;
00135     }
00136   }
00137   
00138   return BUF_FULL;
00139 }
00140 /*---------------------------------------------------------------------------*/
00141 static char
00142 data_is_sent_and_acked(CC_REGISTER_ARG struct psock *s)
00143 {
00144   /* If data has previously been sent, and the data has been acked, we
00145      increase the send pointer and call send_data() to send more
00146      data. */
00147   if(s->state != STATE_DATA_SENT || uip_rexmit()) {
00148     if(s->sendlen > uip_mss()) {
00149       uip_send(s->sendptr, uip_mss());
00150     } else {
00151       uip_send(s->sendptr, s->sendlen);
00152     }
00153     s->state = STATE_DATA_SENT;
00154     return 0;
00155   } else if(s->state == STATE_DATA_SENT && uip_acked()) {
00156     if(s->sendlen > uip_mss()) {
00157       s->sendlen -= uip_mss();
00158       s->sendptr += uip_mss();
00159     } else {
00160       s->sendptr += s->sendlen;
00161       s->sendlen = 0;
00162     }
00163     s->state = STATE_ACKED;
00164     return 1;
00165   }
00166   return 0;
00167 }
00168 /*---------------------------------------------------------------------------*/
00169 PT_THREAD(psock_send(CC_REGISTER_ARG struct psock *s, const uint8_t *buf,
00170                      unsigned int len))
00171 {
00172   PT_BEGIN(&s->psockpt);
00173 
00174   /* If there is no data to send, we exit immediately. */
00175   if(len == 0) {
00176     PT_EXIT(&s->psockpt);
00177   }
00178 
00179   /* Save the length of and a pointer to the data that is to be
00180      sent. */
00181   s->sendptr = buf;
00182   s->sendlen = len;
00183 
00184   s->state = STATE_NONE;
00185 
00186   /* We loop here until all data is sent. The s->sendlen variable is
00187      updated by the data_sent() function. */
00188   while(s->sendlen > 0) {
00189 
00190     /*
00191      * The protothread will wait here until all data has been
00192      * acknowledged and sent (data_is_acked_and_send() returns 1).
00193      */
00194     PT_WAIT_UNTIL(&s->psockpt, data_is_sent_and_acked(s));
00195   }
00196 
00197   s->state = STATE_NONE;
00198   
00199   PT_END(&s->psockpt);
00200 }
00201 /*---------------------------------------------------------------------------*/
00202 PT_THREAD(psock_generator_send(CC_REGISTER_ARG struct psock *s,
00203                                unsigned short (*generate)(void *), void *arg))
00204 {
00205   PT_BEGIN(&s->psockpt);
00206 
00207   /* Ensure that there is a generator function to call. */
00208   if(generate == NULL) {
00209     PT_EXIT(&s->psockpt);
00210   }
00211 
00212   s->state = STATE_NONE;
00213   do {
00214     /* Call the generator function to generate the data in the
00215      uip_appdata buffer. */
00216     s->sendlen = generate(arg);
00217     s->sendptr = uip_appdata;
00218     
00219     if(s->sendlen > uip_mss()) {
00220       uip_send(s->sendptr, uip_mss());
00221     } else {
00222       uip_send(s->sendptr, s->sendlen);
00223     }
00224     s->state = STATE_DATA_SENT;
00225 
00226     /* Wait until all data is sent and acknowledged. */
00227  // if (!s->sendlen) break;   //useful debugging aid
00228     PT_YIELD_UNTIL(&s->psockpt, uip_acked() || uip_rexmit());
00229   } while(!uip_acked());
00230   
00231   s->state = STATE_NONE;
00232   
00233   PT_END(&s->psockpt);
00234 }
00235 /*---------------------------------------------------------------------------*/
00236 u16_t
00237 psock_datalen(struct psock *psock)
00238 {
00239   return psock->bufsize - psock->buf.left;
00240 }
00241 /*---------------------------------------------------------------------------*/
00242 char
00243 psock_newdata(struct psock *s)
00244 {
00245   if(s->readlen > 0) {
00246     /* There is data in the uip_appdata buffer that has not yet been
00247        read with the PSOCK_READ functions. */
00248     return 1;
00249   } else if(s->state == STATE_READ) {
00250     /* All data in uip_appdata buffer already consumed. */
00251     s->state = STATE_BLOCKED_NEWDATA;
00252     return 0;
00253   } else if(uip_newdata()) {
00254     /* There is new data that has not been consumed. */
00255     return 1;
00256   } else {
00257     /* There is no new data. */
00258     return 0;
00259   }
00260 }
00261 /*---------------------------------------------------------------------------*/
00262 PT_THREAD(psock_readto(CC_REGISTER_ARG struct psock *psock, unsigned char c))
00263 {
00264   PT_BEGIN(&psock->psockpt);
00265 
00266   buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
00267   
00268   /* XXX: Should add buf_checkmarker() before do{} loop, if
00269      incoming data has been handled while waiting for a write. */
00270 
00271   do {
00272     if(psock->readlen == 0) {
00273       PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
00274       psock->state = STATE_READ;
00275       psock->readptr = (u8_t *)uip_appdata;
00276       psock->readlen = uip_datalen();
00277     }
00278   } while((buf_bufto(&psock->buf, c,
00279                      &psock->readptr,
00280                      &psock->readlen) & BUF_FOUND) == 0);
00281   
00282   if(psock_datalen(psock) == 0) {
00283     psock->state = STATE_NONE;
00284     PT_RESTART(&psock->psockpt);
00285   }
00286   PT_END(&psock->psockpt);
00287 }
00288 /*---------------------------------------------------------------------------*/
00289 PT_THREAD(psock_readbuf_len(CC_REGISTER_ARG struct psock *psock, uint16_t len))
00290 {
00291   PT_BEGIN(&psock->psockpt);
00292 
00293   buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
00294 
00295   /* XXX: Should add buf_checkmarker() before do{} loop, if
00296      incoming data has been handled while waiting for a write. */
00297   
00298   /* read len bytes or to end of data */
00299   do {
00300     if(psock->readlen == 0) {
00301       PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
00302       psock->state = STATE_READ;
00303       psock->readptr = (u8_t *)uip_appdata;
00304       psock->readlen = uip_datalen();
00305     }
00306   } while(buf_bufdata(&psock->buf, psock->bufsize,
00307                       &psock->readptr, &psock->readlen) == BUF_NOT_FULL &&
00308           psock_datalen(psock) < len);
00309   
00310   if(psock_datalen(psock) == 0) {
00311     psock->state = STATE_NONE;
00312     PT_RESTART(&psock->psockpt);
00313   }
00314   PT_END(&psock->psockpt);
00315 }
00316 
00317 /*---------------------------------------------------------------------------*/
00318 void
00319 psock_init(CC_REGISTER_ARG struct psock *psock,
00320            uint8_t *buffer, unsigned int buffersize)
00321 {
00322   psock->state = STATE_NONE;
00323   psock->readlen = 0;
00324   psock->bufptr = buffer;
00325   psock->bufsize = buffersize;
00326   buf_setup(&psock->buf, buffer, buffersize);
00327   PT_INIT(&psock->pt);
00328   PT_INIT(&psock->psockpt);
00329 }
00330 /*---------------------------------------------------------------------------*/

Generated on Mon Apr 11 14:23:30 2011 for Contiki 2.5 by  doxygen 1.6.1