diff options
Diffstat (limited to 'cfe/cfe/main/cfe_httpfs.c')
-rw-r--r-- | cfe/cfe/main/cfe_httpfs.c | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/cfe/cfe/main/cfe_httpfs.c b/cfe/cfe/main/cfe_httpfs.c new file mode 100644 index 0000000..4ebad4c --- /dev/null +++ b/cfe/cfe/main/cfe_httpfs.c @@ -0,0 +1,396 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * "HTTP" file system File: cfe_httpfs.c + * + * This filesystem driver lets you read files from an HTTP + * server. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_console.h" + +#include "cfe.h" + +#include "bsp_config.h" + +#if (CFG_TCP) && (CFG_HTTPFS) + +#include "net_ebuf.h" +#include "net_api.h" + + +/* ********************************************************************* + * HTTP context + ********************************************************************* */ + +/* + * File system context - describes overall file system info, + * such as the handle to the underlying device. + */ + +typedef struct http_fsctx_s { + int http_tmp; /* context not really needed */ +} http_fsctx_t; + +/* + * File context - describes an open file on the file system. + */ + +#define HTTP_BUFSIZE 1024 +typedef struct http_file_s { + http_fsctx_t *http_fsctx; + int http_socket; + uint8_t http_buffer[HTTP_BUFSIZE]; + uint8_t *http_bptr; + int http_blen; + int http_offset; + char *http_filename; +} http_file_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int http_fileop_init(void **fsctx,void *devicename); +static int http_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int http_fileop_read(void *ref,uint8_t *buf,int len); +static int http_fileop_write(void *ref,uint8_t *buf,int len); +static int http_fileop_seek(void *ref,int offset,int how); +static void http_fileop_close(void *ref); +static void http_fileop_uninit(void *fsctx); + +/* ********************************************************************* + * RAW fileio dispatch table + ********************************************************************* */ + +const fileio_dispatch_t http_fileops = { + "http", + FSYS_TYPE_NETWORK, + http_fileop_init, + http_fileop_open, + http_fileop_read, + http_fileop_write, + http_fileop_seek, + http_fileop_close, + http_fileop_uninit +}; + +static int http_fileop_init(void **newfsctx,void *dev) +{ + http_fsctx_t *fsctx; + + *newfsctx = NULL; + + fsctx = KMALLOC(sizeof(http_fsctx_t),0); + if (!fsctx) { + return CFE_ERR_NOMEM; + } + + fsctx->http_tmp = 0; + *newfsctx = fsctx; + + return 0; +} + +static int http_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode) +{ + http_fsctx_t *fsctx; + http_file_t *file; + char temp[200]; + char *hostname, *filen; + int hlen; + int termidx; + int res; + int err = 0; + char *hptr; + char *tok; + uint8_t hostaddr[IP_ADDR_LEN]; + uint8_t termstr[4]; + uint8_t b; + + if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + fsctx = (http_fsctx_t *) fsctx_arg; + + file = KMALLOC(sizeof(http_file_t),0); + if (!file) { + return CFE_ERR_NOMEM; + } + + file->http_filename = lib_strdup(filename); + if (!file->http_filename) { + KFREE(file); + return CFE_ERR_NOMEM; + } + + lib_chop_filename(file->http_filename,&hostname,&filen); + + /* + * Look up remote host + */ + + res = dns_lookup(hostname,hostaddr); + if (res < 0) { + KFREE(file); + return res; + } + + file->http_socket = tcp_socket(); + if (file->http_socket < 0) { + KFREE(file->http_filename); + KFREE(file); + return -1; + } + + /* + * Connect to remote host. + */ + + tcp_setflags(file->http_socket,0); /* set socket to blocking */ + res = tcp_connect(file->http_socket,hostaddr,80); + + if (res < 0) { + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); + return res; + } + + /* + * Send GET command. Supply the hostname (for HTTP 1.1 requirements) + * and set the connection to close as soon as all the data is received. + */ + + hlen = sprintf(temp,"GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",filen,hostname); + + res = tcp_send(file->http_socket,temp,hlen); + if (res < 0) { + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); + return res; + } + + /* + * Read bytes until we either reach EOF or we see "\r\n\r\n" + * This is the server's status string. + */ + + termstr[0] = '\r'; termstr[1] = '\n'; + termstr[2] = '\r'; termstr[3] = '\n'; + termidx = 0; + + file->http_offset = 0; + file->http_blen = 0; + file->http_bptr = file->http_buffer; + + res = 0; + for (;;) { + res = tcp_recv(file->http_socket,&b,1); + if (res < 0) break; + if (b == termstr[termidx]) { + termidx++; + if (termidx == 4) break; + } + else { + termidx = 0; + } + + /* + * Save the bytes from the header up to our buffer + * size. It's okay if we don't save it all, + * since all we want is the result code which comes + * first. + */ + + if (file->http_blen < (HTTP_BUFSIZE-1)) { + *(file->http_bptr) = b; + file->http_bptr++; + file->http_blen++; + } + } + + /* + * Premature EOFs are not good, bail now. + */ + + if (res < 0) { + err = CFE_ERR_EOF; + goto protocolerr; + } + + /* + * Skip past the HTTP response header and grab the result code. + * Sanity check it a little. + */ + + *(file->http_bptr) = 0; + + hptr = file->http_buffer; + tok = lib_gettoken(&hptr); + if (!tok || (memcmp(tok,"HTTP",4) != 0)) { + err = CFE_ERR_PROTOCOLERR; + goto protocolerr; + } + + tok = lib_gettoken(&hptr); + if (!tok) { + err = CFE_ERR_PROTOCOLERR; + goto protocolerr; + } + + switch (lib_atoi(tok)) { + case 200: + err = 0; + break; + case 404: + err = CFE_ERR_FILENOTFOUND; + break; + + } + + /* + * If we get to here, the file is okay and we're about to receive data. + */ + + if (err == 0) { + *ref = file; + return 0; + } + +protocolerr: + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); + *ref = NULL; + return err; +} + +static int http_fileop_read(void *ref,uint8_t *buf,int len) +{ + http_file_t *file = (http_file_t *) ref; + int res; + + res = tcp_recv(file->http_socket,buf,len); + + if (res > 0) { + file->http_offset += res; + return res; + } + + return 0; /* Any error becomes "EOF" */ +} + +static int http_fileop_write(void *ref,uint8_t *buf,int len) +{ + return CFE_ERR_UNSUPPORTED; +} + +static int http_fileop_seek(void *ref,int offset,int how) +{ + http_file_t *file = (http_file_t *) ref; + int newoffset; + int res; + int buflen; + + switch (how) { + case FILE_SEEK_BEGINNING: + newoffset = offset; + break; + case FILE_SEEK_CURRENT: + newoffset = file->http_offset + offset; + break; + default: + newoffset = offset; + break; + } + + /* + * Can't seek backwards. + */ + if (newoffset < file->http_offset) { + return CFE_ERR_UNSUPPORTED; + } + + /* + * Eat data till offset reaches where we want. + */ + + while (file->http_offset != newoffset) { + buflen = HTTP_BUFSIZE; + if (buflen > (newoffset - file->http_offset)) buflen = (newoffset-file->http_offset); + res = tcp_recv(file->http_socket,file->http_buffer,buflen); + if (res < 0) break; + file->http_offset += res; + } + + return file->http_offset; +} + + +static void http_fileop_close(void *ref) +{ + http_file_t *file = (http_file_t *) ref; + + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); +} + +static void http_fileop_uninit(void *fsctx_arg) +{ + http_fsctx_t *fsctx = (http_fsctx_t *) fsctx_arg; + + KFREE(fsctx); +} + +#endif |