diff options
Diffstat (limited to 'cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_httpd.c')
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_httpd.c | 1031 |
1 files changed, 1031 insertions, 0 deletions
diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_httpd.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_httpd.c new file mode 100755 index 0000000..dcd5b0a --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_httpd.c @@ -0,0 +1,1031 @@ +/* milli_httpd - pretty small HTTP server +** A combination of +** micro_httpd - really small HTTP server +** and +** mini_httpd - small HTTP server +** +** Copyright 1999,2000 by Jef Poskanzer <jef@acme.com>. +** 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. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. +*/ + +#if (CFG_WEB_SERVER==1) + +/** Includes. **/ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_timer.h" +#include "cfe_error.h" +#include "cfe.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" + +#include "bsp_config.h" + +#include "bcmTag.h" +#include "bcm63xx_util.h" + + +/** Externs. **/ + +extern char ul_html[]; +extern char ulinfo_html[]; +extern int ul_html_size; +extern int ulinfo_html_size; + +extern int g_console_abort; +extern int g_processing_cmd; + +/** Defines. **/ + +#define SERVER_NAME "micro_httpd" +#define SERVER_URL "http://www.acme.com/software/micro_httpd/" +#define SERVER_PORT 80 +#define PROTOCOL "HTTP/1.0" +#define POST_DATA_START (unsigned char *) \ + BOARD_IMAGE_DOWNLOAD_ADDRESS +#define SOCKET_CLOSED -100 +#define NUM_SOCKETS 4 + +/* Return codes from cfe_web_gets. */ +#define WEB_GETS_DONE 1 +#define WEB_GETS_PENDING 2 +#define WEB_GETS_ERROR 3 + +/* HTTP states. */ +#define HTTP_INITIAL 0 +#define HTTP_READ_FIRST_HDR 1 +#define HTTP_READ_REMAINING_HDRS 2 +#define HTTP_READ_POST_DATA 3 + +/* HTTP POST status */ +#define UPLOAD_OK '0' +#define UPLOAD_FAIL_NO_MEM '1' +#define UPLOAD_FAIL_NO_FILENAME '2' +#define UPLOAD_FAIL_ILLEGAL_IMAGE '3' +#define UPLOAD_FAIL_IMAGE_TOOBIG '4' +#define UPLOAD_FAIL_CORRUPT_IMAGE '5' +#define UPLOAD_FAIL_FLASH '6' +#define UPLOAD_FATAL '7' +#define UPLOAD_PENDING '8' +#define UPLOAD_TCP_ERROR '9' + +/* HTTP upload image formats. */ +#define NO_IMAGE_FORMAT 0 +#define BROADCOM_IMAGE_FORMAT 1 +#define FLASH_IMAGE_FORMAT 2 + + +/** Structs. **/ + +typedef struct +{ + int s; + int state; + int web_buf_idx; + int post_content_length; + char web_first_buf[128]; + char web_buf[256]; +} SOCKET_INFO, *PSOCKET_INFO; + +typedef struct +{ + char *wp_name; + char *wp_content_buf; + int *wp_content_size; + char *wp_mime_type; +} WEB_PAGE_MAP, *PWEB_PAGE_MAP; + + +/** Globals. **/ + +static int g_listen_idx = 0; +static unsigned char *g_image_start = NULL; +static int g_image_len = 0; +static int g_image_format = NO_IMAGE_FORMAT; +static int g_post_data_in_progress = 0; +static int g_post_data_idx = 0; + +static SOCKET_INFO g_socket_info[NUM_SOCKETS]; + +static WEB_PAGE_MAP g_web_page_map[] = + { + {"/", ul_html, &ul_html_size, "text/html"}, + {"/upload.html", ul_html, &ul_html_size, "text/html"}, + {"/uploadinfo.html", ulinfo_html, &ulinfo_html_size, "text/html"}, + {NULL, NULL, 0, NULL} + }; + + +/** Prototypes. **/ + +int cfe_web_check(void); +void cfe_web_fg_process(void); +void cfe_web_poll(void *x); +static void cfe_web_listen( int *listen_idx_ptr ); +static void cfe_web_bg_process(PSOCKET_INFO si); +static int cfe_web_gets( char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int s ); +static int read_first_hdr(int s, char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int *close_tcp_ptr); +static int read_remaining_hdrs(int s, char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int *close_tcp_ptr, int *content_length_ptr); +static char read_post_data( int s, unsigned char *post_data_start, + int content_length, int *post_data_idx_ptr ); +static char parse_post_data( int s, unsigned char *post_data_start, + int post_data_length, unsigned char **image_start_ptr, int *image_len_ptr, + int *image_format_ptr ); +static void send_error( int s, int status, char* title, char* extra_header, + char* text ); +static void send_error( int s, int status, char* title, char* extra_header, + char* text ); +static void send_headers( int s, int status, char* title, char* extra_header, + char* mime_type ); +static void send_page( int s, char *path, int send_headers_flag, + char **substs, int num_substs ); +static int cfe_web_tcp_send( int s, char *buf, int size ); +void * memmove(void * dest,const void *src,size_t count); + + +/*************************************************************************** + * Function Name: cfe_web_check + * Description : Checks if an image has been downloaded through an HTTP POST + * request and is ready to be written to flash memory. + * Returns : 1 - image is ready to be flashed, 0 - nothing to do + ***************************************************************************/ +int cfe_web_check(void) +{ + return( (g_image_format != NO_IMAGE_FORMAT) ? 1 : 0 ); +} /* cfe_web_check */ + + +/*************************************************************************** + * Function Name: cfe_web_process + * Description : Calls the appropriate functions to write an image to + * flash memory. + * Returns : None. + ***************************************************************************/ +void cfe_web_fg_process(void) +{ + /* Wait so the uploadinfo web page can be displayed on the browser. */ + cfe_sleep(CFE_HZ * 2); + if( g_image_format == BROADCOM_IMAGE_FORMAT ) + flashImage( g_image_start ); + else + if( g_image_format == FLASH_IMAGE_FORMAT ) + writeWholeImage( g_image_start, g_image_len ); + + if( g_image_format != NO_IMAGE_FORMAT ) + softReset(); + +} /* cfe_web_process */ + + +/*************************************************************************** + * Function Name: cfe_web_poll + * Description : The entry point function that is called in the background + * at polled intervals. It listens for and processes HTTP + * requests. + * Returns : None. + ***************************************************************************/ +void cfe_web_poll(void *x) +{ + static int first_time = 1; + static int in_cfe_web_poll = 0; + + PSOCKET_INFO si; + int i; + + if( in_cfe_web_poll == 0 ) + { + in_cfe_web_poll = 1; + + /* If this is the first time that this function was called, initialize + * the socket info data array. + */ + if( first_time == 1 ) + { + first_time = 0; + for( i = 0, si = g_socket_info; i < NUM_SOCKETS; i++, si++ ) + { + si->s = SOCKET_CLOSED; + si->state = HTTP_READ_FIRST_HDR; + si->web_buf_idx = 0; + si->post_content_length = 0; + } + } + + /* Check the connection state of each socket. */ + for( i = 0, si = g_socket_info; i < NUM_SOCKETS; i++, si++ ) + { + cfe_web_listen( &g_listen_idx ); + if( si->s >= 0 ) + { + unsigned int connflag; + tcp_status( si->s, &connflag, NULL, NULL ); + if( connflag == TCPSTATUS_CONNECTED ) + { + cfe_web_bg_process( si ); + POLL(); + } + else + if( connflag == TCPSTATUS_NOTCONN ) + { + console_log("web warning: Unexpected TCP disconnect."); + tcp_close(si->s); + si->s = SOCKET_CLOSED; + si->state = HTTP_READ_FIRST_HDR; + si->web_buf_idx = 0; + } + } + } + + in_cfe_web_poll = 0; + } +} /* cfe_web_poll */ + + +/*************************************************************************** + * Function Name: cfe_web_listen + * Description : This function checks to see if TCP listen can be issued + * on the HTTP port and issues the listen if it can. + * Returns : None. + ***************************************************************************/ +static void cfe_web_listen( int *listen_idx_ptr ) +{ + static int port = SERVER_PORT; + + int listen_idx = *listen_idx_ptr; + PSOCKET_INFO si = &g_socket_info[listen_idx]; + + /* If a TCP socket has been opened, check its connection status. */ + if( si->s >= 0 ) + { + unsigned int connflag; + tcp_status( si->s, &connflag, NULL, NULL ); + + /* If the socket is connection, set the next socket index to listen for + * a TCP connection. + */ + if( connflag == TCPSTATUS_CONNECTED ) + { + listen_idx = (listen_idx + 1) % NUM_SOCKETS; + si = &g_socket_info[listen_idx]; + } + } + + /* If the TCP socket has not been opened, open it and listen for a TCP + * connection. + */ + if( si->s == SOCKET_CLOSED ) + { + /* Open the socket in non-blocking mode. */ + POLL(); + if( (si->s = tcp_socket()) >= 0 ) + { + console_log("web info: Waiting for connection on socket %d.", si->s); + if( tcp_listen(si->s, port) != 0 ) + console_log("web error: listen error on %d.", si->s); + } + else + { + console_log("web error %d: Could not create TCP socket.", si->s); + si->s = SOCKET_CLOSED; + } + } + + *listen_idx_ptr = listen_idx; +} /* cfe_web_listen */ + + +/*************************************************************************** + * Function Name: cfe_web_bg_process + * Description : This function processes an HTTP request on a socket. + * Returns : None. + ***************************************************************************/ +static void cfe_web_bg_process(PSOCKET_INFO si) +{ + char post_subst[] = {UPLOAD_FATAL, '\0'}; + char *post_substs[] = {post_subst}; + int close_tcp = 0; + + switch( si->state ) + { + case HTTP_READ_FIRST_HDR: + if( read_first_hdr( si->s, si->web_first_buf, + sizeof(si->web_first_buf), &si->web_buf_idx, &close_tcp ) == 0 ) + { + /* Not all of the first header has been read yet. Try again later.*/ + break; + } + + /* The first header has been read. */ + si->state = HTTP_READ_REMAINING_HDRS; + + /* fall thru */ + + case HTTP_READ_REMAINING_HDRS: + if( read_remaining_hdrs( si->s, si->web_buf, sizeof(si->web_buf), + &si->web_buf_idx, &close_tcp, &si->post_content_length ) ) + { + if( g_processing_cmd == 0 ) + { + char *method = NULL; + char *path = NULL; + char *ptr = (char *) si->web_first_buf; + + method = gettoken(&ptr); + if( method ) + path = gettoken(&ptr); + + /* Process the HTTP request. Only GET and POST are supported. */ + if( method && path ) + { + if( !strcmpi( method, "get" ) ) + { + send_page( si->s, path, 1, NULL, 0 ); + close_tcp = 1; + } + else + { + if( !strcmpi( method, "post" ) ) + { + if( g_post_data_in_progress == 0 ) + { + g_post_data_in_progress = 1; + si->state = HTTP_READ_POST_DATA; + } + else + { + send_error( si->s, 501, "Upload Busy", + (char*) 0, + "An image is already being uploaded." ); + close_tcp = 1; + } + } + else + { + send_error( si->s, 501, "Not Implemented", + (char*) 0, + "That method is not implemented." ); + close_tcp = 1; + } + } + } + else + { + send_error( si->s, 400, "Bad Request", (char *) 0, + "Can't parse request." ); + close_tcp = 1; + } + } + else + { + /* A download and flash image command is being executed from + * the serial port console. + */ + send_error( si->s, 400, "Bad Request", (char *) 0, + "Console command is in progress." ); + close_tcp = 1; + } + } + + if( si->state != HTTP_READ_POST_DATA ) + break; + + case HTTP_READ_POST_DATA: + /* Read the post data, which contains an image to flash, into low + * memory. + */ + if( (post_subst[0] = read_post_data( si->s, POST_DATA_START, + si->post_content_length, &g_post_data_idx )) == UPLOAD_OK ) + { + /* Verify that the post data is a valid image to flash. */ + post_subst[0] = parse_post_data( si->s, POST_DATA_START, + g_post_data_idx, (unsigned char **) &g_image_start, &g_image_len, + &g_image_format ); + } + + switch( post_subst[0] ) + { + case UPLOAD_PENDING: + break; + + case UPLOAD_TCP_ERROR: + close_tcp = 1; + g_post_data_in_progress = 0; + g_post_data_idx = 0; + break; + + case UPLOAD_OK: + /* Notify foreground to abort the console input so it can + * write the image to flash memory. + */ + g_console_abort = 1; + + send_page(si->s, "/uploadinfo.html", 0, post_substs, 1); + close_tcp = 1; + g_post_data_idx = 0; + break; + + default: + /* The image was downloaded OK but there was a problem with it + * so it could not be written to flash memory. + */ + send_page(si->s, "/uploadinfo.html", 0, post_substs, 1); + close_tcp = 1; + g_post_data_in_progress = 0; + g_post_data_idx = 0; + break; + } + break; + } + + /* Close the socket if the HTTP transaction is done. */ + if( close_tcp ) + { + POLL(); + tcp_close(si->s); + si->s = SOCKET_CLOSED; + si->state = HTTP_READ_FIRST_HDR; + si->web_buf_idx = 0; + si->post_content_length = 0; + } +} /* cfe_web_poll */ + + +/*************************************************************************** + * Function Name: cfe_web_gets + * Description : Reads from a socket up to a <CR><LF> or <LF>. The socket + * is non-blocking. + * Returns : WEB_GETS_DONE - Complete line was read. + * WEB_GETS_PENDING - Line partially read. + * WEB_GETS_ERROR - Socket error. + ***************************************************************************/ +static int cfe_web_gets( char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int s ) +{ + int ret = WEB_GETS_PENDING; + unsigned char ch; + int web_buf_idx = *web_buf_idx_ptr; + char *p = web_buf + web_buf_idx; + int continue_reading = 1; + + while( web_buf_idx < web_buf_size && continue_reading ) + { + switch( tcp_recv( s, &ch, 1 ) ) + { + case 0: /* no characters are available to receive */ + continue_reading = 0; + break; + + case 1: /* character was read */ + if( ch == '\n' ) + { + *p = '\0'; + continue_reading = 0; + ret = WEB_GETS_DONE; + } + else + if( ch != '\r' ) + { + *p++ = ch; + web_buf_idx++; + } + break; + + default: + continue_reading = 0; + ret = WEB_GETS_ERROR; + break; + } + } + + if( web_buf_idx == web_buf_size ) + { + web_buf[web_buf_idx - 1] = '\0'; + ret = WEB_GETS_DONE; + } + + *web_buf_idx_ptr = web_buf_idx; + + return( ret ); +} /* cfe_web_gets */ + + +/*************************************************************************** + * Function Name: read_first_hdr + * Description : This function reads the first HTTP header which contains + * the method (GET, POST), path and protocol. For example, + * GET /upload.html HTTP/1.1 + * Returns : 1 - First header was read, 0 - was not read. + ***************************************************************************/ +static int read_first_hdr(int s, char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int *close_tcp_ptr) +{ + int ret = 0; + int sts = cfe_web_gets( web_buf, web_buf_size, web_buf_idx_ptr, s ); + + switch( sts ) + { + case WEB_GETS_DONE: + /* The first HTTP header has been read into web_buf. */ + *web_buf_idx_ptr = 0; + ret = 1; + break; + + case WEB_GETS_ERROR: + console_log("web error: TCP read error."); + *close_tcp_ptr = 1; + break; + } + + return( ret ); +} /* read_first_hdr */ + + +/*************************************************************************** + * Function Name: read_remaining_hdrs + * Description : This function reads the remaining HTTP headers. + * Returns : 1 - Remaining headers were read, 0 - were not read. + ***************************************************************************/ +static int read_remaining_hdrs(int s, char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int *close_tcp_ptr, int *content_length_ptr) +{ + int ret = 0; + int sts = WEB_GETS_DONE; + + while( sts == WEB_GETS_DONE ) + { + sts = cfe_web_gets( web_buf, web_buf_size, web_buf_idx_ptr, s ); + switch( sts ) + { + case WEB_GETS_DONE: + if( *web_buf_idx_ptr == 0 ) + { + /* The remaining HTTP headers have been read. */ + ret = 1; + sts = WEB_GETS_PENDING; + } + else + { + char *p2 = web_buf; + char *p1 = gettoken(&p2); + if( !strcmpi( p1, "Content-Length:" ) ) + *content_length_ptr=atoi(p2); + *web_buf_idx_ptr = 0; + } + break; + + case WEB_GETS_ERROR: + console_log("web error: TCP read error."); + *close_tcp_ptr = 1; + break; + } + } + + return( ret ); +} /* read_remaining_hdrs */ + + +/*************************************************************************** + * Function Name: read_post_data + * Description : This function reads HTTP POST data which is the contents of + * a new image to write to flash memory. + * Returns : UPLOAD_OK - all data read + * UPLOAD_PENDING - not all data read + * UPLOAD_TCP_ERROR - TCP error + ***************************************************************************/ +static char read_post_data( int s, unsigned char *post_data_start, + int content_length, int *post_data_idx_ptr ) +{ + char ret = UPLOAD_PENDING; + int post_data_idx = *post_data_idx_ptr; + int len; + + do + { + len = tcp_recv( s, (unsigned char*)(post_data_start + post_data_idx), + content_length - post_data_idx ); + post_data_idx += len; + POLL(); + cfe_web_listen( &g_listen_idx ); + } while( len > 0 && post_data_idx < content_length ); + + *post_data_idx_ptr = post_data_idx; + + if( len < 0 ) + { + console_log("web error: TCP read error receiving post data."); + ret = UPLOAD_TCP_ERROR; + } + else + if( post_data_idx == content_length ) + ret = UPLOAD_OK; + + return( ret ); +} /* read_post_data */ + + +/*************************************************************************** + * Function Name: parse_post_data + * Description : This function parses HTTP POST data which is the contents of + * a new image to write to flash memory. + * Returns : UPLOAD_OK or UPLOAD_xxx error + ***************************************************************************/ +static char parse_post_data( int s, unsigned char *post_data_start, + int post_data_length, unsigned char **image_start_ptr, int *image_len_ptr, + int *image_format_ptr ) +{ + char ret = UPLOAD_OK; + unsigned char *p = post_data_start; + int boundary_size = 0; + + /* Convert the start boundary field into a string. It will be compared + * against the end boundary field below. + */ + while( *p != '\r' && *p != '\n' && + ((int) p - (int) post_data_start) < post_data_length ) + { + p++; + } + + if( *p == '\r' || *p == '\n' ) + { + *p++ = '\0'; + boundary_size = strlen((char*)post_data_start); + } + else + { + console_log("web error: HTTP POST start bound field not found."); + ret = UPLOAD_FATAL; + } + + /* Verify that a filename has been entered. */ + if( ret == UPLOAD_OK ) + { + unsigned char *fname = NULL; + while( memcmp( p, "\r\n\r\n", strlen("\r\n\r\n") ) ) + { + if( *p == 'f' && !memcmp( p, "filename=", strlen("filename=" ) ) ) + { + p += strlen("filename="); + fname = p + 1; + if( p[0] == '"' && p[1] != '"' ) + { + p++; + while( *p != '"' && *p != '\r' && *p != '\n' ) + p++; + *p = '\0'; + } + else + { + console_log("web error: HTTP POST filename not specified."); + ret = UPLOAD_FAIL_NO_FILENAME; + } + break; + } + + p++; + } + + if( fname == NULL ) + { + console_log("web error: HTTP POST filename field not found."); + ret = UPLOAD_FATAL; + } + } + + /* Find the start of the image which starts after two consecutive + * carriage return, linefeed pairs. + */ + if( ret == UPLOAD_OK ) + { + while( memcmp( p, "\r\n\r\n", strlen("\r\n\r\n") ) ) + p++; + + p += strlen("\r\n\r\n"); + if( p[0] != '\r' || p[1] != '\n' || + memcmp(p + 2, post_data_start, boundary_size ) ) + { + *image_start_ptr = p; + } + else + { + console_log("web error: HTTP POST no image data."); + ret = UPLOAD_FAIL_ILLEGAL_IMAGE; + } + } + + /* Find the end of the image which contains the same boundary field as + * at the start of the buffer. + */ + if( ret == UPLOAD_OK ) + { + p = post_data_start + post_data_length - 1; + while( *p == '\r' || *p == '\n' || *p == '-' ) + p--; + p[1] = '\0'; + p -= boundary_size + 1; + if( !memcmp( p + strlen("\r\n"), post_data_start, boundary_size ) ) + *image_len_ptr = (int) p - (int) *image_start_ptr; + else + { + console_log("web error: HTTP POST end bound field not found."); + ret = UPLOAD_FATAL; + } + } + + /* Verify that the image is (or should be) a Broadcom flash format file or + * a flash image format. + */ + if( ret == UPLOAD_OK ) + { + /* Align the image on a 16 byte boundary */ + if( ((unsigned long) *image_start_ptr & 0x0f) != 0 ) + { + unsigned char *dest = (unsigned char *) + ((unsigned long) *image_start_ptr & ~0x0f); + unsigned char *src = *image_start_ptr; + memmove( dest, src, *image_len_ptr ); + *image_start_ptr = dest; + } + + /* Check if the first part of the image is the Broadcom defined TAG + * record. + */ + if( verifyTag( (FILE_TAG *) *image_start_ptr, 0 ) == -1 ) + { + /* It is not a Broadcom flash format file. Now check if it is a + * flash image format file. A flash image format file must have a + * CRC at the end of the image. + */ + unsigned char *image_ptr = *image_start_ptr; + unsigned long image_len = (unsigned long) *image_len_ptr - TOKEN_LEN; + unsigned long crc = CRC32_INIT_VALUE; + + crc = getCrc32(image_ptr, image_len, crc); + if (memcmp(&crc, image_ptr + image_len, CRC_LEN) == 0) + { + console_log("web info: Upload %lu bytes, flash image format.", + *image_len_ptr); + *image_format_ptr = FLASH_IMAGE_FORMAT; + } + else + { + console_log("web info: Upload %lu bytes, invalid image format.", + *image_len_ptr); + ret = UPLOAD_FAIL_ILLEGAL_IMAGE; + } + } + else + { + console_log("web info: Upload %lu bytes, Broadcom image format.", + *image_len_ptr); + *image_format_ptr = BROADCOM_IMAGE_FORMAT; + } + } + + return( ret ); +} /* parse_post_data */ + + +/*************************************************************************** + * Function Name: send_error + * Description : This function sends an HTTP error response to the browser. + * Returns : None. + ***************************************************************************/ +static void send_error( int s, int status, char* title, char* extra_header, + char* text ) +{ + int tcpret = 0; + char buf[128]; + send_headers( s, status, title, extra_header, "text/html" ); + sprintf( (char *) buf, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n" + "<BODY BGCOLOR=\"#cc9999\"><H4>%d %s</H4>\n", status, title, status, + title ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + sprintf( (char *) buf, "%s\n", text ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + sprintf( (char *) buf, "<HR>\n<ADDRESS><A HREF=\"%s\">%s</A></ADDRESS>\n" + "</BODY></HTML>\n", SERVER_URL, SERVER_NAME ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + + if( tcpret < 0 ) + console_log("web error: TCP write error sending error response."); +} /* send_error */ + + +/*************************************************************************** + * Function Name: send_headers + * Description : This function sends an HTTP response to the browser. + * Returns : None. + ***************************************************************************/ +static void send_headers( int s, int status, char* title, char* extra_header, + char* mime_type ) +{ + int tcpret = 0; + char buf[128]; + unsigned long secs = (unsigned long) cfe_ticks / CFE_HZ; + + sprintf( buf, "%s %d %s\r\n", PROTOCOL, status, title ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + sprintf( buf, "Server: %s\r\n", SERVER_NAME ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + sprintf( buf, "Date: Thu, 01 Jan 1970 %2.2d:%2.2d:%2.2d GMT\r\n", + secs / 3600, (secs % 3600) / 60, secs % 60 ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + if ( extra_header != (char*) 0 ) + { + sprintf( buf, "%s\r\n", extra_header ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + } + if ( mime_type != (char*) 0 ) + { + sprintf( buf, "Content-Type: %s\r\n", mime_type ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + } + sprintf( buf, "Connection: close\r\n\r\n" ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + + if( tcpret < 0 ) + console_log("web error: TCP write error sending header."); +} /* send_headers */ + + +/*************************************************************************** + * Function Name: send_page + * Description : This function sends a web page to the browser. + * Returns : None. + ***************************************************************************/ +static void send_page( int s, char *path, int send_headers_flag, + char **substs, int num_substs ) +{ + PWEB_PAGE_MAP map; + + /* Find the specified web page. */ + for( map = g_web_page_map; map->wp_name; map++ ) + { + if( !strcmp( map->wp_name, path ) ) + { + /* Found the web page. */ + char *p2 = NULL; + char *p = (char *) map->wp_content_buf; + int size = *map->wp_content_size; + int i = 0; + + if( send_headers_flag ) + send_headers( s, 200, "Ok", (char *) 0, map->wp_mime_type ); + + /* Make substitutions. */ + while( i < num_substs && (p2 = strnchr( p, '<', size )) != NULL ) + { + if( p2[1] == '%' ) + { + /* Found a substituion pattern. Send up to that point. */ + if( cfe_web_tcp_send( s, p, (int) (p2 - p) ) < 0 ) + break; + + /* Send substitution value. */ + if( cfe_web_tcp_send( s, substs[i], strlen(substs[i]) ) < 0 ) + break; + + i++; + + /* Skip to end of substitution pattern. */ + p = p2 + 2; /* skip '<%' */ + while( p[0] != '%' || p[1] != '>' ) + p++; + p += 2; /* skip '%.' */ + } + else + { + /* Was not a substitution pattern. Send up that point. */ + p2++; + if( cfe_web_tcp_send( s, p, (int) (p2 - p) ) < 0 ) + break; + + p = p2; + } + + size = *map->wp_content_size - ((int)p-(int)map->wp_content_buf); + } + + /* Send remaining part of web page after the last substitution. */ + cfe_web_tcp_send( s, p, size ); + + break; /* for loop */ + } + } + + if( map->wp_name == NULL ) + send_error( s, 404, "Not Found", (char*) 0, "File not found." ); +} /* send_page */ + + +/*************************************************************************** + * Function Name: cfe_web_tcp_send + * Description : Sends data on a TCP non blocking connection and waits for + * it to finish. + * Returns : > 0 - bytes send, < 0 - TCP error + ***************************************************************************/ +static int cfe_web_tcp_send( int s, char *buf, int size ) +{ + int i, len = 0; + + for( i = 0; i < size; i += len ) + { + POLL(); + cfe_web_listen( &g_listen_idx ); + len = tcp_send( s, (unsigned char*)(buf + i), size - i ); + if( len < 0 ) + { + console_log("web error: TCP write error sending a web page."); + break; + } + } + + return( len ); +} /* cfe_web_tcp_send */ + + +/** + * memmove - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * Unlike memcpy(), memmove() copes with overlapping areas. + */ +void * memmove(void * dest,const void *src,size_t count) +{ + char *tmp, *s; + + if (dest <= src) { + tmp = (char *) dest; + s = (char *) src; + while (count--) + *tmp++ = *s++; + } + else { + tmp = (char *) dest + count; + s = (char *) src + count; + while (count--) + *--tmp = *--s; + } + + return dest; +} + +#else + +/*************************************************************************** + * Function Name: Functions stubs. + * Description : Used when the web server is not compiled into the CFE. + * Returns : None. + ***************************************************************************/ + +int cfe_web_check(void); +void cfe_web_fg_process(void); +void cfe_web_poll(void *x); + +int cfe_web_check(void) +{ + return(0); +} + +void cfe_web_fg_process(void) +{ +} + +void cfe_web_poll(void *x) +{ +} + +#endif + |