uIP 1.0 based webserver for LPC1114 + ENC28J60

Dependencies:   mbed TMP102

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers psock.c Source File

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