#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <dirent.h>
#define oops(s) { perror(s); exit(1);}
/* server facts here, plus a mutex for them */
time_t server_started ;
int server_bytes_sent;
int server_requests;
pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER;
/*
* prototypes
*/
static void stats_get(time_t *started, int *bytesp, int *hitsp);
static void stats_add(int bytesamt, int hitsamt);
int setup(int ac, char *av[],pthread_attr_t *attrp);
static void *handle_call(void *fdptr);
static void skip_rest_of_header(FILE *fp);
static void process_rq( char *rq, int fd,struct in_addr caller);
static void sanitize(char *str);
int built_in(char *arg, int fd);
int http_reply(int fd, FILE **fpp, int code, char *msg, char *type, char *content);
static void not_implemented(int fd);
static void do_404(char *item, int fd);
int isadir(char *f);
static int not_exist(char *f);
static void do_ls(char *dir, int fd);
char *file_type(char *f);
static void do_cat(char *f, int fd);
static int ends_in_cgi(char *);
static int in_cgibin(char *);
static void do_exec( char *, int );
int server_log(int , void *);
int logwrite(int , struct in_addr , char *, char *);
void safecpy(char *, char *, int );
int make_server_socket_q(int , int );
int make_server_socket(int );
/*
* Access to the server stats are managed through
* these functions below:
*
* stats_get(time_t *started, int *bytesp, int *hitsp )
* stats_add(int bytesamt, int hitsamt)
*
* These two functions use the mutex to prevent trouble
*/
/* -----------------------------------------------------
* logfile header material. Should be in serverlog.h
*/
#define LOGMODE 0600
#define SL_OPEN 0
#define SL_ADDR 1
#define SL_REQ 2
#define SL_REPLY 3
#define REPLY_MAX 10
#define REQUEST_MAX 200 /* longest request allowed */
/* --- end of serverlog.h ------------ */
#define HOSTLEN 256
#define BACKLOG 1
int main(int ac, char *av[])
{
int sock, fd;
int *fdptr;
pthread_t worker;
pthread_attr_t attr;
int len;
struct sockaddr_in clnt_addr;
if ( ac == 1 ){
fprintf(stderr,"usage: tws portnum\n");
exit(1);
}
sock = setup(ac,av,&attr);
/* main loop here: take call, handle call in new thread */
while(1){
len = sizeof(struct sockaddr);
fd = accept( sock, (struct sockaddr *) &clnt_addr, &len);
if ( fd == -1 && errno == EINTR )//中断函数调用
continue;
if ( fd == -1 )
oops("accept");
stats_add(0,1);
fdptr = malloc(sizeof(int));
*fdptr = fd;
void *arg[2]={fdptr,&clnt_addr.sin_addr};
pthread_create(&worker,&attr,handle_call,arg);
}
return 0;
}
int make_server_socket(int portnum)
{
return make_server_socket_q(portnum, BACKLOG);
}
int make_server_socket_q(int portnum, int backlog)
{
struct sockaddr_in saddr; /* build our address here */
struct hostent *hp; /* this is part of our */
char hostname[HOSTLEN]; /* address */
int sock_id; /* the socket */
sock_id = socket(PF_INET, SOCK_STREAM, 0); /* get a socket */
if ( sock_id == -1 )
return -1;
/** build address and bind it to socket **/
bzero((void *)&saddr, sizeof(saddr)); /* clear out struct */
if ( gethostname(hostname, HOSTLEN) == -1 ) /* where am I ? */
{
perror("gethostname");
exit(1);
}
hp = gethostbyname(hostname); /* get info about host */
if ( hp == NULL ){
perror("Cannot get host");
exit(2);
}
/* fill in host part */
bcopy( (void *)hp->h_addr, (void *)&saddr.sin_addr, hp->h_length);
saddr.sin_port = htons(portnum); /* fill in socket port */
saddr.sin_family = AF_INET ; /* fill in addr family */
if ( bind(sock_id, (struct sockaddr *)&saddr, sizeof(saddr)) != 0 )
return -1;
/** arrange for incoming calls **/
if ( listen(sock_id, backlog) != 0 )
return -1;
return sock_id;
}
static void stats_get(time_t *started, int *bytesp, int *hitsp)
{
pthread_mutex_lock(&stats_lock);
*started = server_started;
*bytesp = server_bytes_sent;
*hitsp = server_requests;
pthread_mutex_unlock(&stats_lock);
}
static void stats_add(int bytesamt, int hitsamt)
{
pthread_mutex_lock(&stats_lock);
server_bytes_sent += bytesamt;
server_requests += hitsamt;
pthread_mutex_unlock(&stats_lock);
}
/*
* initialize the status variables and
* set the thread attribute to detached初始化状态变量,并设置分离线程
*/
int setup(int ac, char *av[],pthread_attr_t *attrp)
{
pthread_attr_init(attrp);
pthread_attr_setdetachstate(attrp,PTHREAD_CREATE_DETACHED);
time(&server_started);
server_requests = 0;
server_bytes_sent = 0;
int portnum = -1;
char *logfile = NULL;
int pos;
int sock;
/* parse */
for(pos=1; pos<ac; pos++)
{
if ( isdigit(av[pos][0]) )
portnum = atoi(av[pos]);
else if ( strcmp(av[pos], "-l") == 0 ){
if ( ++pos < ac )
logfile = av[pos];
else {
fprintf(stderr,"missing logfilename\n");
exit(1);
}
}
}
/* act: make socket, make log object */
if ( portnum == -1 ){
fprintf(stderr,"usage: ws portnum\n");
exit(1);
}
sock = make_server_socket( portnum );//建立套接字
if ( sock == -1 ) {
perror("socket");
exit(2);
}
if ( logfile )
server_log(SL_OPEN, logfile);//打开日志文件
return sock;
}
static void *handle_call(void *fdptr)
{
FILE *fpin;
char request[BUFSIZ];
int *fd ;
fd = ((void**)fdptr)[0];
//free(fdptr); /* get fd from arg */
struct in_addr *caller;
caller=((void**)fdptr)[1];
fpin = fdopen(*fd, "r"); /* buffer input */
fgets(request,BUFSIZ,fpin); /* read client request */
printf("got a call on %d: request = %s", *fd, request);
skip_rest_of_header(fpin);
process_rq(request, *fd,*caller); /* process client rq */
fclose(fpin);
return NULL;
}
/* ------------------------------------------------------ *
skip_rest_of_header(FILE *)
skip over all request info until a CRNL is seen
------------------------------------------------------ */
static void skip_rest_of_header(FILE *fp)
{
char buf[BUFSIZ];
while( fgets(buf,BUFSIZ,fp) != NULL && strcmp(buf,"\r\n") != 0 )
;
printf("%s\n",buf);
}
/* ------------------------------------------------------ *
process_rq( char *rq, int fd )
do what the request asks for and write reply to fd
handles request in a new process
rq is HTTP command: GET /foo/bar.html HTTP/1.0
------------------------------------------------------ */
static void process_rq( char *rq, int fd,struct in_addr caller)
{
char cmd[BUFSIZ], arg[BUFSIZ];
server_log(SL_REQ, rq);
server_log(SL_ADDR, &caller);
if ( sscanf(rq, "%s%s", cmd, arg) != 2 )
return;
sanitize(arg);
printf("sanitized version is %s\n", arg);
if ( strcmp(cmd,"GET") != 0 && strcmp(cmd, "HEAD") != 0 && strcmp(cmd, "POST") != 0)
not_implemented(fd);
else if ( built_in(arg, fd) )
server_log(SL_REPLY, "200");
else if ( not_exist( arg ) )
do_404(arg, fd);
else if ( isadir( arg ) )
do_ls( arg, fd );
else if ( ends_in_cgi( arg ) || in_cgibin(arg))
{
do_exec( arg, fd );
server_log(SL_REPLY, "200");
}
else
do_cat( arg, fd );
}
/*
* make sure all paths are below the current directory
*/
static void sanitize(char *str)
{
char *src, *dest;
src = dest = str;
while( *src ){
if( strncmp(src,"/../",4) == 0 )
src += 3;
else if ( strncmp(src,"//",2) == 0 )
src++;
else
*dest++ = *src++;
}
*dest = '\0';
if ( *str == '/' )
strcpy(str,str+1);
if ( str[0]=='\0' || strcmp(str,"./")==0 || strcmp(str,"./..")==0 )
strcpy(str,".");
}
/* handle built-in URLs here. Only one so far is "status" */
int built_in(char *arg, int fd)
{
FILE
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
twebserv.zip (6个子文件)
twebserv
logfile 188B
flower.jpg 88KB
hello.cgi 57B
twebserv.c 13KB
twebserv 22KB
cgi_bin
hello.cgi 86B
共 6 条
- 1
资源评论
- xiaoxiaobintou2012-07-06只有源码,没有解释!
- Sj_Chan2012-11-19没解释,初学者吃力啊!
- qibbs2013-11-22还可以只是缺少注释,看起来费力。
- a314924994a2013-03-23很不错的资源 做Qt的服务器范例不错
blixmut
- 粉丝: 0
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功