Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Examples

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.1 2006/06/17 22:41:18 adamdunkels Exp $
00034  */
00035 
00036 #include <stdio.h>
00037 #include <string.h>
00038 
00039 #include "net/psock.h"
00040 
00041 #define STATE_NONE 0
00042 #define STATE_ACKED 1
00043 #define STATE_READ 2
00044 #define STATE_BLOCKED_NEWDATA 3
00045 #define STATE_BLOCKED_CLOSE 4
00046 #define STATE_BLOCKED_SEND 5
00047 #define STATE_DATA_SENT 6
00048 
00049 /*
00050  * Return value of the buffering functions that indicates that a
00051  * buffer was not filled by incoming data.
00052  *
00053  */
00054 #define BUF_NOT_FULL 0
00055 #define BUF_NOT_FOUND 0
00056 
00057 /*
00058  * Return value of the buffering functions that indicates that a
00059  * buffer was completely filled by incoming data.
00060  *
00061  */
00062 #define BUF_FULL 1
00063 
00064 /*
00065  * Return value of the buffering functions that indicates that an
00066  * end-marker byte was found.
00067  *
00068  */
00069 #define BUF_FOUND 2
00070 
00071 /*---------------------------------------------------------------------------*/
00072 static void
00073 buf_setup(struct psock_buf *buf,
00074           u8_t *bufptr, u16_t bufsize)
00075 {
00076   buf->ptr = bufptr;
00077   buf->left = bufsize;
00078 }
00079 /*---------------------------------------------------------------------------*/
00080 static u8_t
00081 buf_bufdata(struct psock_buf *buf, u16_t len,
00082             u8_t **dataptr, u16_t *datalen)
00083 {
00084   if(*datalen < buf->left) {
00085     memcpy(buf->ptr, *dataptr, *datalen);
00086     buf->ptr += *datalen;
00087     buf->left -= *datalen;
00088     *dataptr += *datalen;
00089     *datalen = 0;
00090     return BUF_NOT_FULL;
00091   } else if(*datalen == buf->left) {
00092     memcpy(buf->ptr, *dataptr, *datalen);
00093     buf->ptr += *datalen;
00094     buf->left = 0;
00095     *dataptr += *datalen;
00096     *datalen = 0;
00097     return BUF_FULL;
00098   } else {
00099     memcpy(buf->ptr, *dataptr, buf->left);
00100     buf->ptr += buf->left;
00101     *datalen -= buf->left;
00102     *dataptr += buf->left;
00103     buf->left = 0;
00104     return BUF_FULL;
00105   }
00106 }
00107 /*---------------------------------------------------------------------------*/
00108 static u8_t
00109 buf_bufto(register struct psock_buf *buf, u8_t endmarker,
00110           register u8_t **dataptr, register u16_t *datalen)
00111 {
00112   u8_t c;
00113   while(buf->left > 0 && *datalen > 0) {
00114     c = *buf->ptr = **dataptr;
00115     ++*dataptr;
00116     ++buf->ptr;
00117     --*datalen;
00118     --buf->left;
00119     
00120     if(c == endmarker) {
00121       return BUF_FOUND;
00122     }
00123   }
00124 
00125   if(*datalen == 0) {
00126     return BUF_NOT_FOUND;
00127   }
00128 
00129   while(*datalen > 0) {
00130     c = **dataptr;
00131     --*datalen;
00132     ++*dataptr;
00133     
00134     if(c == endmarker) {
00135       return BUF_FOUND | BUF_FULL;
00136     }
00137   }
00138   
00139   return BUF_FULL;
00140 }
00141 /*---------------------------------------------------------------------------*/
00142 static char
00143 send_data(register struct psock *s)
00144 {
00145   if(s->state != STATE_DATA_SENT || uip_rexmit()) {
00146     if(s->sendlen > uip_mss()) {
00147       uip_send(s->sendptr, uip_mss());
00148     } else {
00149       uip_send(s->sendptr, s->sendlen);
00150     }
00151     s->state = STATE_DATA_SENT;
00152     return 1;
00153   }
00154   return 0;
00155 }
00156 /*---------------------------------------------------------------------------*/
00157 static char
00158 data_acked(register struct psock *s)
00159 {
00160   if(s->state == STATE_DATA_SENT && uip_acked()) {
00161     if(s->sendlen > uip_mss()) {
00162       s->sendlen -= uip_mss();
00163       s->sendptr += uip_mss();
00164     } else {
00165       s->sendptr += s->sendlen;
00166       s->sendlen = 0;
00167     }
00168     s->state = STATE_ACKED;
00169     return 1;
00170   }
00171   return 0;
00172 }
00173 /*---------------------------------------------------------------------------*/
00174 PT_THREAD(psock_send(register struct psock *s, const char *buf,
00175                      unsigned int len))
00176 {
00177   PT_BEGIN(&s->psockpt);
00178 
00179   /* If there is no data to send, we exit immediately. */
00180   if(len == 0) {
00181     PT_EXIT(&s->psockpt);
00182   }
00183 
00184   /* Save the length of and a pointer to the data that is to be
00185      sent. */
00186   s->sendptr = buf;
00187   s->sendlen = len;
00188 
00189   s->state = STATE_NONE;
00190 
00191   /* We loop here until all data is sent. The s->sendlen variable is
00192      updated by the data_sent() function. */
00193   while(s->sendlen > 0) {
00194 
00195     /*
00196      * The condition for this PT_WAIT_UNTIL is a little tricky: the
00197      * protothread will wait here until all data has been acknowledged
00198      * (data_acked() returns true) and until all data has been sent
00199      * (send_data() returns true). The two functions data_acked() and
00200      * send_data() must be called in succession to ensure that all
00201      * data is sent. Therefore the & operator is used instead of the
00202      * && operator, which would cause only the data_acked() function
00203      * to be called when it returns false.
00204      */
00205     PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
00206   }
00207 
00208   s->state = STATE_NONE;
00209   
00210   PT_END(&s->psockpt);
00211 }
00212 /*---------------------------------------------------------------------------*/
00213 PT_THREAD(psock_generator_send(register struct psock *s,
00214                                unsigned short (*generate)(void *), void *arg))
00215 {
00216   PT_BEGIN(&s->psockpt);
00217 
00218   /* Ensure that there is a generator function to call. */
00219   if(generate == NULL) {
00220     PT_EXIT(&s->psockpt);
00221   }
00222 
00223   /* Call the generator function to generate the data in the
00224      uip_appdata buffer. */
00225   s->sendlen = generate(arg);
00226   s->sendptr = uip_appdata;
00227 
00228   s->state = STATE_NONE;  
00229   do {
00230     /* Call the generator function again if we are called to perform a
00231        retransmission. */
00232     if(uip_rexmit()) {
00233       generate(arg);
00234     }
00235     /* Wait until all data is sent and acknowledged. */
00236     PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
00237   } while(s->sendlen > 0);
00238   
00239   s->state = STATE_NONE;
00240   
00241   PT_END(&s->psockpt);
00242 }
00243 /*---------------------------------------------------------------------------*/
00244 u16_t
00245 psock_datalen(struct psock *psock)
00246 {
00247   return psock->bufsize - psock->buf.left;
00248 }
00249 /*---------------------------------------------------------------------------*/
00250 char
00251 psock_newdata(struct psock *s)
00252 {
00253   if(s->readlen > 0) {
00254     /* There is data in the uip_appdata buffer that has not yet been
00255        read with the PSOCK_READ functions. */
00256     return 1;
00257   } else if(s->state == STATE_READ) {
00258     /* All data in uip_appdata buffer already consumed. */
00259     s->state = STATE_BLOCKED_NEWDATA;
00260     return 0;
00261   } else if(uip_newdata()) {
00262     /* There is new data that has not been consumed. */
00263     return 1;
00264   } else {
00265     /* There is no new data. */
00266     return 0;
00267   }
00268 }
00269 /*---------------------------------------------------------------------------*/
00270 PT_THREAD(psock_readto(register struct psock *psock, unsigned char c))
00271 {
00272   PT_BEGIN(&psock->psockpt);
00273 
00274   buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
00275   
00276   /* XXX: Should add buf_checkmarker() before do{} loop, if
00277      incoming data has been handled while waiting for a write. */
00278 
00279   do {
00280     if(psock->readlen == 0) {
00281       PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
00282       psock->state = STATE_READ;
00283       psock->readptr = (u8_t *)uip_appdata;
00284       psock->readlen = uip_datalen();
00285     }
00286   } while((buf_bufto(&psock->buf, c,
00287                      &psock->readptr,
00288                      &psock->readlen) & BUF_FOUND) == 0);
00289   
00290   if(psock_datalen(psock) == 0) {
00291     psock->state = STATE_NONE;
00292     PT_RESTART(&psock->psockpt);
00293   }
00294   PT_END(&psock->psockpt);
00295 }
00296 /*---------------------------------------------------------------------------*/
00297 PT_THREAD(psock_readbuf(register struct psock *psock))
00298 {
00299   PT_BEGIN(&psock->psockpt);
00300 
00301   buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
00302   
00303   /* XXX: Should add buf_checkmarker() before do{} loop, if
00304      incoming data has been handled while waiting for a write. */
00305 
00306   do {
00307     if(psock->readlen == 0) {
00308       PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
00309       printf("Waited for newdata\n");
00310       psock->state = STATE_READ;
00311       psock->readptr = (u8_t *)uip_appdata;
00312       psock->readlen = uip_datalen();
00313     }
00314   } while(buf_bufdata(&psock->buf, psock->bufsize,
00315                          &psock->readptr,
00316                          &psock->readlen) != BUF_FULL);
00317 
00318   if(psock_datalen(psock) == 0) {
00319     psock->state = STATE_NONE;
00320     PT_RESTART(&psock->psockpt);
00321   }
00322   PT_END(&psock->psockpt);
00323 }
00324 /*---------------------------------------------------------------------------*/
00325 void
00326 psock_init(register struct psock *psock, char *buffer, unsigned int buffersize)
00327 {
00328   psock->state = STATE_NONE;
00329   psock->readlen = 0;
00330   psock->bufptr = buffer;
00331   psock->bufsize = buffersize;
00332   buf_setup(&psock->buf, buffer, buffersize);
00333   PT_INIT(&psock->pt);
00334   PT_INIT(&psock->psockpt);
00335 }
00336 /*---------------------------------------------------------------------------*/

Generated on Thu Jun 22 17:45:42 2006 for Contiki 2.x by  doxygen 1.4.4