⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 webserve.c

📁 开源的嵌入式WEB服务器
💻 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 + -