📄 webserve.c
字号:
/* Web Server for 'TCP/IP Lean' (c) Iosoft Ltd. 2000
This software is only licensed for distribution with the book 'TCP/IP Lean',
and may only be used for personal experimentation by the purchaser
of that book, on condition that this copyright notice is retained.
For commercial licensing, contact license@iosoft.co.uk
This is experimental software; use it entirely at your own risk. The author
offers no warranties of any kind, including its fitness for purpose. */
/*
** v0.01 JPB 20/3/00 Derived from Telnet v0.12
** v0.02 JPB 23/3/00 Used function upcall ptrs in TCP.C and IP.C
** v0.03 JPB 11/4/00 Added HTTP header type selection
** v0.04 JPB 12/4/00 Added clickable HTML directory
** v0.05 JPB 13/4/00 Added state machine to handle large directories
** v0.06 JPB 15/4/00 Return directory only if null filename
** Return error response if file not found
** v0.07 JPB 3/7/00 Changed default config file to TCPLEAN.CFG
** Revised header for book CD
*/
#define VERSION "0.07"
/* HTTP response header: 0=none, 1=simple OK, 2=content-type */
#define HTTP_HEAD 2
/* Directory type: 0=text, 1=simple HTML, 2=table, 3=large dir support */
#define HTML_DIR 3
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <stdarg.h>
#include "ether.h"
#include "netutil.h"
#include "net.h"
#include "ip.h"
#include "tcp.h"
#include "uart.h"
#include "fs.h"
#include "timer.h"
#define HTTP_OK "HTTP/1.1 200 OK\r\n"
#define HTTP_NOFILE "HTTP/1.1 404 Not found\r\n"
#define HTTP_HTM "Content-type: text/html\r\n"
#define HTTP_TXT "Content-type: text/plain\r\n"
#define HTTP_GIF "Content-type: image/gif\r\n"
#define HTTP_XBM "Content-type: image/x-xbitmap\r\n"
#define HTTP_JAVA "Content-type: application/java\r\n"
#define HTTP_CLOSE "Connection: close\r\n"
#define HTTP_BLANK "\r\n"
#define HTTP_MAXLEN 80
GENFRAME genframe; /* Frame for network Tx/Rx */
extern BYTE bcast[MACLEN]; /* Broadcast Ethernet addr */
NODE locnode; /* My Ethernet and IP addresses */
int breakflag; /* Flag to indicate ctrl-break pressed */
char httpreq[HTTP_MAXLEN+1]; /* Buffer for first part of HTTP request */
/* Debug flags */
extern int netdebug; /* Verbose packet display */
extern int tcpdebug; /* TCP frame display */
extern int statedebug; /* TCP state display */
int webdebug; /* Web (HTTP) diagnostic display */
extern LWORD ticks;
extern TIME tm0;
extern DATA_FILE *FS_ROOT;
/* Socket storage */
#define NSOCKS 5
TSOCK tsocks[NSOCKS] = /* Initialise index num and buffer sizes */
{
{1,{_CBUFFLEN_},{_CBUFFLEN_}},
{2,{_CBUFFLEN_},{_CBUFFLEN_}},
{3,{_CBUFFLEN_},{_CBUFFLEN_}},
{4,{_CBUFFLEN_},{_CBUFFLEN_}},
{5,{_CBUFFLEN_},{_CBUFFLEN_}},
};
/* Application-specific storage */
typedef struct {
DATA_FILE *in;
long count; /* State variable/counter */
} APPDATA;
APPDATA appdata[NSOCKS];
/* Function pointers: upcalls from TCP/IP stack */
extern NODE *(*get_locnode_n)(int n); /* Get local node */
extern int (*server_upcall)(TSOCK *ts, CONN_STATE conn);/* TCP server action */
extern volatile char MyMacSrcAddr[6] ;
/* Prototypes */
WORD read_netconfig(char *fname, NODE *np);
NODE *locnode_n(int n);
int server_action(TSOCK *ts, CONN_STATE conn);
int tcp_echo(TSOCK *ts, CONN_STATE conn);
void http_get(TSOCK *ts, char *fname);
void http_data(TSOCK *ts,CONN_STATE conn);
int dir_head(CBUFF *bp, char *path);
int dir_entry(CBUFF *bp, char *name);
int dir_tail(CBUFF *bp);
void do_receive(GENFRAME *gfp);
void do_poll(GENFRAME *gfp);
int buff_inprintf(CBUFF *bp, char *str, ...);
void disp_usage(void);
void break_handler(int sig);
void web_test()
{
int i;
char temps[18];
GENFRAME *gfp;
LWORD time; // LWORD mstimer;
locnode.dtype=0; //以太网
for(i=0;i<MACLEN;i++)
locnode.mac[i]=MyMacSrcAddr[i];
locnode.ip=10; //ip 10.11.112.5
locnode.ip=(locnode.ip<<8)+11;
locnode.ip=(locnode.ip<<8)+112;
locnode.ip=(locnode.ip<<8)+5;
locnode.mask=255; //mask 255.255.255.0
locnode.mask=(locnode.mask<<8)+255;
locnode.mask=(locnode.mask<<8)+255;
locnode.mask=(locnode.mask<<8)+255;
locnode.mask=(locnode.mask<<8)+0;
locnode.gate=10; //gate 10.11.112.1
locnode.gate=(locnode.gate<<8)+11;
locnode.gate=(locnode.gate<<8)+112;
locnode.gate=(locnode.gate<<8)+1;
printf("Ready for WEBSERVE \n"); /* Sign on */
printf("Please send email to bookworm01@sohu.com,if you have any problem.\n");
printf("Ren Daqian\n");
printf("the department of mechanical engineering\n");
printf("Zhejiang University.\n");
genframe.g.dtype =locnode.dtype; /* Set frame driver type */
gfp = &genframe; /* Get pointer to frame */
printf("IP %s", ipstr(locnode.ip, temps));
printf(" mask %s", ipstr(locnode.mask, temps));
if (locnode.gate)
printf(" gate %s", ipstr(locnode.gate, temps));
if (locnode.dtype & DTYPE_ETHER)
printf(" Ethernet %s", ethstr(locnode.mac, temps));
for (i=0; i<NSOCKS; i++) //初始化socket
tsocks[i].app = &appdata[i];
get_locnode_n = locnode_n; /* Set upcall func ptrs */
server_upcall = server_action;
statedebug =0;//1; /* display TCP states */
tcpdebug = 0;//1; /* display TCP segments */
netdebug |= 1; /* verbose packet display */
webdebug = 1; /* Web (HTTP) diagnostics */
netdebug |= 2; /* hex packet display */
netdebug =0;
mstimeout(&time,0);//记录当前时间
while (1) /* Main loop.. */
{
do_receive(gfp); /* Receive frames */
do_poll(gfp); /* Poll net drivers */
if(mstimeout(&time,5000))
printf("\ncurrent time is %d:%d:%d.%d", tm0.tm_hour,tm0.tm_min,
tm0.tm_sec,tm0.tm_millisec);
}
}
/* Return ptr to local node 'n' (n=0 for first), return 0 if doesn't exist
** Used by IP functions to get my netmask & gateway addresses */
NODE *locnode_n(int n)
{
return(n==0 ? &locnode : 0);
}
/* Upcall from TCP stack to server when opening, connecting, receiving data
** or closing. Return 0 to prevent connection opening, or close if connected */
int server_action(TSOCK *ts, CONN_STATE conn)
{
int ok=1, len;
WORD port;
char *s, *name;
APPDATA *adp;
port = ts->loc.port;
adp = (APPDATA *)ts->app;
if (port != HTTPORT)
ok = 0;
else if (conn == TCP_OPEN)
{
adp->in = 0;
}
else if (conn == TCP_DATA)
{
if ((len = buff_chrlen(&ts->rxb, '\n'))!=0) /* Got request? */
{
len = mini(len+1, HTTP_MAXLEN); /* Truncate length */
buff_out(&ts->rxb, (BYTE *)httpreq, (WORD)len);
httpreq[len] = 0;
if (webdebug) /* Display if debugging */
printf("%s", httpreq);
s = strtok(httpreq, " "); /* Chop into tokens */
if (!strcmp(s, "GET")) /* 1st token is 'GET'? */
{
name = strtok(0, " ?\r\n"); /* 2nd token is filename */
http_get(ts, name); /* Process filename */
}
}
}
http_data(ts,conn);
return(ok);
}
/* Process the filepath from an HTTP 'get' method */
void http_get(TSOCK *ts, char *fname)
{
APPDATA *adp;
char *s=0;
DATA_FILE * fp;
adp = (APPDATA *)ts->app;
adp->count =0;
if((fname[0]=='/')&&(fname[1]==NULL)) //GET / 返回目录
{ int i=0;
char * str;
buff_instr(&ts->txb, HTTP_OK);
buff_inprintf(&ts->txb,HTTP_CLOSE);
buff_inprintf(&ts->txb,HTTP_BLANK);
i=buff_instr(&ts->txb, "<html><head><title>Directory</title></head><body>\r\n");
for(fp = FS_ROOT; fp != NULL; fp = (DATA_FILE*)fp->next)
{ str =fp->name;
i=i+buff_inprintf(&ts->txb,"<p><a href=\42%s\42> %s</a>\r\n",str,str);
}
i=i+buff_inprintf(&ts->txb,"</body></html>\r\n");
buff_inprintf(&ts->txb,HTTP_BLANK);
close_tcp(ts); //关闭tcp连接
return;
}
adp->in=fs_open(fname);
if(adp->in !=NULL) //找到文件
{adp->count =(adp->in)->len;
buff_instr(&ts->txb, HTTP_OK);
s=strchr(fname,'.'); //得到文件的扩展名
if ((!strcmp(s, ".html"))||(!strcmp(s, ".htm")))//超文本
buff_instr(&ts->txb,HTTP_HTM);
else if(!strcmp(s, ".class"))
buff_instr(&ts->txb,HTTP_JAVA);
buff_inprintf(&ts->txb, "Content-Length : %d \r\n",adp->count);
buff_inprintf(&ts->txb,HTTP_CLOSE);
buff_inprintf(&ts->txb,HTTP_BLANK);
}
else //找不到文件
{
buff_instr(&ts->txb, HTTP_NOFILE);
buff_inprintf(&ts->txb,HTTP_CLOSE);
buff_inprintf(&ts->txb,HTTP_BLANK);
close_tcp(ts); //关闭tcp连接
}
}
/* If there is space in the transmit buffer, send HTTP data */
void http_data(TSOCK *ts,CONN_STATE conn)
{
APPDATA *adp;
DATA_FILE *file;
int len;
adp = (APPDATA *)ts->app;
if((adp->in)&&((adp->count)>0)) //如果有数据需要传送
{file =adp->in;
len=buff_in(&(ts->txb),&(file->data[file->len-(adp->count)]),adp->count);
//将文件塞进缓冲区
adp->count -=len;
if(adp->count <=0)
close_tcp(ts); //关闭tcp连接
if(tcpdebug)
{printf("Put Tx data in socket(%d) %d -> %d\n",
ts->index, ts->loc.port,ts->rem.port);
printf("%d bytes sent and remain %d bytes.\n",len,adp->count);
}
}
else
{ adp->in=NULL;
adp->count =0;
}
}
/* Write out head of HTML file dir, given filepath. Return 0 if error */
int dir_head(CBUFF *bp, char *path)
{
#if HTML_DIR > 1
return(buff_instr(bp, HTTP_OK HTTP_HTM HTTP_BLANK) &&
buff_instr(bp, "<html><head><title>Directory</title></head>\r\n") &&
buff_inprintf(bp, "<body><h2>Directory of %s</h2>\r\n", path) &&
buff_instr(bp, "<table><th>File</th><th>Size</th>\r\n"));
#else
return(buff_instr(bp, HTTP_OK HTTP_HTM HTTP_BLANK) &&
buff_instr(bp, "<html><head><title>Directory</title></head>\r\n") &&
buff_inprintf(bp, "<body><h2>Directory of %s</h2>\r\n", path));
#endif
}
/* Write out tail of HTML file dir. Return length, 0 if error */
int dir_tail(CBUFF *bp)
{
#if HTML_DIR > 1
return(buff_instr(bp, "</table></body></html>\r\n"));
#else
return(buff_instr(bp, "</body></html>\r\n"));
#endif
}
/* Check for incoming packets, send response if required */
void do_receive(GENFRAME *gfp)
{
NODE node;
ARPKT *arp;
IPKT *ip;
ICMPKT *icmp;
int rxlen, txlen, len;
if ((rxlen=get_frame(gfp)) > 0) /* Any incoming frames? */
{
if(netdebug)
disp_frame(gfp, rxlen, 0); //显示数据包
ip = getframe_datap(gfp);
if (is_arp(gfp, rxlen))
{ /* ARP response? */
arp = getframe_datap(gfp);
swap_arp(gfp);
if (arp->op==ARPREQ && arp->dip==locnode.ip)
{ /* ARP request? */
node.ip = arp->sip; /* Make ARP response */
memcpy(node.mac, arp->smac, MACLEN);
txlen = make_arp(gfp, &locnode, &node, ARPRESP);
put_frame(gfp, txlen); /* Send packet */
if(netdebug)
disp_frame(gfp, txlen, 1); //显示数据包
}
if (arp->op==ARPRESP && arp->dip==locnode.ip)
{ /* ARP response? */
arp_receive(tsocks, NSOCKS, gfp);
}
return;
}
rxlen=is_ip(gfp, rxlen);
if ((rxlen!=0) && /* IP datagram? */
ip->i.dip==locnode.ip || ip->i.dip==BCASTIP)
{
getip_srce(gfp, &node);
if ((len=is_icmp(ip, rxlen))!=0) /* ICMP? */
{
icmp = (ICMPKT *)ip;
if (icmp->c.type==ICREQ) /* Echo request? */
{
len = (WORD)maxi(len, 0); /* Make response */
txlen = make_icmp(gfp, &locnode, &node, ICREP,
icmp->c.code, (WORD)len);
put_frame(gfp, txlen); /* Send packet */
if(netdebug)
disp_frame(gfp, txlen, 1); //显示数据包
}
}
else if ((len=is_tcp(ip, rxlen))!=0) /* TCP? */
{
tcp_receive(tsocks, NSOCKS, gfp, len);
}
}
}
}
/* Poll the network interface to keep it alive */
void do_poll(GENFRAME *gfp)
{
tcp_poll(tsocks, NSOCKS, gfp);
}
/* Version of printf() to write a string into a circular buffer.
** Return string length, or zero if insufficient room in buffer */
int buff_inprintf(CBUFF *bp, char *str, ...)
{
char temps[200];
int len;
va_list argptr;
va_start(argptr, str);
len = vsprintf(temps, str, argptr);
va_end(argptr);
if (len<=0 || len>buff_freelen(bp))
len = 0;
else
buff_in(bp, (BYTE *)temps, (WORD)len);
return(len);
}
/* Display usage help */
/* Ctrl-break handler: set flag and return */
void break_handler(int sig)
{
breakflag = sig;
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -