First version of the AVR port
diff --git a/contiki-avr/apps/webclient.c b/contiki-avr/apps/webclient.c
new file mode 100644
index 0000000..eac5400
--- /dev/null
+++ b/contiki-avr/apps/webclient.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "contiki" web browser.
+ *
+ * $Id: webclient.c,v 1.1 2003/07/04 10:54:51 adamdunkels Exp $
+ *
+ */
+
+#include "uip.h"
+#include "webclient.h"
+#include "resolv.h"
+#include "uip_main.h"
+
+#include <string.h>
+
+#define WEBCLIENT_TIMEOUT 100
+
+#define WEBCLIENT_STATE_STATUSLINE 0
+#define WEBCLIENT_STATE_HEADERS 1
+#define WEBCLIENT_STATE_DATA 2
+#define WEBCLIENT_STATE_CLOSE 3
+
+#define HTTPFLAG_NONE 0
+#define HTTPFLAG_OK 1
+#define HTTPFLAG_MOVED 2
+#define HTTPFLAG_ERROR 3
+
+
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+#define ISO_space 0x20
+
+struct webclient_state {
+ u8_t timer;
+ u8_t state;
+ u8_t httpflag;
+
+ u16_t port;
+ char host[40];
+ char file[100];
+ u16_t getrequestptr;
+ u16_t getrequestleft;
+
+ char httpheaderline[200];
+ u16_t httpheaderlineptr;
+
+ char mimetype[32];
+};
+
+static struct webclient_state s;
+
+/*-----------------------------------------------------------------------------------*/
+char *
+webclient_mimetype(void)
+{
+ return s.mimetype;
+}
+/*-----------------------------------------------------------------------------------*/
+char *
+webclient_filename(void)
+{
+ return s.file;
+}
+/*-----------------------------------------------------------------------------------*/
+char *
+webclient_hostname(void)
+{
+ return s.host;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned short
+webclient_port(void)
+{
+ return s.port;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+webclient_init(void)
+{
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+init_connection(void)
+{
+ s.state = WEBCLIENT_STATE_STATUSLINE;
+
+ s.getrequestleft = sizeof(http_get) - 1 + 1 +
+ sizeof(http_10) - 1 +
+ sizeof(http_crnl) - 1 +
+ sizeof(http_host) - 1 +
+ sizeof(http_crnl) - 1 +
+ strlen(http_user_agent_fields) +
+ strlen(s.file) + strlen(s.host);
+ s.getrequestptr = 0;
+
+ s.httpheaderlineptr = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+webclient_close(void)
+{
+ s.state = WEBCLIENT_STATE_CLOSE;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+webclient_get(char *host, u16_t port, char *file)
+{
+ struct uip_conn *conn;
+ u16_t *ipaddr;
+ u16_t addr[2];
+
+ /* First check if the host is an IP address. */
+ ipaddr = &addr[0];
+ if(uip_main_ipaddrconv(host, (unsigned char *)addr) == 0) {
+ ipaddr = resolv_lookup(host);
+
+ if(ipaddr == NULL) {
+ return 0;
+ }
+ }
+
+ /* XXX: here we check so that the server does not try to access any
+ hosts on the SICS networks. */
+ if(ipaddr[0] == HTONS((193 << 8) | 10) &&
+ ((htons(ipaddr[1]) >> 8) == 66 ||
+ (htons(ipaddr[1]) >> 8) == 67)) {
+ return 0;
+ } else {
+ conn = uip_connect(ipaddr, port);
+ }
+
+ if(conn == NULL) {
+ return 0;
+ }
+
+ dispatcher_markconn(conn, NULL);
+
+ s.port = port;
+ strncpy(s.file, file, sizeof(s.file));
+ strncpy(s.host, host, sizeof(s.host));
+
+ init_connection();
+ return 1;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char *
+copy_string(unsigned char *dest, unsigned char *src, unsigned char len)
+{
+ return strcpy(dest, src) + len;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+senddata(void)
+{
+ u16_t len;
+ char *getrequest;
+ char *cptr;
+
+ if(s.getrequestleft > 0) {
+ cptr = getrequest = (char *)uip_appdata;
+
+ cptr = copy_string(cptr, http_get, sizeof(http_get) - 1);
+ cptr = copy_string(cptr, s.file, strlen(s.file));
+ *cptr++ = ISO_space;
+ cptr = copy_string(cptr, http_10, sizeof(http_10) - 1);
+
+ cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1);
+
+ cptr = copy_string(cptr, http_host, sizeof(http_host) - 1);
+ cptr = copy_string(cptr, s.host, strlen(s.host));
+ cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1);
+
+ cptr = copy_string(cptr, http_user_agent_fields,
+ strlen(http_user_agent_fields));
+
+ len = s.getrequestleft > uip_mss()?
+ uip_mss():
+ s.getrequestleft;
+ uip_send(&(getrequest[s.getrequestptr]), len);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+acked(void)
+{
+ u16_t len;
+
+ if(s.getrequestleft > 0) {
+ len = s.getrequestleft > uip_mss()?
+ uip_mss():
+ s.getrequestleft;
+ s.getrequestleft -= len;
+ s.getrequestptr += len;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static u16_t
+parse_statusline(u16_t len)
+{
+ char *cptr;
+
+ while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) {
+ s.httpheaderline[s.httpheaderlineptr] = *uip_appdata;
+ ++uip_appdata;
+ --len;
+ if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) {
+
+ if((strncmp(s.httpheaderline, http_10,
+ sizeof(http_10) - 1) == 0) ||
+ (strncmp(s.httpheaderline, http_11,
+ sizeof(http_11) - 1) == 0)) {
+ cptr = &(s.httpheaderline[9]);
+ s.httpflag = HTTPFLAG_NONE;
+ if(strncmp(cptr, http_200, sizeof(http_200) - 1) == 0) {
+ /* 200 OK */
+ s.httpflag = HTTPFLAG_OK;
+ } else if(strncmp(cptr, http_301, sizeof(http_301) - 1) == 0 ||
+ strncmp(cptr, http_302, sizeof(http_302) - 1) == 0) {
+ /* 301 Moved permanently or 302 Found. Location: header line
+ will contain thw new location. */
+ s.httpflag = HTTPFLAG_MOVED;
+ } else {
+ s.httpheaderline[s.httpheaderlineptr - 1] = 0;
+ }
+ } else {
+ uip_abort();
+ webclient_aborted();
+ return 0;
+ }
+
+ /* We're done parsing the status line, so we reset the pointer
+ and start parsing the HTTP headers.*/
+ s.httpheaderlineptr = 0;
+ s.state = WEBCLIENT_STATE_HEADERS;
+ break;
+ } else {
+ ++s.httpheaderlineptr;
+ }
+ }
+ return len;
+}
+/*-----------------------------------------------------------------------------------*/
+static u16_t
+parse_headers(u16_t len)
+{
+ char *cptr;
+
+ while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) {
+ s.httpheaderline[s.httpheaderlineptr] = *uip_appdata;
+ ++uip_appdata;
+ --len;
+ if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) {
+ /* We have an entire HTTP header line in s.httpheaderline, so
+ we parse it. */
+ if(s.httpheaderline[0] == ISO_cr) {
+ /* This was the last header line (i.e., and empty "\r\n"), so
+ we are done with the headers and proceed with the actual
+ data. */
+ s.state = WEBCLIENT_STATE_DATA;
+ return len;
+ }
+
+ s.httpheaderline[s.httpheaderlineptr - 1] = 0;
+ /* Check for specific HTTP header fields. */
+ if(strncmp(s.httpheaderline, http_content_type,
+ sizeof(http_content_type) - 1) == 0) {
+ /* Found Content-type field. */
+ cptr = strchr(s.httpheaderline, ';');
+ if(cptr != NULL) {
+ *cptr = 0;
+ }
+ strncpy(s.mimetype, s.httpheaderline +
+ sizeof(http_content_type) - 1, sizeof(s.mimetype));
+ } else if(strncmp(s.httpheaderline, http_location,
+ sizeof(http_location) - 1) == 0) {
+ strncpy(s.file, s.httpheaderline +
+ sizeof(http_location) - 1, sizeof(s.file));
+ s.file[s.httpheaderlineptr - 1] = 0;
+ }
+
+
+ /* We're done parsing, so we reset the pointer and start the
+ next line. */
+ s.httpheaderlineptr = 0;
+ } else {
+ ++s.httpheaderlineptr;
+ }
+ }
+ return len;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+newdata(void)
+{
+ u16_t len;
+
+ len = uip_datalen();
+
+ if(s.state == WEBCLIENT_STATE_STATUSLINE) {
+ len = parse_statusline(len);
+ }
+
+ if(s.state == WEBCLIENT_STATE_HEADERS && len > 0) {
+ len = parse_headers(len);
+ }
+
+ if(len > 0 && s.state == WEBCLIENT_STATE_DATA &&
+ s.httpflag != HTTPFLAG_MOVED) {
+ webclient_datahandler((char *)uip_appdata, len);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+DISPATCHER_UIPCALL(webclient_appcall, state)
+{
+ struct uip_conn *conn;
+ DISPATCHER_UIPCALL_ARG(state);
+
+ if(uip_connected()) {
+ s.timer = 0;
+ s.state = WEBCLIENT_STATE_STATUSLINE;
+ senddata();
+ webclient_connected();
+ dispatcher_markconn(uip_conn, &s);
+ return;
+ }
+
+
+ if(state == NULL) {
+ uip_abort();
+ return;
+ }
+
+ if(s.state == WEBCLIENT_STATE_CLOSE) {
+ webclient_closed();
+ uip_abort();
+ return;
+ }
+
+
+
+ if(uip_aborted()) {
+ webclient_aborted();
+ }
+ if(uip_timedout()) {
+ webclient_timedout();
+ }
+
+
+ if(uip_acked()) {
+ s.timer = 0;
+ acked();
+ }
+ if(uip_newdata()) {
+ s.timer = 0;
+ newdata();
+ }
+ if(uip_rexmit() ||
+ uip_newdata() ||
+ uip_acked()) {
+ senddata();
+ } else if(uip_poll()) {
+ ++s.timer;
+ if(s.timer == WEBCLIENT_TIMEOUT) {
+ webclient_timedout();
+ uip_abort();
+ return;
+ }
+ /* senddata();*/
+ }
+
+ if(uip_closed()) {
+ dispatcher_markconn(uip_conn, NULL);
+ if(s.httpflag != HTTPFLAG_MOVED) {
+ /* Send NULL data to signal EOF. */
+ webclient_datahandler(NULL, 0);
+ } else {
+ conn = uip_connect(uip_conn->ripaddr, s.port);
+ if(conn != NULL) {
+ dispatcher_markconn(conn, NULL);
+ init_connection();
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/