Support for Macintosh System 1.1 on 128K Macintosh

This port of lwip adds support for 128K Macintosh
with the original 64K ROMs running System 1.1 or
later.
Modem port must be connected to a server running pppd
at 9600 baud.
This commit is contained in:
Eric Pooch 2018-03-12 21:40:46 -07:00
parent 3e5dca9bfb
commit 9a5b3d8918
31 changed files with 6390 additions and 3266 deletions

4
.gitignore vendored
View File

@ -1,3 +1,7 @@
.DS_Store
*.o
/ports/mac/ElWhip-HTTPD
/ports/mac/ElWhip\ 0.*
/ports/win32/msvc/Debug
/ports/win32/lwipcfg_msvc.h
/ports/win32/msvc/Debug unittests

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,140 +1 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_FS_H
#define LWIP_FS_H
#include "lwip/opt.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Set this to 1 and provide the functions:
* - "int fs_open_custom(struct fs_file *file, const char *name)"
* Called first for every opened file to allow opening files
* that are not included in fsdata(_custom).c
* - "void fs_close_custom(struct fs_file *file)"
* Called to free resources allocated by fs_open_custom().
*/
#ifndef LWIP_HTTPD_CUSTOM_FILES
#define LWIP_HTTPD_CUSTOM_FILES 0
#endif
/** Set this to 1 to support fs_read() to dynamically read file data.
* Without this (default=off), only one-block files are supported,
* and the contents must be ready after fs_open().
*/
#ifndef LWIP_HTTPD_DYNAMIC_FILE_READ
#define LWIP_HTTPD_DYNAMIC_FILE_READ 0
#endif
/** Set this to 1 to include an application state argument per file
* that is opened. This allows to keep a state per connection/file.
*/
#ifndef LWIP_HTTPD_FILE_STATE
#define LWIP_HTTPD_FILE_STATE 0
#endif
/** HTTPD_PRECALCULATED_CHECKSUM==1: include precompiled checksums for
* predefined (MSS-sized) chunks of the files to prevent having to calculate
* the checksums at runtime. */
#ifndef HTTPD_PRECALCULATED_CHECKSUM
#define HTTPD_PRECALCULATED_CHECKSUM 0
#endif
/** LWIP_HTTPD_FS_ASYNC_READ==1: support asynchronous read operations
* (fs_read_async returns FS_READ_DELAYED and calls a callback when finished).
*/
#ifndef LWIP_HTTPD_FS_ASYNC_READ
#define LWIP_HTTPD_FS_ASYNC_READ 0
#endif
#define FS_READ_EOF -1
#define FS_READ_DELAYED -2
#if HTTPD_PRECALCULATED_CHECKSUM
struct fsdata_chksum {
u32_t offset;
u16_t chksum;
u16_t len;
};
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
struct fs_file {
const char *data;
int len;
int index;
void *pextension;
#if HTTPD_PRECALCULATED_CHECKSUM
const struct fsdata_chksum *chksum;
u16_t chksum_count;
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
u8_t http_header_included;
#if LWIP_HTTPD_CUSTOM_FILES
u8_t is_custom_file;
#endif /* LWIP_HTTPD_CUSTOM_FILES */
#if LWIP_HTTPD_FILE_STATE
void *state;
#endif /* LWIP_HTTPD_FILE_STATE */
};
#if LWIP_HTTPD_FS_ASYNC_READ
typedef void (*fs_wait_cb)(void *arg);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
err_t fs_open(struct fs_file *file, const char *name);
void fs_close(struct fs_file *file);
#if LWIP_HTTPD_DYNAMIC_FILE_READ
#if LWIP_HTTPD_FS_ASYNC_READ
int fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg);
#else /* LWIP_HTTPD_FS_ASYNC_READ */
int fs_read(struct fs_file *file, char *buffer, int count);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
#if LWIP_HTTPD_FS_ASYNC_READ
int fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
int fs_bytes_left(struct fs_file *file);
#if LWIP_HTTPD_FILE_STATE
/** This user-defined function is called when a file is opened. */
void *fs_state_init(struct fs_file *file, const char *name);
/** This user-defined function is called when a file is closed. */
void fs_state_free(struct fs_file *file, void *state);
#endif /* #if LWIP_HTTPD_FILE_STATE */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_FS_H */
/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * 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. 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 lwIP TCP/IP stack. * * Author: Adam Dunkels <adam@sics.se> * */ #ifndef LWIP_FS_H #define LWIP_FS_H #include "lwip/opt.h" #include "lwip/err.h" #ifdef __cplusplus extern "C" { #endif /** Set this to 1 and provide the functions: * - "int fs_open_custom(struct fs_file *file, const char *name)" * Called first for every opened file to allow opening files * that are not included in fsdata(_custom).c * - "void fs_close_custom(struct fs_file *file)" * Called to free resources allocated by fs_open_custom(). */ #ifndef LWIP_HTTPD_CUSTOM_FILES #define LWIP_HTTPD_CUSTOM_FILES 0 #endif /** Set this to 1 to support fs_read() to dynamically read file data. * Without this (default=off), only one-block files are supported, * and the contents must be ready after fs_open(). */ #ifndef LWIP_HTTPD_DYNAMIC_FILE_READ #define LWIP_HTTPD_DYNAMIC_FILE_READ 0 #endif /** Set this to 1 to include an application state argument per file * that is opened. This allows to keep a state per connection/file. */ #ifndef LWIP_HTTPD_FILE_STATE #define LWIP_HTTPD_FILE_STATE 0 #endif /** HTTPD_PRECALCULATED_CHECKSUM==1: include precompiled checksums for * predefined (MSS-sized) chunks of the files to prevent having to calculate * the checksums at runtime. */ #ifndef HTTPD_PRECALCULATED_CHECKSUM #define HTTPD_PRECALCULATED_CHECKSUM 0 #endif /** LWIP_HTTPD_FS_ASYNC_READ==1: support asynchronous read operations * (fs_read_async returns FS_READ_DELAYED and calls a callback when finished). */ #ifndef LWIP_HTTPD_FS_ASYNC_READ #define LWIP_HTTPD_FS_ASYNC_READ 0 #endif #define FS_READ_EOF -1 #define FS_READ_DELAYED -2 #if HTTPD_PRECALCULATED_CHECKSUM struct fsdata_chksum { u32_t offset; u16_t chksum; u16_t len; }; #endif /* HTTPD_PRECALCULATED_CHECKSUM */ struct fs_file { const char *data; int len; int index; void *pextension; #if HTTPD_PRECALCULATED_CHECKSUM const struct fsdata_chksum *chksum; u16_t chksum_count; #endif /* HTTPD_PRECALCULATED_CHECKSUM */ u8_t http_header_included; #if LWIP_HTTPD_CUSTOM_FILES u8_t is_custom_file; #endif /* LWIP_HTTPD_CUSTOM_FILES */ #if LWIP_HTTPD_FILE_STATE void *state; #endif /* LWIP_HTTPD_FILE_STATE */ }; #if LWIP_HTTPD_FS_ASYNC_READ typedef void (*fs_wait_cb)(void *arg); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ err_t fs_open(struct fs_file *file, const char *name); void fs_close(struct fs_file *file); #if LWIP_HTTPD_DYNAMIC_FILE_READ #if LWIP_HTTPD_FS_ASYNC_READ int fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); #else /* LWIP_HTTPD_FS_ASYNC_READ */ int fs_read(struct fs_file *file, char *buffer, int count); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ #endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ #if LWIP_HTTPD_FS_ASYNC_READ int fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ int fs_bytes_left(struct fs_file *file); #if LWIP_HTTPD_FILE_STATE /** This user-defined function is called when a file is opened. */ void *fs_state_init(struct fs_file *file, const char *name); /** This user-defined function is called when a file is closed. */ void fs_state_free(struct fs_file *file, void *state); #endif /* #if LWIP_HTTPD_FILE_STATE */ #ifdef __cplusplus } #endif #endif /* LWIP_FS_H */

View File

@ -1,50 +1 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_FSDATA_H
#define LWIP_FSDATA_H
#include "lwip/opt.h"
#include "fs.h"
struct fsdata_file {
const struct fsdata_file *next;
const unsigned char *name;
const unsigned char *data;
int len;
u8_t http_header_included;
#if HTTPD_PRECALCULATED_CHECKSUM
u16_t chksum_count;
const struct fsdata_chksum *chksum;
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
};
#endif /* LWIP_FSDATA_H */
/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * 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. 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 lwIP TCP/IP stack. * * Author: Adam Dunkels <adam@sics.se> * */ #ifndef LWIP_FSDATA_H #define LWIP_FSDATA_H #include "lwip/opt.h" #include "fs.h" struct fsdata_file { const struct fsdata_file *next; const unsigned char *name; const unsigned char *data; int len; u8_t http_header_included; #if HTTPD_PRECALCULATED_CHECKSUM u16_t chksum_count; const struct fsdata_chksum *chksum; #endif /* HTTPD_PRECALCULATED_CHECKSUM */ }; #endif /* LWIP_FSDATA_H */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

15
head_support.h.patch Normal file
View File

@ -0,0 +1,15 @@
diff --git a/apps/httpserver_raw/httpd.h b/apps/httpserver_raw/httpd.h
index 3962f72..e0a9d18 100644
--- a/apps/httpserver_raw/httpd.h
+++ b/apps/httpserver_raw/httpd.h
@@ -59,6 +59,10 @@ extern "C" {
#define LWIP_HTTPD_SUPPORT_POST 0
#endif
+/** Set this to 1 to support HTTP HEAD */
+#ifndef LWIP_HTTPD_SUPPORT_HEAD
+#define LWIP_HTTPD_SUPPORT_HEAD 0
+#endif
#if LWIP_HTTPD_CGI

311
head_support.patch Normal file
View File

@ -0,0 +1,311 @@
diff --git a/apps/httpserver_raw/httpd.c b/apps/httpserver_raw/httpd.c
index 772b179..b6199a4 100644
--- a/apps/httpserver_raw/httpd.c
+++ b/apps/httpserver_raw/httpd.c
@@ -317,6 +317,17 @@ static char http_post_response_filename[LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN+1];
#define NUM_FILE_HDR_STRINGS 3
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
+#if LWIP_HTTPD_SUPPORT_HEAD || LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_V09
+enum request_method {
+ METHOD_UNK, /* Unknown method */
+ METHOD_GET, /* HTTP 1.0 spec 8.1 - GET */
+ METHOD_HEAD, /* HTTP 1.0 spec 8.2 - HEAD */
+ METHOD_POST, /* HTTP 1.0 spec 8.3 - POST */
+ METHOD_V09_GET = 9 /* HTTP 0.9 - GET */
+};
+#endif /* LWIP_HTTPD_SUPPORT_HEAD || LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_V09*/
+
+
#if LWIP_HTTPD_SSI
#define HTTPD_LAST_TAG_PART 0xFFFF
@@ -370,6 +381,9 @@ struct http_state {
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
u8_t keepalive;
#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
+#if LWIP_HTTPD_SUPPORT_HEAD || LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_V09
+ int method;
+#endif /* LWIP_HTTPD_SUPPORT_HEAD || LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_V09 */
#if LWIP_HTTPD_SSI
struct http_ssi_state *ssi;
#endif /* LWIP_HTTPD_SSI */
@@ -398,8 +412,8 @@ struct http_state {
static err_t http_close_conn(struct tcp_pcb *pcb, struct http_state *hs);
static err_t http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_conn);
-static err_t http_find_file(struct http_state *hs, const char *uri, int is_09);
-static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri, u8_t tag_check);
+static err_t http_find_file(struct http_state *hs, const char *uri);
+static err_t http_init_file(struct http_state *hs, struct fs_file *file, const char *uri, u8_t tag_check);
static err_t http_poll(void *arg, struct tcp_pcb *pcb);
static u8_t http_check_eof(struct tcp_pcb *pcb, struct http_state *hs);
#if LWIP_HTTPD_FS_ASYNC_READ
@@ -706,7 +720,6 @@ http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_
}
#endif /* LWIP_HTTPD_SUPPORT_POST*/
-
tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL);
tcp_err(pcb, NULL);
@@ -1620,7 +1633,7 @@ http_find_error_file(struct http_state *hs, u16_t error_nr)
}
}
}
- return http_init_file(hs, &hs->file_handle, 0, NULL, 0);
+ return http_init_file(hs, &hs->file_handle, NULL, 0);
}
#else /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
#define http_find_error_file(hs, error_nr) ERR_ARG
@@ -1677,7 +1690,7 @@ http_handle_post_finished(struct http_state *hs)
/* NULL-terminate the buffer */
http_post_response_filename[0] = 0;
httpd_post_finished(hs, http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN);
- return http_find_file(hs, http_post_response_filename, 0);
+ return http_find_file(hs, http_post_response_filename);
}
/** Pass received POST body data to the application and correctly handle
@@ -1706,11 +1719,11 @@ http_post_rxpbuf(struct http_state *hs, struct pbuf *p)
hs->post_content_len_left = 0;
}
if (hs->post_content_len_left == 0) {
-#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
+#if LWIP_HTTPD_POST_MANUAL_WND
if (hs->unrecved_bytes != 0) {
return ERR_OK;
}
-#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
+#endif /* LWIP_HTTPD_POST_MANUAL_WND */
/* application error or POST finished */
return http_handle_post_finished(hs);
}
@@ -1792,7 +1805,7 @@ http_post_request(struct pbuf *inp, struct http_state *hs,
}
} else {
/* return file passed from application */
- return http_find_file(hs, http_post_response_filename, 0);
+ return http_find_file(hs, http_post_response_filename);
}
} else {
LWIP_DEBUGF(HTTPD_DEBUG, ("POST received invalid Content-Length: %s\n",
@@ -1946,11 +1959,7 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
if (data_len >= MIN_REQ_LEN) {
/* wait for CRLF before parsing anything */
crlf = strnstr(data, CRLF, data_len);
- if (crlf != NULL) {
-#if LWIP_HTTPD_SUPPORT_POST
- int is_post = 0;
-#endif /* LWIP_HTTPD_SUPPORT_POST */
- int is_09 = 0;
+ if (crlf != NULL) {
char *sp1, *sp2;
u16_t left_len, uri_len;
LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("CRLF received, parsing request\n"));
@@ -1959,16 +1968,27 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
sp1 = data + 3;
/* received GET request */
LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received GET request\"\n"));
+#if LWIP_HTTPD_SUPPORT_HEAD || LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_V09
+ hs->method = METHOD_GET;
+#endif /* LWIP_HTTPD_SUPPORT_HEAD || LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_V09 */
+#if LWIP_HTTPD_SUPPORT_HEAD
+ } else if (!strncmp(data, "HEAD ", 5)) {
+ /* store request type */
+ hs->method = METHOD_HEAD;
+ sp1 = data + 4;
+ /* received HEAD request */
+ LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received HEAD request\n"));
+#endif /* LWIP_HTTPD_SUPPORT_HEAD */
#if LWIP_HTTPD_SUPPORT_POST
} else if (!strncmp(data, "POST ", 5)) {
/* store request type */
- is_post = 1;
+ hs->method = METHOD_POST;
sp1 = data + 4;
- /* received GET request */
+ /* received POST request */
LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received POST request\n"));
#endif /* LWIP_HTTPD_SUPPORT_POST */
} else {
- /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
+ /* null-terminate the METHOD (pbuf is freed anyway when returning) */
data[4] = 0;
/* unsupported method! */
LWIP_DEBUGF(HTTPD_DEBUG, ("Unsupported request method (not implemented): \"%s\"\n",
@@ -1982,32 +2002,33 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
if (sp2 == NULL) {
/* HTTP 0.9: respond with correct protocol version */
sp2 = strnstr(sp1 + 1, CRLF, left_len);
- is_09 = 1;
-#if LWIP_HTTPD_SUPPORT_POST
- if (is_post) {
- /* HTTP/0.9 does not support POST */
+#if LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_HEAD
+ if (hs->method != METHOD_GET) {
+ /* HTTP/0.9 only supports GET method */
goto badrequest;
}
-#endif /* LWIP_HTTPD_SUPPORT_POST */
+#endif /* LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_HEAD */
+ hs->method = METHOD_V09_GET;
}
#endif /* LWIP_HTTPD_SUPPORT_V09 */
+
uri_len = sp2 - (sp1 + 1);
if ((sp2 != 0) && (sp2 > sp1)) {
/* wait for CRLFCRLF (indicating end of HTTP headers) before parsing anything */
if (strnstr(data, CRLF CRLF, data_len) != NULL) {
char *uri = sp1 + 1;
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
- if (!is_09 && strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len)) {
+ if ((hs->method != METHOD_V09_GET && strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len)) {
hs->keepalive = 1;
}
#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
- /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
+ /* null-terminate the METHOD (pbuf is freed anyway when returning) */
*sp1 = 0;
uri[uri_len] = 0;
LWIP_DEBUGF(HTTPD_DEBUG, ("Received \"%s\" request for URI: \"%s\"\n",
data, uri));
#if LWIP_HTTPD_SUPPORT_POST
- if (is_post) {
+ if (method == METHOD_POST) {
#if LWIP_HTTPD_SUPPORT_REQUESTLIST
struct pbuf *q = hs->req;
#else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
@@ -2027,7 +2048,7 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
} else
#endif /* LWIP_HTTPD_SUPPORT_POST */
{
- return http_find_file(hs, uri, is_09);
+ return http_find_file(hs, uri);
}
}
} else {
@@ -2045,9 +2066,9 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
} else
#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
{
-#if LWIP_HTTPD_SUPPORT_POST
+#if LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_HEAD
badrequest:
-#endif /* LWIP_HTTPD_SUPPORT_POST */
+#endif /* LWIP_HTTPD_SUPPORT_POST || LWIP_HTTPD_SUPPORT_HEAD */
LWIP_DEBUGF(HTTPD_DEBUG, ("bad request\n"));
/* could not parse request */
return http_find_error_file(hs, 400);
@@ -2059,12 +2080,11 @@ badrequest:
*
* @param hs the connection state
* @param uri the HTTP header URI
- * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response)
* @return ERR_OK if file was found and hs has been initialized correctly
* another err_t otherwise
*/
static err_t
-http_find_file(struct http_state *hs, const char *uri, int is_09)
+http_find_file(struct http_state *hs, const char *uri)
{
size_t loop;
struct fs_file *file = NULL;
@@ -2154,7 +2174,7 @@ http_find_file(struct http_state *hs, const char *uri, int is_09)
}
#endif /* LWIP_HTTPD_SSI */
}
- return http_init_file(hs, file, is_09, uri, tag_check);
+ return http_init_file(hs, file, uri, tag_check);
}
/** Initialize a http connection with a file to send (if found).
@@ -2162,14 +2182,13 @@ http_find_file(struct http_state *hs, const char *uri, int is_09)
*
* @param hs http connection state
* @param file file structure to send (or NULL if not found)
- * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response)
* @param uri the HTTP header URI
* @param tag_check enable SSI tag checking
* @return ERR_OK if file was found and hs has been initialized correctly
* another err_t otherwise
*/
static err_t
-http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri, u8_t tag_check)
+http_init_file(struct http_state *hs, struct fs_file *file, const char *uri, u8_t tag_check)
{
if (file != NULL) {
/* file opened, initialise struct http_state */
@@ -2192,25 +2211,41 @@ http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const cha
hs->file = (char*)file->data;
LWIP_ASSERT("File length must be positive!", (file->len >= 0));
hs->left = file->len;
+#if LWIP_HTTPD_DYNAMIC_FILE_READ
+ if (hs->file == NULL) {
+ /* Causes http_check_eof() to be called which will read the data. */
+ hs->left = 0;
+ }
+#endif
hs->retries = 0;
#if LWIP_HTTPD_TIMING
hs->time_started = sys_now();
#endif /* LWIP_HTTPD_TIMING */
#if !LWIP_HTTPD_DYNAMIC_HEADERS
LWIP_ASSERT("HTTP headers not included in file system", hs->handle->http_header_included);
-#endif /* !LWIP_HTTPD_DYNAMIC_HEADERS */
+#endif /* !LWIP_HTTPD_DYNAMIC_HEADERS */
+#if LWIP_HTTPD_SUPPORT_V09 || LWIP_HTTPD_SUPPORT_HEAD
+ if ( hs->handle->http_header_included && hs->method != METHOD_GET) {
+ /* Search for the end of the header. */
+ char *head_end = strnstr(hs->file, CRLF CRLF, hs->left);
+ size_t diff = head_end + 4 - hs->file;
+ if (head_end == NULL) {
+ LWIP_DEBUGF(HTTPD_DEBUG, ("Expected HTTP header, but couldn't find it.\n"));
+ hs->handle->http_header_included = 0;
#if LWIP_HTTPD_SUPPORT_V09
- if (hs->handle->http_header_included && is_09) {
- /* HTTP/0.9 responses are sent without HTTP header,
- search for the end of the header. */
- char *file_start = strnstr(hs->file, CRLF CRLF, hs->left);
- if (file_start != NULL) {
- size_t diff = file_start + 4 - hs->file;
- hs->file += diff;
- hs->left -= (u32_t)diff;
- }
- }
+ } else if (hs->method == METHOD_V09_GET) {
+ /* HTTP/0.9 responses are sent without HTTP header. */
+ hs->file += diff;
+ hs->left -= (u32_t)diff;
#endif /* LWIP_HTTPD_SUPPORT_V09*/
+#if LWIP_HTTPD_SUPPORT_HEAD
+ } else if (hs->method == METHOD_HEAD) {
+ /* HEAD method responses are sent with only HTTP header. */
+ hs->left = (u32_t)diff;
+#endif /* LWIP_HTTPD_SUPPORT_HEAD*/
+ }
+ }
+#endif /* LWIP_HTTPD_SUPPORT_V09 || LWIP_HTTPD_SUPPORT_HEAD*/
} else {
hs->handle = NULL;
hs->file = NULL;
@@ -2221,7 +2256,18 @@ http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const cha
/* Determine the HTTP headers to send based on the file extension of
* the requested URI. */
if ((hs->handle == NULL) || !hs->handle->http_header_included) {
- get_http_headers(hs, (char*)uri);
+#if LWIP_HTTPD_SUPPORT_V09
+ if (hs->method != METHOD_V09_GET)
+ /* Don't load the header. */
+#endif /* LWIP_HTTPD_SUPPORT_V09*/
+ get_http_headers(hs, (char*)uri);
+#if LWIP_HTTPD_SUPPORT_HEAD
+ if (hs->method == METHOD_HEAD) {
+ /* Just the the header, not the file. */
+ hs->left = 0;
+ hs->handle->len = 0;
+ }
+#endif /* LWIP_HTTPD_SUPPORT_HEAD*/
}
#else /* LWIP_HTTPD_DYNAMIC_HEADERS */
LWIP_UNUSED_ARG(uri);

1
ports/mac/ElWhip.c Normal file

File diff suppressed because one or more lines are too long

1
ports/mac/ElWhip.h Normal file
View File

@ -0,0 +1 @@
/* * ElWhip.h * * * Created by Eric Pooch on 1/26/14. * Copyright 2014 __MyCompanyName__. All rights reserved. * */ #define kMinSize 128 /* application's minimum size (in K) */ /* We made the preferred size bigger than the minimum size by 12K, so that there would be even more room for the scrap, FKEYs, etc. */ #define kPrefSize 192 /* application's preferred size (in K) */ #define rMenuBar 128 /* application's menu bar */ #define rAboutAlert 128 /* about alert */ #define rUserAlert 129 /* error user alert */ /* kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the SysEnvRec we understand. */ #define kSysEnvironsVersion 1 /* kTextMargin is the number of pixels we leave blank at the edge of the window. */ #define kTextMargin 2 /* kScrollWidth is the width of the scroll bar. */ #define kScrollWidth 15 /* kCrChar is used to match with a carriage return when calculating the number of lines in the TextEdit record. kDelChar is used to check for delete in keyDowns. */ #define kCrChar 13 #define kDelChar 8 /* kMaxTELength is an arbitrary number used to limit the length of text in the TERec so that various errors won't occur from too many characters in the text. */ #define kMaxTELength 32000 /* kOSEvent is the event number of the suspend/resume and mouse-moved events sent by MultiFinder. Once we determine that an event is an osEvent, we look at the high byte of the message sent to determine which kind it is. To differentiate suspend and resume events we check the resumeMask bit. */ #define kOSEvent app4Evt /* event used by MultiFinder */ #define kSuspendResumeMessage 1 /* high byte of suspend/resume event message */ #define kResumeMask 1 /* bit of message field for resume vs. suspend */ #define kMouseMovedMessage 0xFA /* high byte of mouse-moved event message */ #define kNoEvents 0 /* no events mask */ /* The following constants are used to identify menus and their items. The menu IDs have an "m" prefix and the item numbers within each menu have an "i" prefix. */ #define mApple 128 /* Apple menu */ #define iAbout 1 #define mFile 129 /* File menu */ /*#define iNew 1 #define iClose 4*/ #define iQuit 1 /*2*/ #define mEdit 130 /* Edit menu */ /*#define iUndo 1 #define iCut 3 #define iCopy 4 #define iPaste 5 #define iClear 6 #define mConn 131 */ /* Connection menu */ /*#define iConn 1 #define iDcon 2*/ /* 1.01 - kTopLeft - This is for positioning the Disk Initialization dialogs. */ /* #define kDITop 0x0050 #define kDILeft 0x0070 */ /* 1.01 - kMinHeap - This is the minimum result from the following equation: ORD(GetApplLimit) - ORD(ApplicZone) for the application to run. It will insure that enough memory will be around for reasonable-sized scraps, FKEYs, etc. to exist with the application, and still give the application some 'breathing room'. To derive this number, we ran under a MultiFinder partition that was our requested minimum size, as given in the 'SIZE' resource. */ #define kMinHeap 21 * 1024 /* 1.01 - kMinSpace - This is the minimum result from PurgeSpace, when called at initialization time, for the application to run. This number acts as a double-check to insure that there really is enough memory for the application to run, including what has been taken up already by pre-loaded resources, the scrap, code, and other sundry memory blocks. */ #define kMinSpace 8 * 1024 /* kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions. */ #define kExtremeNeg -32768 #define kExtremePos 32767 - 1 /* required to address an old region bug */ /* these #defines are used to set enable/disable flags of a menu */ #define AllItems 0b1111111111111111111111111111111 /* 31 flags */ #define NoItems 0b0000000000000000000000000000000 #define MenuItem1 0b0000000000000000000000000000001 #define MenuItem2 0b0000000000000000000000000000010 #define MenuItem3 0b0000000000000000000000000000100 #define MenuItem4 0b0000000000000000000000000001000 #define MenuItem5 0b0000000000000000000000000010000 #define MenuItem6 0b0000000000000000000000000100000 #define MenuItem7 0b0000000000000000000000001000000 #define MenuItem8 0b0000000000000000000000010000000 #define MenuItem9 0b0000000000000000000000100000000 #define MenuItem10 0b0000000000000000000001000000000 #define MenuItem11 0b0000000000000000000010000000000 #define MenuItem12 0b0000000000000000000100000000000

1
ports/mac/ElWhip.r Normal file
View File

@ -0,0 +1 @@
/*------------------------------------------------------------------------------*/ #include "Types.r" #include "ElWhip.h" resource 'vers' (1) { 0x02, 0x00, release, 0x00, verUS, ".071", ".071, Copyright \251 Eric Pooch 2014, 2015" }; /* we use an MBAR resource to conveniently load all the menus */ resource 'MBAR' (rMenuBar, preload) { { mApple, mFile, mEdit }; /* three menus */ }; resource 'MENU' (mApple, preload) { mApple, textMenuProc, AllItems & ~MenuItem2, /* Disable dashed line, enable About and DAs */ enabled, apple, { "About ElWhipÉ", noicon, nokey, nomark, plain; "-", noicon, nokey, nomark, plain } }; resource 'MENU' (mFile, preload) { mFile, textMenuProc, AllItems, /* enable Quit only, program enables others */ enabled, "File", { /* "New", noicon, "N", nomark, plain; "Open", noicon, "O", nomark, plain; "-", noicon, nokey, nomark, plain; "Close", noicon, "W", nomark, plain; "Save", noicon, "S", nomark, plain; "Save AsÉ", noicon, nokey, nomark, plain; "Revert", noicon, nokey, nomark, plain; "-", noicon, nokey, nomark, plain; "Page SetupÉ", noicon, nokey, nomark, plain; "PrintÉ", noicon, nokey, nomark, plain; "-", noicon, nokey, nomark, plain;*/ "Quit", noicon, "Q", nomark, plain } }; resource 'MENU' (mEdit, preload) { mEdit, textMenuProc, NoItems, // disable everything, program does the enabling enabled, "Edit", { "Undo", noicon, "Z", nomark, plain; "-", noicon, nokey, nomark, plain; "Cut", noicon, "X", nomark, plain; "Copy", noicon, "C", nomark, plain; "Paste", noicon, "V", nomark, plain; "Clear", noicon, nokey, nomark, plain } }; /* this ALRT and DITL are used as an About screen */ resource 'ALRT' (rAboutAlert, purgeable) { {40, 20, 160, 300}, rAboutAlert, { /* array: 4 elements */ /* [1] */ OK, visible, silent, /* [2] */ OK, visible, silent, /* [3] */ OK, visible, silent, /* [4] */ OK, visible, silent }, centerMainScreen }; resource 'DITL' (rAboutAlert, purgeable) { { /* array DITLarray: 4 elements */ /* [1] */ {88, 180, 108, 240}, Button { enabled, "OK" }, /* [2] */ {8, 8, 24, 260}, StaticText { disabled, "El Whip with lwip networking stack" }, /* [3] */ {32, 8, 48, 260}, StaticText { disabled, " © 2014, 2015 Eric Pooch" }, /* [5] */ {56, 8, 72, 260}, StaticText { disabled, "Thanks to RetroChallenge 2014WW" } } }; /* this ALRT and DITL are used as an error screen */ resource 'ALRT' (rUserAlert, purgeable) { {40, 20, 120, 260}, rUserAlert, { /* array: 4 elements */ /* [1] */ OK, visible, silent, /* [2] */ OK, visible, silent, /* [3] */ OK, visible, silent, /* [4] */ OK, visible, silent }, centerMainScreen }; resource 'DITL' (rUserAlert, purgeable) { { /* array DITLarray: 3 elements */ /* [1] */ {50, 150, 70, 230}, Button { enabled, "OK" }, /* [2] */ {10, 60, 30, 230}, StaticText { disabled, "ElWhip - Fatal Error occurred!" }, /* [3] */ {8, 8, 40, 40}, Icon { disabled, 2 } } }; #ifdef TESTING_1234 /* here is the quintessential MultiFinder friendliness device, the SIZE resource */ resource 'SIZE' (-1) { dontSaveScreen, acceptSuspendResumeEvents, enableOptionSwitch, canBackground, /* we can background; we don't currently, but our sleep value */ /* guarantees we don't hog the Mac while we are in the background */ multiFinderAware, /* this says we do our own activate/deactivate; don't fake us out */ backgroundAndForeground, /* this is definitely not a background-only application! */ dontGetFrontClicks, /* change this is if you want "do first click" behavior like the Finder */ ignoreChildDiedEvents, /* essentially, I'm not a debugger (sub-launching) */ not32BitCompatible, /* this app should not be run in 32-bit address space */ reserved, reserved, reserved, reserved, reserved, reserved, reserved, kPrefSize * 1024, kMinSize * 1024 }; #endif

View File

1
ports/mac/Makefile Normal file

File diff suppressed because one or more lines are too long

115
ports/mac/include/arch/cc.h Normal file
View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __ARCH_CC_H__
#define __ARCH_CC_H__
/* Turn debugging on */
// We define with the compiler on a per-file basis
//#define LWIP_DEBUG
//#undef LWIP_DEBUG
#if defined LWIP_DEBUG
#include <stdio.h>
#endif
#define BYTE_ORDER BIG_ENDIAN
typedef unsigned char u_char;
typedef unsigned char u8_t;
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef signed short s16_t;
typedef unsigned int u32_t;
typedef signed int s32_t;
typedef u32_t mem_ptr_t;
#define __sio_fd_t_defined
typedef void * sio_fd_t;
/* Compiler hints for packing structures */
#define PACK_STRUCT_BEGIN //#pragma options align=mac68k
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END //#pragma options align=reset
#define PACK_STRUCT_FIELD(x) x
//#define ALIGN_STRUCT_8_BEGIN #pragma options align=power
//#define ALIGN_STRUCT_END #pragma options align=reset
/*
* Debug printing formats
*/
#define X16_F "x"
#define U16_F "u"
#define S16_F "d"
#define X32_F "x"
#define U32_F "u"
#define S32_F "d"
/* Plaform specific diagnostic output */
#ifdef LWIP_DEBUG
#if SER_DEBUG
/* Proto for the serial debug print function in test.c */
void ser_debug_print( const char *fmt, ...);
#define LWIP_PLATFORM_DIAG(x) do {ser_debug_print x;} while(0)
#else
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#endif
#define LWIP_PLATFORM_ASSERT(x) LWIP_PLATFORM_DIAG(("Assertion Failed: \"%s\" at line %d in %s\n", \
x, __LINE__, __FILE__))
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
LWIP_PLATFORM_DIAG(("Error: %s", message)); handler;}} while(0)
#else
#define LWIP_PLATFORM_DIAG(x)
#define LWIP_PLATFORM_ASSERT(x)
#endif
/*
#define LWIP_PLATFORM_DIAG(x)
#define LWIP_PLATFORM_DIAG(x) lwip_debug_print x
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#define LWIP_PLATFORM_ASSERT(x) lwip_debug_print( "Assertion \"%s\" failed at line %d in %s\n", \
x, __LINE__, __FILE__)
*/
#endif /* __ARCH_CC_H__ */

View File

@ -0,0 +1 @@
/* * macos_debug.h * * * Created by Eric Pooch on 2/1/15. * Copyright 2015 Eric Pooch. All rights reserved. * * #include "arch/macos_debug.h" instead of debug.h to take advantage of dialog boxes, etc. */ /* MAC_DIALOG DEF? NO-> LWIP_DEBUGF DEF? NO-> Nothing YES YES v v printf() SER_DEBUG ? -NO-> printf() -> Mac dialog box v YES Mac dialog box |-> ser_debug_print() -> Printer port */ #define MAC_DIALOG #undef LWIP_DEBUG #if defined MAC_DIALOG #include <stdio.h> #include "lwip/opt.h" #endif /* MAC_DLOGF: Enable modal dialog notices. * Not for use in timing sensitive portions of code. * Use MACOS_STATE to send the buffer. */ #ifndef MACOS_DEBUG #define MACOS_DEBUG (LWIP_DBG_ON | LWIP_DBG_LEVEL_WARNING) #define MACOS_TRACE (LWIP_DBG_OFF | LWIP_DBG_TRACE ) #define MACOS_STATE (LWIP_DBG_ON | LWIP_DBG_STATE | LWIP_DBG_MASK_LEVEL) #endif #ifdef MACOS_DIALOG #define MACOS_DLOGF(debug, message) do { printf message; if (debug & LWIP_DBG_STATE) { fflush(stdout); } } while (0) #define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ MACOS_DLOGF(LWIP_DBG_STATE, ("Error: %s", message)); handler;}} while(0) #else #define MACOS_DLOGF(debug, message) LWIP_DEBUGF(debug, message) #endif /*MAC_DIALOG*/

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __ARCH_PERF_H__
#define __ARCH_PERF_H__
/*#include <sys/times.h>*/
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
#if 0
void perf_print(unsigned long c1l, unsigned long c1h,
unsigned long c2l, unsigned long c2h,
char *key);
void perf_print_times(struct tms *start, struct tms *end, char *key);
void perf_init(char *fname);
#endif
#endif /* __ARCH_PERF_H__ */

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __SYS_MAC_H__
#define __SYS_MAC_H__
#define SYS_MBOX_NULL 0
typedef u8_t sys_sem_t;
typedef u8_t sys_mutex_t;
typedef u8_t sys_mbox_t;
typedef int sys_thread_t;
#endif /* __SYS_MAC_H__ */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

1364
ports/mac/include/lwipopts.h Normal file

File diff suppressed because it is too large Load Diff

11
ports/mac/mac_httpd_ssi.c Normal file
View File

@ -0,0 +1,11 @@
/*
* mac_httpd_ssi.c
*
*
* Created by Eric Pooch on 2/11/15.
* Copyright 2015 __MyCompanyName__. All rights reserved.
*
*/
#include "mac_httpd_ssi.h"

View File

@ -0,0 +1,9 @@
/*
* mac_httpd_ssi.h
*
*
* Created by Eric Pooch on 2/11/15.
* Copyright 2015 __MyCompanyName__. All rights reserved.
*
*/

400
ports/mac/sio.c Normal file
View File

@ -0,0 +1,400 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. 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 lwIP TCP/IP stack.
*
*/
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/sio.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <Errors.h>
#include <Files.h>
#include <Devices.h>
#include <Serial.h>
/**
* SIO_DEBUG: Enable debugging for SIO.
*/
#ifndef SIO_DEBUG
#define SIO_DEBUG LWIP_DBG_OFF
#endif
/**
* MACOS_INPUT_BUFF_SIZE: Set the ppp input buffer.
* 64 or less uses driver's default 64 byte buffer.
*/
#ifndef MACOS_SIO_BUFF_SIZE
#define MACOS_SIO_BUFF_SIZE 64
#endif
/* sio_fd_t is supposed to be a void pointer, so we need to do some casting back. */
#define PORT_NUM(sd) (*(short *)sd)
#define IN_REF(sd) (int)(PORT_NUM(sd) + 3) * -2
#define OUT_REF(sd) (int)IN_REF(sd)-1
u8_t sio_setup(sio_fd_t sd);
OSErr ROMSDOpen(SPortSel whichPort);
char *sio_input_buffer;
#if NO_SYS==0
static unsigned char sio_abort = 0xFF;
#endif
#pragma segment LWUPDN
u8_t sio_setup(sio_fd_t fd)
{
OSErr error;
unsigned short baud;
short databits;
short stopbits;
short parity;
short config;
SerShk shake;
/* Set the new data */
baud = baud19200; /* 19200 */
parity = noParity; /* None*/
databits = data8; /* 8 */
stopbits = stop10; /* 1 */
/* do not use flow control */
shake.fXOn = 0;
shake.fCTS = 0;
shake.xOn = 0;
shake.xOff = 0;
shake.errs = 0;
shake.evts = 0;
shake.fInX = 0;
shake.fDTR = 0;
config = baud + parity + databits + stopbits;
//config = (baud | parity | databits | stopbits);
LWIP_DEBUGF(SIO_DEBUG, ("sio_setup(%d, %d)\n", IN_REF(fd), OUT_REF(fd))) ;
if (error = SerReset(IN_REF(fd), config))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't configure serial port due to \'SerReset\' error:%d. Continuing...\n", IN_REF(fd), error)) ;
if (error = SerHShake(IN_REF(fd), &shake))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't disable serial handshake due to \'SerHShake\' error:%d. Continuing...\n", IN_REF(fd), error)) ;
if (error = SerReset(OUT_REF(fd), config))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't configure serial port due to \'SerReset\' error:%d. Continuing...\n", OUT_REF(fd), error)) ;
if (error = SerHShake(OUT_REF(fd), &shake))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't disable serial handshake due to \'SerHShake\' error:%d. Continuing...\n", OUT_REF(fd), error)) ;
return 1;
}
OSErr ROMSDOpen(SPortSel whichPort)
{
OSErr error = fnfErr;
short inRef, outRef;
char *inDriver;
char *outDriver;
switch (whichPort)
{
case sPortA:
inDriver = ".AIn";
outDriver = ".AOut";
break;
case sPortB:
inDriver = ".BIn";
outDriver = ".BOut";
break;
default:
return error;
break;
}
error = opendriver(outDriver, &outRef);
LWIP_DEBUGF(SIO_DEBUG, ("ROMSDOpen(%d) 'opendriver(%s, %d)\n", whichPort, outDriver, outRef )) ;
if (error == noErr)
{
error = opendriver(inDriver, &inRef);
LWIP_DEBUGF(SIO_DEBUG, ("ROMSDOpen(%d) 'opendriver(%s, %d)\n", whichPort, inDriver, inRef )) ;
}
LWIP_DEBUGF(SIO_DEBUG, ("ROMSDOpen(%d) will return: %d\n", whichPort, error));
return error;
}
/**
* Opens a serial device for communication.
*
* @param devnum device number
* @return handle to serial device if successful, NULL otherwise
*/
sio_fd_t sio_open(u8_t devnum)
{
OSErr error = fnfErr;
/* These are the the serial port numbers that 'sio_fd_t sd' points to. */
static const short modemPort = sPortA;
static const short printerPort = sPortB;
/* The serial port device is just a pointer to one of the constant port numbers. */
sio_fd_t sd;
/* Keep track of the port name for debugging and warnings. */
char* port_name;
/* We don't have devices, but sPortA (0) is Modem and sPortB (1) is Printer. */
switch (devnum)
{
case 'P' :
case 'p' :
case 'b' :
case 'B' :
case sPortB :
port_name = "Printer";
sd = (sio_fd_t)&printerPort;
error = ROMSDOpen(sPortB);
break;
case 'M' :
case 'm' :
case 'a' :
case 'A' :
case sPortA :
default:
port_name = "Modem";
sd = (sio_fd_t)&modemPort;
error = ROMSDOpen(sPortA);
/* PPP was overflowing the input buffer, so make it bigger.*/
if (MACOS_SIO_BUFF_SIZE > 64 && sio_input_buffer == NULL)
{
sio_input_buffer = (char *)malloc(MACOS_SIO_BUFF_SIZE);
LWIP_ASSERT("sio_open() can't allocate memory", sio_input_buffer != NULL);
}
if ( error == noErr && sio_input_buffer)
SerSetBuf(IN_REF(sd), sio_input_buffer, MACOS_SIO_BUFF_SIZE);
break;
}
switch (error)
{
case (int)noErr: //0
LWIP_DEBUGF(SIO_TRACE, ("Serial Port successfully opened.\n", devnum));
break;
case (int)badUnitErr: //-21
LWIP_ERROR("Bad Reference Number for Serial Port.\n", (error == noErr ), return NULL;);
break;
case (int)dInstErr: //-26
LWIP_ERROR("Couldn't Find Serial Driver in Resource File.\n", (error == noErr ), return NULL;);
break;
case (int)openErr: //-23
LWIP_ERROR("Driver can't perform the requested reading or writing.\n", (error == noErr ), return NULL;);
break;
case (int)unitEmptyErr: //-22
LWIP_ERROR("Bad Reference Number for Serial Port.\n", (error == noErr ), return NULL;);
break;
case (int)fnfErr: //-43
LWIP_ERROR(("Serial Port Not Found.\n"), (error == noErr ), return NULL;);
break;
default:
//printf("%d", (int)error);
LWIP_ERROR("Unknown Error opening Serial Port.\n", (error == noErr ), return NULL;);
break;
}
sio_setup(sd);
LWIP_DEBUGF(SIO_DEBUG, ("%s Port Successfully Opened.\n", (PORT_NUM(sd) == (int)sPortA)? "Modem":"Printer"));
return sd;
}
/**
* Closes a serial device.
*
* @param fd device
*/
void
sio_close(sio_fd_t fd)
{
if (PORT_NUM(fd) == (int)sPortA && sio_input_buffer)
SerSetBuf(IN_REF(fd), sio_input_buffer, 0);
/* Don't Close the ROM Serial Driver */
}
/**
* Sends a single character to the serial device.
*
* @param c character to send
* @param fd serial device handle
*
* @note This function will block until the character can be sent.
*/
#pragma segment LWPPP
void sio_send(u8_t c, sio_fd_t fd)
{
OSErr error;
long count = 1;
error = FSWrite(OUT_REF(fd), &count, &(char)c);
if (error)
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_send(%c, %d) failed due to \'FSWrite\' error: %d.\n", c, PORT_NUM(fd), error));
return;
}
/**
* Receives a single character from the serial device.
*
* @param fd serial device handle
*
* @note This function will block until a character is received. The blocking
* can be cancelled by calling sio_read_abort().
*/
#if NO_SYS==0
u8_t sio_recv(sio_fd_t fd)
{
static unsigned char cbuff;
sio_read(fd, &(char)cbuff, 1);
return cbuff;
}
#endif
/**
* Reads from the serial device.
*
* @param fd serial device handle
* @param data pointer to data buffer for receiving
* @param len maximum length (in bytes) of data to receive
* @return number of bytes actually received - may be 0 if aborted by sio_read_abort
*
* @note If NO_SYS is > 0, this function will block until data can be received.
* The blocking can be cancelled by calling sio_read_abort().
*/
u32_t sio_read(sio_fd_t fd, u8_t* data, u32_t len)
{
long count = 0;
#if NO_SYS==0
while (sio_abort != IN_REF(fd) && count < len)
#endif
{
count = sio_tryread(fd, data, len);
}
#if NO_SYS==0
if (sio_abort == IN_REF(fd))
sio_abort = 0xFF;
#endif
return count;
}
/**
* Non-Blocking Read from the serial device.
*
* @param fd serial device handle
* @param data pointer to data buffer for receiving
* @param len maximum length (in bytes) of data to receive
* @return number of bytes actually received - may be 0
*
*/
u32_t sio_tryread(sio_fd_t fd, u8_t* data, u32_t len)
{
OSErr error;
long count = 0;
(void)SerGetBuf(IN_REF(fd), &count);
if (count)
{
/* only get up to the length asked for. */
if (count > len) count = (long)len;
if ((error = FSRead(IN_REF(fd), &count, (char *)data)))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_read(%d, %d) failed due to \'FSRead\' error: %d.\n", IN_REF(fd), len, error));
}
return count;
}
/**
* Writes to the serial device.
*
* @param fd serial device handle
* @param data pointer to data to send
* @param len length (in bytes) of data to send
* @return number of bytes actually sent
*
* @note This function will block until all data can be sent.
*/
u32_t sio_write(sio_fd_t fd, u8_t* data, u32_t len)
{
OSErr error;
long count = (long)len;
error = FSWrite(OUT_REF(fd), &count, (char *)data);
// The ppp module will log the error for us.
if (error)
return error;
return len;
}
#if NO_SYS==0
/**
* Aborts a blocking sio_read() call.
*
* @param fd serial device handle
*/
void sio_read_abort(sio_fd_t fd)
{
LWIP_DEBUGF(SIO_DEBUG, ("sio_read_abort(%d)\n", IN_REF(fd) ));
sio_abort = IN_REF(fd);
return;
}
#endif

139
ports/mac/sys_arch.c Normal file
View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include <time.h>
#include ":lwip:sys.h"
#include ":lwip:def.h"
#include ":lwip:opt.h"
#if NO_SYS
struct thread_struct_wrapper *lwip_system_threads = NULL; // a list of all threads created by lwIP
u32_t
sys_jiffies(void)
{
return (u32_t)clock();
}
#else
static clock_t sys_start;
u32_t
sys_jiffies(void)
{
return (u32_t)(clock() - sys_start);
}
u32_t
sys_now(void)
{
return (u32_t)(sys_jiffies() * (1000/CLOCKS_PER_SEC) );
}
void
sys_init(void)
{
sys_start = clock();
return;
}
void
sys_arch_block(u16_t time)
{
u16_t ticks;
ticks = (time * (1000/CLOCKS_PER_SEC)) + clock();
while (clock() != ticks) {}
}
err_t
sys_mbox_new(sys_mbox_t *mbox, int size)
{
mbox = SYS_MBOX_NULL;
return ERR_OK;
}
void
sys_mbox_free(sys_mbox_t *mbox)
{
return;
}
err_t
sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
return ERR_OK;
}
err_t
sys_sem_new(sys_sem_t *sem, u8_t count)
{
sem = 0;
return ERR_OK;
}
u32_t
sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
sys_arch_block(timeout);
return 0;
}
void
sys_sem_signal(sys_sem_t *sem)
{
return;
}
void
sys_sem_free(sys_sem_t *sem)
{
return;
}
sys_thread_t
sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
return 0;
}
#endif
u32_t
sys_now(void)
{
return (u32_t)(sys_jiffies() * (1000/CLOCKS_PER_SEC));
}

1
ports/mac/test.c Normal file

File diff suppressed because one or more lines are too long

1
ports/mac/test.h Normal file
View File

@ -0,0 +1 @@
/* * test.h * * * Created by Eric Pooch on 1/26/14. * Copyright 2014 __MyCompanyName__. All rights reserved. * */ void test_init(void); void test_restart(void); void test_poll(void); void test_quit(void);

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

49
ports/mac/www/index.html Normal file
View File

@ -0,0 +1,49 @@
<html>
<head><title>ElWhip: Featuring lwip - A Lightweight TCP/IP Stack</title></head>
<body bgcolor="white" text="black">
<table width="100%">
<tr valign="top"><td width="80">
<img src="/img/mac_hello.gif"
border="0" alt="Macintosh hello" title="Macintosh hello"></a>
</td><td width="500">
<h1>ElWhip: Featuring lwIP - A Lightweight TCP/IP Stack</h1>
<p>
The web page you are viewing is being served on an original
Macintosh with 512K RAM. This is the first known TCP/IP stack
running on a Macintosh with the original 64K ROMs. This is made
possible by the lightweight TCP/IP stack <a
href="http://www.sics.se/~adam/lwip/">lwIP</a>.
</p>
<p>
lwIP is an open source implementation of the TCP/IP
protocol suite that was originally written by <a
href="http://www.sics.se/~adam/lwip/">Adam Dunkels
of the Swedish Institute of Computer Science</a> but now is
being actively developed by a team of developers
distributed world-wide. Since it's release, lwIP has
spurred a lot of interest and has been ported to several
platforms and operating systems. lwIP can be used either
with or without an underlying OS.
</p>
<p>
The focus of the lwIP TCP/IP implementation is to reduce
the RAM usage while still having a full scale TCP. This
makes lwIP suitable for use in embedded systems with tens
of kilobytes of free RAM and room for around 40 kilobytes
of code ROM.
</p>
<p>
More information about lwIP can be found at the lwIP
homepage at <a
href="http://savannah.nongnu.org/projects/lwip/">http://savannah.nongnu.org/projects/lwip/</a>
or at the lwIP wiki at <a
href="http://lwip.wikia.com/">http://lwip.wikia.com/</a>.
</p>
</td><td>
&nbsp;
</td></tr>
</table>
</body>
</html>