FPGA / ARM / DSP Wishbone SoC


< WB+LINUX+USB+TCPIP+WEBServer >

 

 

 

 

Lab5 : Linux 2.6.26 mini-Web Server

 

 

 

Introduction

 

  

Lab.5本實驗在ARM9 Linux Kernel, 應用ARM週邊模組的Ethernet Controller與Linux核心的 protocal stack與檔案系統, 進行以TCP/IP為基礎的簡單版Web Server應用


實驗是修改自IBM的範例程式, 如同一般Web page browsing, 以Client/Server的形式, Client端級是PC Windows/Linux或其他具有Browser的裝置,Server端為ZX Integrator實驗器


Client端Browser發送讀取網頁資料要求後, Server端的ZX Integrator 再簡單的解譯後, 讀取Client端要求的檔案, 透過所建立的TCP/IP Socket回傳給Client, 供Client端的Browser 顯示


(後面的章節將示範:基於Server side dynamic web page的Web based control 應用,*編寫中)


 

Design Codes

 

  nweb.c

 

 

 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <errno.h>

#include <string.h>

#include <fcntl.h>

#include <signal.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

 

#define BUFSIZE 8096

#define ERROR 42

#define SORRY 43

#define LOG   44

 

struct {

     char *ext;

     char *filetype;

} extensions [] = {

     {"gif", "image/gif" }, 

     {"jpg", "image/jpeg"},

     {"jpeg","image/jpeg"},

     {"png", "image/png" }, 

     {"zip", "image/zip" }, 

     {"gz",  "image/gz"  }, 

     {"tar", "image/tar" }, 

     {"htm", "text/html" }, 

     {"html","text/html" }, 

     {0,0} };

 

void log(int type, char *s1, char *s2, int num)

{

     int fd ;

     char logbuffer[BUFSIZE*2];

 

     switch (type) {

     case ERROR: (void)sprintf(logbuffer,"ERROR: %s:%s Errno=%d exiting pid=%d",s1, s2, errno,getpid()); break;

     case SORRY:

         (void)sprintf(logbuffer, "<HTML><BODY><H1>nweb Web Server Sorry: %s %s</H1></BODY></HTML>\r\n", s1, s2);

         (void)write(num,logbuffer,strlen(logbuffer));

         (void)sprintf(logbuffer,"SORRY: %s:%s",s1, s2);

         break;

     case LOG: (void)sprintf(logbuffer," INFO: %s:%s:%d",s1, s2,num); break;

     }   

     /* no checks here, nothing can be done a failure anyway */

     if((fd = open("nweb.log", O_CREAT| O_WRONLY | O_APPEND,0644)) >= 0) {

         (void)write(fd,logbuffer,strlen(logbuffer));

         (void)write(fd,"\n",1);     

         (void)close(fd);

     }

     if(type == ERROR || type == SORRY) exit(3);

}

 

/* this is a child web server process, so we can exit on errors */

void web(int fd, int hit)

{

     int j, file_fd, buflen, len;

     long i, ret;

     char * fstr;

     static char buffer[BUFSIZE+1]; /* static so zero filled */

 

     ret =read(fd,buffer,BUFSIZE);   /* read Web request in one go */

     if(ret == 0 || ret == -1) { /* read failure stop now */

         log(SORRY,"failed to read browser request","",fd);

     }

     if(ret > 0 && ret < BUFSIZE)    /* return code is valid chars */

         buffer[ret]=0;         /* terminate the buffer */

     else buffer[0]=0;

 

     for(i=0;i<ret;i++) /* remove CF and LF characters */

         if(buffer[i] == '\r' || buffer[i] == '\n')

              buffer[i]='*';

     log(LOG,"request",buffer,hit);

 

     if( strncmp(buffer,"GET ",4) && strncmp(buffer,"get ",4) )

         log(SORRY,"Only simple GET operation supported",buffer,fd);

 

     for(i=4;i<BUFSIZE;i++) { /* null terminate after the second space to ignore extra stuff */

         if(buffer[i] == ' ') { /* string is "GET URL " +lots of other stuff */

              buffer[i] = 0;

              break;

         }

     }

 

     for(j=0;j<i-1;j++)     /* check for illegal parent directory use .. */

         if(buffer[j] == '.' && buffer[j+1] == '.')

              log(SORRY,"Parent directory (..) path names not supported",buffer,fd);

 

     if( !strncmp(&buffer[0],"GET /\0",6) || !strncmp(&buffer[0],"get /\0",6) ) /* convert no filename to index file */

         (void)strcpy(buffer,"GET /index.html");

 

     /* work out the file type and check we support it */

     buflen=strlen(buffer);

     fstr = (char *)0;

     for(i=0;extensions[i].ext != 0;i++) {

         len = strlen(extensions[i].ext);

         if( !strncmp(&buffer[buflen-len], extensions[i].ext, len)) {

              fstr =extensions[i].filetype;

              break;

         }

     }

     if(fstr == 0) log(SORRY,"file extension type not supported",buffer,fd);

 

     if(( file_fd = open(&buffer[5],O_RDONLY)) == -1) /* open the file for reading */

         log(SORRY, "failed to open file",&buffer[5],fd);

 

     log(LOG,"SEND",&buffer[5],hit);

 

     (void)sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: %s\r\n\r\n", fstr);

     (void)write(fd,buffer,strlen(buffer));

 

     /* send file in 8KB block - last block may be smaller */

     while (  (ret = read(file_fd, buffer, BUFSIZE)) > 0 ) {

         (void)write(fd,buffer,ret);

     }

#ifdef LINUX

     sleep(1);     /* to allow socket to drain */

#endif

     exit(1);

}

 

 

int main(int argc, char **argv)

{

     int i, port, pid, listenfd, socketfd, hit;

     size_t length;

     static struct sockaddr_in cli_addr; /* static = initialised to zeros */

     static struct sockaddr_in serv_addr; /* static = initialised to zeros */

 

     if( argc < 3  || argc > 3 || !strcmp(argv[1], "-?") ) {

         (void)printf("hint: nweb Port-Number Top-Directory\n\n"

     "\tnweb is a small and very safe mini web server\n"

     "\tnweb only servers out file/web pages with extensions named below\n"

     "\t and only from the named directory or its sub-directories.\n"

     "\tThere is no fancy features = safe and secure.\n\n"

     "\tExample: nweb 8181 /home/nwebdir &\n\n"

     "\tOnly Supports:");

         for(i=0;extensions[i].ext != 0;i++)

              (void)printf(" %s",extensions[i].ext);

 

         (void)printf("\n\tNot Supported: URLs including \"..\", Java, Javascript, CGI\n"

     "\tNot Supported: directories / /etc /bin /lib /tmp /usr /dev /sbin \n"

     "\tNo warranty given or implied\n\tNigel Griffiths nag@uk.ibm.com\n"

             );

         exit(0);

     }

     if( !strncmp(argv[2],"/"   ,2 ) || !strncmp(argv[2],"/etc", 5 ) ||

         !strncmp(argv[2],"/bin",5 ) || !strncmp(argv[2],"/lib", 5 ) ||

         !strncmp(argv[2],"/tmp",5 ) || !strncmp(argv[2],"/usr", 5 ) ||

         !strncmp(argv[2],"/dev",5 ) || !strncmp(argv[2],"/sbin",6) ){

         (void)printf("ERROR: Bad top directory %s, see nweb -?\n",argv[2]);

         exit(3);

     }

     if(chdir(argv[2]) == -1){

         (void)printf("ERROR: Can't Change to directory %s\n",argv[2]);

         exit(4);

     }

 

     /* Become deamon + unstopable and no zombies children (= no wait()) */

     if(fork() != 0)

         return 0; /* parent returns OK to shell */

     (void)signal(SIGCLD, SIG_IGN); /* ignore child death */

     (void)signal(SIGHUP, SIG_IGN); /* ignore terminal hangups */

     for(i=0;i<32;i++)

         (void)close(i);        /* close open files */

     (void)setpgrp();       /* break away from process group */

 

     log(LOG,"nweb starting",argv[1],getpid());

     /* setup the network socket */

     if((listenfd = socket(AF_INET, SOCK_STREAM,0)) <0)

         log(ERROR, "system call","socket",0);

     port = atoi(argv[1]);

     if(port < 0 || port >60000)

         log(ERROR,"Invalid port number (try 1->60000)",argv[1],0);

     serv_addr.sin_family = AF_INET;

     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

     serv_addr.sin_port = htons(port);

     if(bind(listenfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0)

         log(ERROR,"system call","bind",0);

     if( listen(listenfd,64) <0)

         log(ERROR,"system call","listen",0);

 

     for(hit=1; ;hit++) {

         length = sizeof(cli_addr);

         if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)

              log(ERROR,"system call","accept",0);

 

         if((pid = fork()) < 0) {

              log(ERROR,"system call","fork",0);

         }

         else {

              if(pid == 0) {    /* child */

                  (void)close(listenfd);

                  web(socketfd,hit); /* never returns */

              } else { /* parent */

                  (void)close(socketfd);

              }

         }

     }

}

 

 

 

 

  Makefile

 

 

 

GNUARM = /usr/local/arm/3.4.1/bin/

NAME = nweb

CC = $(GNUARM)arm-linux-gcc

LD = $(GNUARM)arm-linux-ld -v

AR = $(GNUARM)arm-linux-ar

AS = $(GNUARM)arm-linux-as

CP = $(GNUARM)arm-linux-objcopy

OD = $(GNUARM)arm-linux-objdump

 

CFLAGS =

AFLAGS = -ahls -mapcs-32

LFLAGS = -Map $(NAME).map -T$(NAME).ld

CPFLAGS = --output-target=binary

ODFLAGS = -x --syms -D

 

 

all: $(NAME)

 

clean:

     -rm $(NAME)

 

 

 

$(NAME): $(NAME).c

     @ echo ".compiling"

     $(CC) $(CFLAGS) -o $@ $^

 

 

 

 

 

 

 

 

 

 

 

 

 

 

文章標籤
全站熱搜
創作者介紹
創作者 zeppe 的頭像
zeppe

ZEPPE

zeppe 發表在 痞客邦 留言(0) 人氣(166)