aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-10-06 16:18:19 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-10-06 16:18:19 -0700
commit78e467f98bd472fce0164f32b0da890640439ed4 (patch)
treeb4d5706ad4f690c7c55404b49fae499aec471f26
parentbf80c09a99bb7fb118c522bf40dbf7c743b42829 (diff)
downloadlwip-78e467f98bd472fce0164f32b0da890640439ed4.tar.gz
lwip-78e467f98bd472fce0164f32b0da890640439ed4.tar.xz
lwip-78e467f98bd472fce0164f32b0da890640439ed4.zip
core: pxe: add a very simple network streaming interface
Add a very simple network streaming interface, similar to the socket read interface, but much simpler. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--core/fs/pxe/http.c228
-rw-r--r--core/fs/pxe/netstream.c80
-rw-r--r--core/fs/pxe/netstream.h26
-rw-r--r--core/fs/pxe/pxe.h5
4 files changed, 219 insertions, 120 deletions
diff --git a/core/fs/pxe/http.c b/core/fs/pxe/http.c
index e39f2f3f..c15c574f 100644
--- a/core/fs/pxe/http.c
+++ b/core/fs/pxe/http.c
@@ -14,13 +14,15 @@
#include "thread.h"
#include "strbuf.h"
#include "url.h"
+#include "netstream.h"
#include "lwip/api.h"
#include "lwip/dns.h"
-struct file *http_open(struct url_info *url, struct strbuf **redirect)
+int http_open(struct file *file, struct url_info *url,
+ struct strbuf **redirect)
{
const char *p;
- char c;
+ int c;
int err;
struct ip_addr ip;
struct netconn *conn = NULL;
@@ -44,7 +46,8 @@ struct file *http_open(struct url_info *url, struct strbuf **redirect)
struct strbuf *header_data = NULL;
int64_t content_length;
char *ep;
- struct file *file;
+ int rv = -1;
+ struct open_file_t *of = file->open_file;
*redirect = NULL;
@@ -73,19 +76,19 @@ struct file *http_open(struct url_info *url, struct strbuf **redirect)
/* XXX: implement at least basic authentication here */
+ memset(&of->data, 0, sizeof of->data);
+
err = netconn_gethostbyname(url->host, &ip);
if (err)
return NULL;
- file = NULL;
-
- conn = netconn_new(NETCONN_TCP);
- err = netconn_connect(conn, &ip, url->port ? url->port : 80);
+ of->data.conn = conn = netconn_new(NETCONN_TCP);
+ err = netconn_connect(of->data.conn, &ip, url->port ? url->port : 80);
if (err)
goto err_delete;
- err = netconn_write(conn, strbuf_str(http_header), strbuf_len(http_header),
- NETCONN_NOCOPY);
+ err = netconn_write(of->data.conn, strbuf_str(http_header),
+ strbuf_len(http_header), NETCONN_NOCOPY);
if (err)
goto err_disconnect;
@@ -99,117 +102,100 @@ struct file *http_open(struct url_info *url, struct strbuf **redirect)
content_length = -1;
while (state != st_eoh) {
- void *data;
- u16_t len;
-
- buf = netconn_recv(conn);
- if (!buf)
+ c = netstream_getc(&of->data);
+ if (c == -1)
break;
+
+ if (c == '\r' || c == '\0')
+ continue;
- do {
- netbuf_data(buf, &data, &len);
+ switch (state) {
+ case st_httpver:
+ if (c == ' ') {
+ state = st_stcode;
+ pos = 0;
+ }
+ break;
+
+ case st_stcode:
+ if (c < '0' || c > '9')
+ goto err_disconnect ;
+ status = (status*10) + (c - '0');
+ if (++pos == 3)
+ state = st_skipline;
+ break;
+
+ case st_skipline:
+ if (c == '\n') {
+ state = st_headerfirst;
+ pos = 0;
+ }
+ break;
+
+ case st_headerfirst:
+ if (c == '\n') {
+ state = st_eoh;
+ break;
+ } else if (isspace(c)) {
+ state = st_skipline;
+ break;
+ }
+ /* else fall through */
- p = data;
- while (state != st_eoh && len) {
- c = *p++;
- len--;
-
- if (c == '\r' || c == '\0')
- continue;
-
- switch (state) {
- case st_httpver:
- if (c == ' ') {
- state = st_stcode;
- pos = 0;
- }
- break;
-
- case st_stcode:
- if (c < '0' || c > '9')
- goto err_disconnect ;
- status = (status*10) + (c - '0');
- if (++pos == 3)
- state = st_skipline;
- break;
-
- case st_skipline:
- if (c == '\n') {
- state = st_headerfirst;
- pos = 0;
- }
- break;
-
- case st_headerfirst:
- if (c == '\n') {
- state = st_eoh;
- break;
- } else if (isspace(c)) {
- state = st_skipline;
- break;
- }
- /* else fall through */
-
- case st_header:
- if (!isspace(c)) {
- strbuf_putc(&header_name, c);
- break;
- }
- /* else fall through */
-
- case st_headergap:
- if (c == '\n')
- state = st_contline;
- else if (!isspace(c)) {
- strbuf_putc(&header_data, c);
- state = st_headertoken;
- }
- break;
-
- case st_contline:
- if (c == '\n') {
- strbuf_free(&header_name);
- state = st_eoh;
- } else if (isspace(c)) {
- state = st_headergap;
- } else {
- strbuf_putc(&header_data, c);
- state = st_headertoken;
- }
- break;
-
- case st_headertoken:
- if (isspace(c)) {
- state = (c == '\n') ? st_headerfirst : st_skipline;
-
- if (!strcasecmp("Location:",
- strbuf_str(header_name))) {
- location = header_data;
- header_data = NULL;
- } else if (!strcasecmp("Content-Length:",
- strbuf_str(header_name))) {
- content_length =
- strtoull(strbuf_str(header_data), &ep, 10);
- if (*ep)
- content_length = -1;
- strbuf_free(&header_data);
- } else {
- strbuf_free(&header_data);
- }
- strbuf_free(&header_name);
- } else {
- strbuf_putc(&header_data, c);
- }
- break;
-
- case st_eoh:
- break; /* Should never happen */
+ case st_header:
+ if (!isspace(c)) {
+ strbuf_putc(&header_name, c);
+ break;
+ }
+ /* else fall through */
+
+ case st_headergap:
+ if (c == '\n')
+ state = st_contline;
+ else if (!isspace(c)) {
+ strbuf_putc(&header_data, c);
+ state = st_headertoken;
+ }
+ break;
+
+ case st_contline:
+ if (c == '\n') {
+ strbuf_free(&header_name);
+ state = st_eoh;
+ } else if (isspace(c)) {
+ state = st_headergap;
+ } else {
+ strbuf_putc(&header_data, c);
+ state = st_headertoken;
+ }
+ break;
+
+ case st_headertoken:
+ if (isspace(c)) {
+ state = (c == '\n') ? st_headerfirst : st_skipline;
+
+ if (!strcasecmp("Location:", strbuf_str(header_name))) {
+ location = header_data;
+ header_data = NULL;
+ } else if (!strcasecmp("Content-Length:",
+ strbuf_str(header_name))) {
+ content_length =
+ strtoull(strbuf_str(header_data), &ep, 10);
+ if (*ep)
+ content_length = -1;
+ strbuf_free(&header_data);
+ } else {
+ strbuf_free(&header_data);
}
+ strbuf_free(&header_name);
+ } else {
+ strbuf_putc(&header_data, c);
}
- } while (state != st_eoh && netbuf_next(buf) >= 0);
-
- if (state != st_eoh)
- netbuf_delete(buf);
+ break;
+
+ case st_eoh:
+ break; /* Should never happen */
+ }
}
if (state != st_eoh)
@@ -240,12 +226,14 @@ err_disconnect:
strbuf_free(&header_data);
strbuf_free(&location);
- if (file)
- return file;
+ if (!rv)
+ return rv;
- netconn_disconnect(conn);
+ if (of->data.buf)
+ netbuf_delete(of->data.buf);
+ netconn_disconnect(of->data.conn);
err_delete:
- netconn_delete(conn);
- return NULL;
+ netconn_delete(of->data.conn);
+ return rv;
}
diff --git a/core/fs/pxe/netstream.c b/core/fs/pxe/netstream.c
new file mode 100644
index 00000000..6c31c09d
--- /dev/null
+++ b/core/fs/pxe/netstream.c
@@ -0,0 +1,80 @@
+/*
+ * netstream.c
+ *
+ * Simple interface to get data from a network stream; used during
+ * header processing. It is much more lightweight than the socket
+ * interface.
+ */
+
+#include <string.h>
+#include "lwip/api.h"
+#include "pxe.h"
+
+int netstream_getc(struct netstream *stream)
+{
+ int rv;
+
+ if (!stream->conn)
+ return -1;
+
+ if (!stream->buf || !stream->buf->ptr) {
+ stream->buf = netconn_recv(stream->conn);
+ if (!stream->buf)
+ return -1;
+ }
+
+ rv = ((unsigned char *)stream->buf->ptr->payload)[stream->offs++];
+ if (stream->offs >= stream->buf->ptr->len) {
+ stream->buf->ptr = stream->buf->ptr->next;
+ if (!stream->buf->ptr) {
+ netbuf_delete(stream->buf);
+ stream->buf = NULL;
+ }
+ stream->offs = 0;
+ }
+
+ return rv;
+}
+
+int netstream_read(struct netstream *stream, void *buf, int bytes)
+{
+ char *p = buf;
+ int rv = 0;
+ int avail;
+
+ if (!stream->conn)
+ return -1;
+
+ while (bytes) {
+ if (!stream->buf || !stream->buf->ptr) {
+ stream->buf = netconn_recv(stream->conn);
+ if (!stream->buf)
+ break;
+ stream->offs = 0;
+ }
+
+ avail = stream->buf->ptr->len - stream->offs;
+ if (avail > bytes)
+ avail = bytes;
+
+ memcpy(p, (char *)stream->buf->ptr->payload + stream->offs, avail);
+ p += avail;
+ stream->offs += avail;
+ bytes -= avail;
+ rv += avail;
+
+ if (stream->offs >= stream->buf->ptr->len) {
+ stream->buf->ptr = stream->buf->ptr->next;
+ if (!stream->buf->ptr) {
+ netbuf_delete(stream->buf);
+ stream->buf = NULL;
+ }
+ stream->offs = 0;
+ }
+ }
+
+ return rv;
+}
+
+
+
diff --git a/core/fs/pxe/netstream.h b/core/fs/pxe/netstream.h
new file mode 100644
index 00000000..ff1ea0e5
--- /dev/null
+++ b/core/fs/pxe/netstream.h
@@ -0,0 +1,26 @@
+/*
+ * netstream.h
+ *
+ * Simple interface to get data from a network stream; used during
+ * header processing. It is much more lightweight than the socket
+ * interface.
+ */
+
+#ifndef CORE_PXE_NETSTREAM_H
+#define CORE_PXE_NETSTREAM_H
+
+#include <stddef.h>
+
+struct netconn;
+struct netbuf;
+
+struct netstream {
+ struct netconn *conn; /* Network connection */
+ struct netbuf *buf; /* Network buffer */
+ size_t offs; /* Offset from ptr */
+};
+
+int netstream_getc(struct netstream *stream);
+int netstream_read(struct netstream *stream, void *buf, int bytes);
+
+#endif /* CORE_PXE_NETSTREAM_H */
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index f62fa7a7..8910f058 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -20,6 +20,8 @@
#define PXE_H
#include <syslinux/pxe_api.h>
+#include "lwip/api.h"
+#include "netstream.h"
#include "fs.h" /* For MAX_OPEN, should go away */
/*
@@ -141,6 +143,9 @@ struct bootp_t {
} __attribute__ ((packed));
struct open_file_t {
+ struct netstream data; /* Data network connection */
+ struct netstream ctl; /* Control network connection (used by FTP) */
+
uint16_t tftp_localport; /* Local port number (0=not in us)*/
uint16_t tftp_remoteport; /* Remote port number */
uint32_t tftp_remoteip; /* Remote IP address */