//-----------------------------------------------------------------------------
// Net HTTP.C
//
// This module is the Web Server
// It currently serves a html text page and a jpeg image, or handles
// a POST message to turn an LED on or off.
// The HTTP protocol specification is at http://www.w3.org/Protocols/
//-----------------------------------------------------------------------------
#include
#include
#include // toupper
#include "main.h" // toupper
#include "rs232.h" // toupper
#include "tcp.h" // toupper
#include "http.h" // toupper
#include "ip.h" // toupper
#include "WebData.h"
// These structures keep track of connection information
bit CONTROL_LED;
void LightONOFF(bit b);
/*********************************************************************
函数名: void ResetSystem(void)
功能: 复位系统
输入: None
输出: None
返回: TRUE or FALSE
日期: 2004/02/09
*********************************************************************/
void LightONOFF(bit b)
{
if (b)
{
TEST_LED = 0;
}
else
{
TEST_LED = 1;
}
}
/*********************************************************************
函数名: void ResetSystem(void)
功能: 复位系统
输入: None
输出: None
返回: TRUE or FALSE
日期: 2004/02/09
*********************************************************************/
void init_http(void)
{
CONTROL_LED = 0;
LightONOFF(CONTROL_LED);
}
/*********************************************************************
函数名: UWORK8 FlashCheck(void)
功能: 把整形转成ASCII的字符串
输入: none
输出: None
返回: none
日期: 2005/11/19
注意:最少为12个字节
*********************************************************************/
char *itoa(UWORK16 value, char * buf, UWORK8 radix)
{
UWORK16 i;
char * ptr;
char * temphold;
temphold = buf;
ptr = buf + 12;
*--ptr = 0; // Insert NULL char
do
{
i = (value % radix) + 0x30; // First create string in reverse order
if(i > 0x39) i += 7;
*--ptr = i;
value = value / radix;
} while(value != 0);
for( ; (*buf++ = *ptr++); ); // Next, move the string 6 places to the left Include NULL character
return(temphold);
}
//------------------------------------------------------------------------
// This function is the standard string search. The Keil library
// does not provide it. It looks for one string in another string
// and returns a pointer to it if found, otherwise returns NULL.
//------------------------------------------------------------------------
char * strstr(char * haystack, char * needle)
{
char *ptr1, *ptr2;
// Protect against NULL pointer
if (*needle == 0) return(haystack);
for( ; *haystack; haystack++ )
{
// Look for needle in haystack. If there is a
// match then this will continue all the way
// until ptr1 reaches the NULL at the end of needle
for(ptr1 = needle, ptr2 = haystack; *ptr1 && (*ptr1 == *ptr2); ++ptr1, ++ptr2);
// If there is a match then return pointer to needle in haystack
if(*ptr1 == 0) return(haystack);
}
return NULL; // no matching string found
}
//------------------------------------------------------------------------
// This sends an TCP segment to the ip layer. The segment is
// is normally either a web page or a graphic.
// See "TCP/IP Illustrated, Volume 1" Sect 17.3
//------------------------------------------------------------------------
void http_send(UWORK16 flags, UWORK8 *TData, UWORK16 TLen, UWORK8 nr)
{
ST_TCP_FORMAT *strTcp;
UWORK8 destIP_buf[4];
UWORK16 TCPHead_len;
UWORK8 *TempD;
TempD = TData;
TCPHead_len = 20;
strTcp = (ST_TCP_FORMAT *)&NetSend_buf[20];
strTcp->usSourcePort = SourcePort; //源端口
strTcp->usDesPort = StrConnection_buf[nr].usDesPort; //目标端口,在接收TCP时已附值
strTcp->ucSERIESNUM = StrConnection_buf[nr].ucSERIESNUM; //序号为0
strTcp->ucTRUECODE = StrConnection_buf[nr].ucTRUECODE; //确认号为0
memcpy(destIP_buf,(UWORK8 *)&StrConnection_buf[nr].ipaddr, 4); //发送的目标IP地址在TCP接收中已附值
strTcp->ucMOVENUM = (TCPHead_len strTcp->ucWINDOWBIG = 1024; //设置窗口大小
strTcp->ucTCPCHECK = 0; //先设置校验位为0
strTcp->ucMUSGPOINT = 0; //紧急指针为0
memcpy((UWORK8 *)&NetSend_buf[(20 + TCPHead_len)], TData, TLen); //把发送的数据传到发送缓存中
//下面是给IP打包头
gstIphead.ucVerAndLen = 0x45; //版本号和长度,各占4位
gstIphead.ucDs = 0; //区分服务
gstIphead.usTotalLen = IP_HEAD_LEN + TCPHead_len + TLen; //头加后面的数据
gstIphead.usID = ++LocalIpID;
gstIphead.usSegOffset = 0;
gstIphead.ucTTL = 0; // max hops
gstIphead.ucprotocol = TCP;
gstIphead.usCheckSum = TCPHead_len + TLen; //在计算TCP的校验位时,TCP的长度要算两次,此时是借IP的校验位来做第二个TCP的长度
memcpy(&gstIphead.ucDestIP[0],&IPDestAddress_buf[0],IP_LEN); // 目的IP
memcpy(&gstIphead.ucSourceIP[0],&IPLocalAddress_buf[0],IP_LEN); // 源IP
memcpy(&NetSend_buf[0],&gstIphead,20); //把IP的头传给发送缓存区
strTcp->ucTCPCHECK = 0;
strTcp->ucTCPCHECK = CheckSum((UWORK16 *)&NetSend_buf[8],TCPHead_len + TLen + 12); // 20 = 12个字节伪头 + 8个字节UDP头
gstIphead.ucTTL = 0x20; //校验和计算完毕,重赋TTL值
memcpy(&MAC_Remote_buf[0],&gstaRevEthernet.ucaSourceNodID[0],MAC_LEN); // 目的MAC
// memcpy((UWORK8 *)&MAC_Remote_buf[4],&gstaRevEthernet.ucaDestNodID[0],MAC_LEN); // 目的MAC
// memcpy(&MAC_Remote_buf[0],&ArpCache_Buf[0].ucaMAC[0],MAC_LEN); // 远程MAC
IpSend();
// (Re)start TCP retransmit timer
StrConnection_buf[nr].timer = TCP_TIMEOUT;
StrConnection_buf[nr].ucRESERIESNUM = StrConnection_buf[nr].ucSERIESNUM;
}
//------------------------------------------------------------------------
// This searches a web page looking for a specified tag. If found,
// it replaces the tag with the text in * sub. Tags are fixed length -
// The first 4 chars of the tag is always "TAG:" and the rest of it
// is always 4 chars for a total of 8 chars.
//------------------------------------------------------------------------
void replace_tag(UWORK8 xdata * start, char * tag, char * sub)
{
UWORK8 idata i, flg;
UWORK8 xdata * ptr;
// Find tag. If not found - just return
ptr = strstr(start, tag);
if (ptr == NULL) return;
flg = TRUE;
// Replace the 8 char tag with the substitute text
// Pad on the right with spaces
for (i=0; i < 8; i++)
{
if (sub[i] == 0) flg = FALSE;
if (flg) ptr[i] = sub[i]; else ptr[i] = SPACE;
}
}
//------------------------------------------------------------------------
// This serves up either a HTML page, a JPEG image, or controls an
// LED, depending what it gets from the browser. The received header
// must contain the word "GET" or "POST" to be considered a valid request.
// With HTTP 1.1 where the connection is left open, the header I send
// should include content length. With HTTP 1.0 you can just close the
// connection after sending the page and the browser knows its done.
//
// The HTTP protocol specification is at http://www.w3.org/Protocols/
//------------------------------------------------------------------------
//------------------------------------------------------------------------
// This serves up either a HTML page, a JPEG image, or controls an
// LED, depending what it gets from the browser. The received header
// must contain the word "GET" or "POST" to be considered a valid request.
// With HTTP 1.1 where the connection is left open, the header I send
// should include content length. With HTTP 1.0 you can just close the
// connection after sending the page and the browser knows its done.
//
// The HTTP protocol specification is at http://www.w3.org/Protocols/
//------------------------------------------------------------------------
UWORK16 http_server(UWORK8 nr, UWORK8 reSendFlag)
{
UWORK16 idata body_len, hhdr_len, jhdr_len, page_len, jpeg_len;
UWORK16 idata sent, remaining;
UWORK8 xdata * outbuf;
UWORK8 xdata * ptr;
UWORK8 xdata * tcp_data;
UWORK8 idata request;
UWORK16 TCPheader_len, data_len, Total_len;
ST_IP_HEAD_FORMAT StrIp;
ST_TCP_FORMAT strTcp;
static UWORK8 idata post_flg = FALSE;
if(FALSE == gbHaveFragment)
{ // 没有分片的数据
memcpy((UWORK8 *)&StrIp.ucVerAndLen, (UWORK8 *)&gstaRevEthernet.ucaPacket[0], 20); //读取IP头数据
memcpy((UWORK8 *)&strTcp.usSourcePort, (UWORK8 *)&gstaRevEthernet.ucaPacket[20], 20); //读取TCP头数据
}
else
{ // 分片的数据
memcpy((UWORK8 *)&StrIp.ucVerAndLen, (UWORK8 *)&gucaSegTemp[0], 20); //读取IP头数据
memcpy((UWORK8 *)&strTcp.usSourcePort, (UWORK8 *)&gucaSegTemp[20], 20); //读取TCP头数据
}
Total_len = StrIp.usTotalLen;
Total_len -= 20; //长度是IC的总数据长度减去IP头的长度。其实就是IP数据包的长度.
TCPheader_len = (strTcp.ucMOVENUM & 0xF000) >> 10; //记算TCP头的长度 data_len = Total_len - TCPheader_len; //len在上面已算过是总个TCP的长度
tcp_data = &gstaRevEthernet.ucaPacket[20 + TCPheader_len];
if (nr == NO_CONNECTION) return 0; //表示没有连上
if (!reSendFlag) //发果不是重复发送
{
StrConnection_buf[nr].ucRESERIESNUM = StrConnection_buf[nr].ucSERIESNUM;
}
else
{
StrConnection_buf[nr].ucSERIESNUM = StrConnection_buf[nr].ucRESERIESNUM;
}
request = NONE;
if (strstr(tcp_data, "POST") != NULL)
{
post_flg = TRUE;
}
else if (strstr(tcp_data, "GET") != NULL) //See if this is a GET message
{
post_flg = FALSE;
if (strstr(tcp_data, "photo1") != NULL)
{
request = GET_JPEG;
}
else if (strstr(tcp_data, "index") != NULL)
{
request = GET_PAGE;
}
else if(strstr(tcp_data, "/ ") != NULL)
{
request = GET_PAGE;
}
}
// If POST flag is "armed" then look for the "switch=" string
// and if found, turn the LED on or off according to whether
// the browser is sending a 1 or a 0.
if (post_flg)
{
ptr = strstr(tcp_data, "switch=");
if (ptr != NULL)
{
// Move to space after equals sign
// Set control indicator accordingly
post_flg = FALSE;
request = POST_PAGE;
ptr += 7;
if (*ptr == '1')
{
CONTROL_LED=0x0;
}
else if (*ptr == '0')
{
CONTROL_LED=0x1;
}
LightONOFF(CONTROL_LED);
}
}
if ((request == GET_PAGE) || (request == POST_PAGE))
{
// Figure out sizes
hhdr_len = strlen(html_header);
page_len = strlen(web_page);
body_len = hhdr_len + page_len;
memcpy(&NetSend_buf[40], html_header, hhdr_len);
memcpy(&NetSend_buf[40 + hhdr_len], web_page, page_len);
NetSend_buf[40 + body_len] = 0; // Append NULL
// Replace length tag with actual value
itoa(page_len, text, 10);
replace_tag(&NetSend_buf[40], "TAG:LEN1", text);
// Insert the word CHECKED into the html so the browser will
// check the correct LED state indicator box
if (CONTROL_LED == ON)
{
replace_tag(&NetSend_buf[40], "TAG:CHK1", "CHECKED");
}
else
{
replace_tag(&NetSend_buf[40], "TAG:CHK2", "CHECKED");
}
http_send(FLG_ACK | FLG_PSH, &NetSend_buf[40], body_len, nr);
// StrConnection_buf[nr].ucSERIESNUM += body_len;
}
else if (request == GET_JPEG)
{
// Ths browser has requested the jpeg image. First figure out
// sizes - cannot use sizeof() for jpeg here because it is in
// another module. Just directly specify length of it
jhdr_len = strlen(jpeg_header);
jpeg_len = 5705;//6194;
body_len = jhdr_len + jpeg_len;
// Free memory holding received message. The message from the
// browser can be 500+ bytes long so this is a significant
// chunk out of the available malloc space of 1500 bytes
// First send the header and enough of the jpeg to make 1000 bytes.
// The value of 1000 is arbitrary, but must be stay under 1500.
if (body_len < 1000) //数据长度大于1000要分片
{
remaining = body_len;
}
else
{
remaining = 1000;
}
memcpy(&NetSend_buf[40], jpeg_header, jhdr_len);
memcpy(&NetSend_buf[40 + jhdr_len], photo1_jpeg, remaining - jhdr_len);
NetSend_buf[40 + remaining] = 0; // Append NULL
itoa(jpeg_len, text, 10); // Replace jpeg length tag with actual value
replace_tag(outbuf + 54, "TAG:LEN2", text);
http_send(FLG_ACK | FLG_PSH, &NetSend_buf[40], remaining, nr);
sent = remaining - jhdr_len;
StrConnection_buf[nr].ucSERIESNUM += remaining;
// Send the rest of the jpeg file in 1000 byte chunks. This sends about
// 6 segments of 1000 bytes back to back, but we should actually process
// acks from the other end to make sure we are not sending more than the
// other end can receive. Most systems can handle 6K
while (sent < jpeg_len) //如发送的数据小于图片长度
{
remaining = jpeg_len - sent;
if (remaining > 1000) remaining = 1000;
memcpy(&NetSend_buf[40], photo1_jpeg + sent, remaining);
NetSend_buf[40 + remaining] = 0; // Append NULL
http_send(FLG_ACK | FLG_PSH, &NetSend_buf[40], remaining, nr);
sent += remaining;
StrConnection_buf[nr].ucSERIESNUM += remaining;
}
}
StrConnection_buf[nr].HttpFlag = TCP_HTTP;
return(body_len); // Return number of bytes sent, not including TCP header
}