Chinaunix首页 | 论坛 | 博客
  • 博客访问: 181447
  • 博文数量: 11
  • 博客积分: 478
  • 博客等级: 下士
  • 技术积分: 264
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-20 11:45
文章分类
文章存档

2011年(1)

2009年(10)

我的朋友

分类: 系统运维

2009-10-28 22:00:31

上一页
thread.h

/* file: thread.h */
#ifndef THREAD_H
#define THREAD_H


/* thread specific data (TSD)
 * this struct is used to save each thread's data, especily the http_req pointed buffer, and the buffer(pointer) must be a mutex value
*/

struct HTTP_TSD
{
    int http_sock;                /* pointer to http connect socket file desciptor */
    char *http_req;                /* pointer to receive buffer, this buffer saved http request passing from process */
    char *uri_buf;                /* pointer to uri, the uri is analys from http request */
    char *time_buf;                /* pointer to server time string */
    unsigned char *file_buf;    /* pointer to date which read from hard disk */
    unsigned char *send_buf;    /* pointer to send buffer */
    char *mime_type;            /* pointer to http mime type */
    char *content_encoding;        /* pointer to http content-encoding */
    int http_status;            /* pointer to http uri status or http response status */
    int file_size;
};


/* create a new thread to deal with client request
 * Arg: http_request
*/

int new_thread(const int http_sock, char *http_req);

void thread_init(void);

void destructor(void *arg);

/* deal the http comunication datails */
void *deal_req(void *arg);



/* get the request header's uri */
char *get_uri();


/* get the uri status,access return 0, not exist return 1, permission deny return 2, error return -1 */
int get_uri_statu();


/* get the mime type of the file request in uri from client's browse */
char *get_mime_type();

/* read the file which requested by client in uri ,and store in entity_buf.
   success return bytes readed,error return -1
*/

int get_file_disk();


#endif



thread.c

/* file: thread.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <pthread.h>
#include "http_session.h"
#include "http_header.h"
#include "get_time.h"
#include "thread.h"


extern size_t RECV_BUFFER_SIZE;
extern size_t SEND_BUFFER_SIZE;
extern size_t URI_SIZE;
extern size_t TIME_BUFFER_SIZE;
extern size_t MIME_BUFFER_SIZE;
extern size_t CONTENT_ENCODING_SIZE;
extern size_t FILE_MAX_SIZE;
extern char WEB_CACH_PATH[];




pthread_mutex_t req_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_key_t key;
char *req_global = NULL;
int http_sock_global = -1;





int new_thread(const int http_sock, char *http_req)
{
    if(pthread_mutex_init(&req_mutex, NULL) != 0)    /* initialize the mutex */
    {
#ifdef DEBUG
        printf("pthread_mutex_init req_mutex\n");
#endif
        return -1;
    }
    
    if(pthread_mutex_lock(&req_mutex) != 0)            /* lock it to change */
    {
#ifdef DEBUG
        printf("pthread_mutex_lock\n");
        return -1;
#endif
    }
    
    /*********************************************/
    req_global = http_req;                            /* change to new request */
    http_sock_global = http_sock;
    /********************************************/
    
    if(pthread_mutex_unlock(&req_mutex) != 0)        /* unlock */
    {
#ifdef DEBUG
        printf("pthread_mutex_unlock\n");
#endif
        return -1;
    }
    
    pthread_t tid;
    if(pthread_create(&tid, NULL, deal_req, NULL) != 0)    /* create a thread to deal with the new request */
    {
#ifdef DEBUG
        printf("pthread_create\n");
#endif
        return -1;
    }
    
    pthread_once(&once, thread_init);
    
    void *exit_stat = NULL;
    pthread_join(tid ,&exit_stat);
    if(exit_stat == NULL)
    {
        return -1;    
    }
    
    return 0;
}

void thread_init()
{
    if(pthread_key_create(&key, destructor) != 0)    /* nothing to do,just print a error message */
    {
#ifdef DEBUG
        printf("pthread_key_create\n");
#endif
        return;
    }
    return;
}

/* called when thread exit if thread's TSD is not NULL, free all memery alloc by its thread */
void destructor(void *arg)
{
    struct HTTP_TSD *tsd = NULL;
    if((tsd = (struct HTTP_TSD *)pthread_getspecific(key)) != NULL)
    {
        if(!tsd->http_req)
            free(tsd->http_req);
        if(!tsd->uri_buf)
            free(tsd->uri_buf);
        if(!tsd->time_buf)
            free(tsd->time_buf);
        if(!tsd->file_buf)
            free(tsd->file_buf);
        if(!tsd->send_buf)
            free(tsd->send_buf);
        if(!tsd->mime_type)
            free(tsd->mime_type);
        if(!tsd->content_encoding)
            free(tsd->content_encoding);
        
        free(tsd);
        return;
    }
    return;
}

void *deal_req(void *arg)
{
    struct HTTP_TSD *tsd;
    pthread_once(&once, thread_init);
    
    if(pthread_mutex_lock(&req_mutex) != 0)
    {
#ifdef DEBUG
        printf("pthread_mutex_lock req_mutex in deal_req\n");
#endif
        return NULL;
    }
    
    /**********************************************************************************/
    /*
     * Allocate All memery need by the new thread
    */

    if((tsd = (struct HTTP_TSD *)pthread_getspecific(key)) == NULL)
    {
        if((tsd = (struct HTTP_TSD *)calloc(1, sizeof(struct HTTP_TSD))) == NULL)
        {
#ifdef DEBUG
            printf("calloc HTTP_TSD\n");
#endif
            return NULL;
        }
        if((tsd->http_req = (char *)calloc(RECV_BUFFER_SIZE + 1, sizeof(char))) == NULL)
        {
#ifdef DEBUG
            printf("calloc RECV_BUFFER_SIZE\n");
#endif
            return NULL;
        }
        if((tsd->uri_buf = (char *)calloc(URI_SIZE + 4, sizeof(char))) == NULL)
        {
#ifdef DEBUG
            printf("calloc URI_SIZE\n");
#endif
            return NULL;
        }
        if((tsd->time_buf = (char *)calloc(TIME_BUFFER_SIZE + 1, sizeof(char))) == NULL)
        {
#ifdef DEBUG
            printf("calloc TIME_BUFFER_SIZE\n");
#endif
            return NULL;
        }
        if((tsd->file_buf = (unsigned char *)calloc(FILE_MAX_SIZE + 1, sizeof(int))) == NULL)
        {
#ifdef DEBUG
            printf("calloc FILE_MAX_SIZE\n");
#endif
            return NULL;
        }
        if((tsd->send_buf = (unsigned char *)calloc(SEND_BUFFER_SIZE + 1, sizeof(unsigned char))) == NULL)
        {
#ifdef DEBUG
            printf("calloc SEND_BUFFER_SIZE\n");
#endif
            return NULL;
        }
        if((tsd->mime_type = (char *)calloc(MIME_BUFFER_SIZE + 1, sizeof(char))) == NULL)
        {
#ifdef DEBUG
            printf("calloc MIME_BUFFER_SIZE\n");
#endif
            return NULL;
        }
        if((tsd->content_encoding = (char *)calloc(CONTENT_ENCODING_SIZE + 1, sizeof(char))) == NULL)
        {
#ifdef DEBUG
            printf("calloc CONTENT_ENCODING_SIZE\n");
#endif
            return NULL;
        }
        
        
        
        /* copy the http_request message to dynamic created memery, and this memery is thread specific data(TSD) */
        /* req_global is mutexed, so during copying ,others threads can not read or write it until unlock */
        tsd->http_sock = http_sock_global;
        memcpy(tsd->http_req, req_global,RECV_BUFFER_SIZE);        /* is memcpy thread safe ,i am not sure */
        
        if(pthread_setspecific(key, tsd) != 0)
        {
#ifdef DEBUG
            printf("pthread_setspecific\n");
#endif
            return NULL;
        }    
    }
    /**********************************************************************************/
    
    if(pthread_mutex_unlock(&req_mutex) != 0)        /* unlock it */
    {
#ifdef DEBUG
        printf("pthread_mutex_unlock in deal_req\n");
#endif
        return NULL;
    }
    
    /* now deal http request
     * step 1. get uri
     * step 2. get the file which require from http URL ,and store in tsd->file_buf
     * step 3. set http response header(fill the tsd->send_buf with some http header fields)
     * step 4. call the system funtion send(), this send() will copy datas in tsd->send_buf to kernel tcp buffer
     * step 5. exit this thread and free all memery allocate
    */

    if(get_uri() == NULL)
    {
#ifdef DEBUG
        printf("NULL of get_uri in deal_req\n");
#endif
        return NULL;
    }

    if(get_mime_type() == NULL)
    {
#ifdef DEBUG
        printf("NULL of get_mime_type in deal_req\n");
#endif
        return NULL;
    }
        
    if(get_file_disk() == -1)
    {
#ifdef DEBUG
        printf("error get_file_disk in deal_req\n");
#endif
        return NULL;
    }
    int send_bytes = 0;
    if((send_bytes = set_header()) == -1)
    {
#ifdef DEBUG
        printf("error set_header in deal_req\n");
#endif
        return NULL;
    }
    
    /* lock the socket file descriptor in order to send data */
    if(pthread_mutex_lock(&req_mutex) != 0)
    {
#ifdef DEBUG
        printf("error pthread_mutex_lock socket, begain send data\n");
#endif
        return NULL;
    }
    
    if( send(tsd->http_sock, tsd->send_buf, send_bytes, 0) == -1)
    {
#ifdef DEBUG
        printf("error send in deal_req\n");
#endif
        return NULL;
    }
    
    if(pthread_mutex_unlock(&req_mutex) != 0)
    {
#ifdef DEBUG
        printf("error pthread_mutex_unlock, after send data\n");
#endif
        return NULL;
    }
    
    pthread_exit((void *)1);
}



/* thread safe mode get_uri function
 * get the uri from http request string, then store it in TSD
*/

char *get_uri()
{
    struct HTTP_TSD *tsd = NULL;
    if((tsd = (struct HTTP_TSD *)pthread_getspecific(key)) == NULL)
    {
#ifdef DEBUG
        printf("getspecific in get_uri\n");
#endif
        return NULL;
    }
    
    if(tsd->http_req == NULL)
    {
#ifdef DEBUG
        printf("NULL of tsd->uri_http in get_uir\n");
#endif
        return NULL;
    }

    
    
    /* HTTP request is some like this 'GET /index.html HTTP/1.1'
     * so the uri base is charactor '/' ,and uri end is space(' ')
    */

    int index = 0;
    while( (tsd->http_req[index] != '/') && (tsd->http_req[index] != '\0') ) /* index to base '/' */
    {
        index++;
    }
    int base = index;
    while( ((index - base) < URI_SIZE) && (tsd->http_req[index] != ' ') && (tsd->http_req[index] != '\0') )
    {
        index++;
    }
    if( (index - base) >= URI_SIZE)        /* too long of uri request */
    {
#ifdef DEBUG
        fprintf(stderr, "error: too long of uri request.\n");
#endif
        tsd->http_status = URI_TOO_LONG;
        return NULL;
    }
    if((tsd->http_req[index - 1] == '/') && (tsd->http_req[index] == ' '))    /* no request page ,so default page index.html return */
    {
        memcpy(tsd->uri_buf, "index.html", 10);
        return tsd->uri_buf;
    }
    
    /* copy uri to TSD uri_buf, is the standard C lib function memcpy thread safe ? i am not sure*/
    memcpy(tsd->uri_buf, tsd->http_req + base + 1, index - base - 1);
#ifdef    DEBUG
    printf("uri:%s\n", tsd->uri_buf);
#endif
    return tsd->uri_buf;

}


int get_uri_status()
{
    struct HTTP_TSD *tsd = NULL;
    if((tsd = (struct HTTP_TSD *)pthread_getspecific(key)) == NULL)
    {
#ifdef DEBUG
        printf("getspecific in get_uri_status\n");
#endif
        return -1;
    }
    if(tsd->uri_buf == NULL)
    {
#ifdef DEBUG
        printf("NULL of tsd->uri_buf in get_uri_status\n");
#endif
        return -1;
    }
    
    /* permission check */
    if(access(tsd->uri_buf, F_OK) == -1)
    {
#ifdef DEBUG
        fprintf(stderr, "File: %s not found.\n", tsd->uri_buf);
#endif
        tsd->http_status = FILE_NOT_FOUND;
        memcpy(tsd->uri_buf, "404.html\0", 9);
        return FILE_NOT_FOUND;
    }
    if(access(tsd->uri_buf, R_OK) == -1)
    {
#ifdef DEBUG
        fprintf(stderr, "File: %s can not read.\n", tsd->uri_buf);
#endif
        tsd->http_status = FILE_FORBIDEN;
        return FILE_FORBIDEN;
    }
    tsd->http_status = FILE_OK;
    return FILE_OK;
}


char *get_mime_type()
{
    struct HTTP_TSD *tsd = NULL;
    if((tsd = (struct HTTP_TSD *)pthread_getspecific(key)) == NULL)
    {
#ifdef DEBUG
        printf("getspecific in get_mime_type\n");
#endif
        return NULL;
    }
    if(tsd->uri_buf == NULL)
    {
#ifdef DEBUG
        printf("NULL of tsd->uri_buf in get_mime_type\n");
#endif
        return NULL;
    }
    if(tsd->mime_type == NULL)
    {
#ifdef DEBUG
        printf("NULL of tsd->mime_type in get_mime_type\n");
#endif
        return NULL;
    }
    
    int len = strlen(tsd->uri_buf);
    int dot = len - 1;    /* the index of uri last charactor */
    
    /* search dot charactor from the tail of uri */
    while( dot >= 0 && tsd->uri_buf[dot] != '.')
    {
        dot--;
    }
    
    /* if the uri begain with a dot and the dot is the last one(that is to say the uri contain only a dot '.'), then it is a bad uri request,so return NULL */
    if(dot == 0)        
    {
#ifdef DEBUG
        printf("bad uri request\n");
#endif
        return NULL;
    }
    
    dot++;    /* index to type field in uri*/
    int type_len = len - dot;    /* the length of file extend name */
    char *type_str = tsd->uri_buf + dot;    /* the pointer to extend name */
    switch(type_len)
    {
        case 4:
         if(!strcmp(type_str, "html") || !strcmp(type_str, "HTML"))
         {
            strncpy(tsd->mime_type, "text/html", 9);
            return "text/html";
         }
         if(!strcmp(type_str, "jpeg") || !strcmp(type_str, "JPEG"))
         {
            strncpy(tsd->mime_type, "image/jpeg", 10);
            return "image/jpeg";
         }
         break;

        case 3:
         if(!strcmp(type_str, "htm") || !strcmp(type_str, "HTM"))
         {
            strncpy(tsd->mime_type, "text/html", 9);
            return "text/html";
         }
         if(!strcmp(type_str, "css") || !strcmp(type_str, "CSS"))
         {
            strncpy(tsd->mime_type, "text/css", 8);
            return "text/css";
         }
         if(!strcmp(type_str, "png") || !strcmp(type_str, "PNG"))
         {
            strncpy(tsd->mime_type, "image/png", 9);
            return "image/png";
         }
         if(!strcmp(type_str, "jpg") || !strcmp(type_str, "JPG"))
         {
            strncpy(tsd->mime_type, "image/jpeg", 10);
            return "image/jpeg";
         }
         if(!strcmp(type_str, "gif") || !strcmp(type_str, "GIF"))
         {
            strncpy(tsd->mime_type, "image/gif", 9);
            return "image/gif";
         }
         if(!strcmp(type_str, "ico") || !strcmp(type_str, "ICO"))
         {
            strncpy(tsd->mime_type, "image/ico", 9);
            return "image/ico";
         }
         if(!strcmp(type_str, "txt") || !strcmp(type_str, "TXT"))
         {
            strncpy(tsd->mime_type, "text/plain", 10);
            return "text/plain";
         }
         break;

        case 2:
         if(!strcmp(type_str, "js") || !strcmp(type_str, "JS"))
         {
            strncpy(tsd->mime_type, "text/javascript", 15);
            return "text/javascript";
         }
         break;

        default:        /* unknown mime type or server do not support type now*/
         memcpy(tsd->mime_type, "UNSUPPORT_MIME_TYPE", 19);
         tsd->http_status = UNSUPPORT_MIME_TYPE;
         return NULL;
         break;
    }

    return NULL;    /* never run to hear, but i'd like to keep it */
}


int get_file_disk()
{
    struct HTTP_TSD *tsd = NULL;
    if((tsd = (struct HTTP_TSD *)pthread_getspecific(key)) == NULL)
    {
#ifdef DEBUG
        printf("getspecific in get_file_disk\n");
#endif
        return -1;
    }
    if(tsd->uri_buf == NULL)
    {
#ifdef DEBUG
        printf("NULL of tsd->uri_buf in get_file_disk\n");
#endif
        return -1;
    }
    if(tsd->file_buf == NULL)
    {
#ifdef DEBUG
        printf("NULL of tsd->file_buf in get_file_disk\n");
#endif
        return -1;
    }
    if(tsd->content_encoding == NULL)
    {
#ifdef DEBUG
        printf("NULL of tsd->content_encoding in get_file_disk\n");
#endif
        return -1;
    }
    
    int read_count = 0;
    /* */
    
    int fd = open(tsd->uri_buf, O_RDONLY);    
    if(fd == -1)
    {
#ifdef DEBUG
        printf("open() in get_file_disk\n");
#endif
        return -1;
    }
    unsigned long st_size;
    struct stat st;
    if(fstat(fd, &st) == -1)
    {
#ifdef DEBUG
        printf("stat() in get_file_disk\n");
#endif
        return -1;
    }
    st_size = st.st_size;
    if(st_size > FILE_MAX_SIZE)
    {
#ifdef DEBUG
        fprintf(stderr, "the file %s is too large.\n", tsd->uri_buf);
#endif
        tsd->http_status = FILE_TOO_LARGE;
        return -1;
    }
    /* is read thread safe? */
    if((read_count = read(fd, tsd->file_buf, FILE_MAX_SIZE)) == -1)
    {
#ifdef DEBUG
        printf("read() in get_file_disk");
#endif
        tsd->http_status = SERVER_ERROR;
        return -1;
    }

    tsd->http_status = FILE_OK;
#ifdef DEBUG
    printf("file %s size : %lu , read %d\n", tsd->uri_buf, st_size, read_count);
#endif
    tsd->file_size = read_count;
    return read_count;
}



webconfig.conf

#web server config file
#config format is writed like bellow:
#    PORT=8888;
#     |   | | |
#    1   2 3 4
#    1-->option name
#    2-->equal charecter
#    3-->number to set
#    4-->end with semicolon
#NOTICE there is no space or other character should contains in a declare sentaince.

#set web server listen port
PORT=8000;

#set web server listening queue size
BACKLOG=20;

#set web server root directory
#be careful there is not ';' end
WEB_ROOT_PATH=../www/

#set web server tcp receive buffer size
#this buffer is used to read http request from client browse
RECV_BUFFER_SIZE=1028;

#set web server tcp send buffer size
SEND_BUFFER_SIZE=10500001;

#set web server time buffer size
TIME_BUFFER_SIZE=40;

#set web server uri size
#this buffer is used to save uri from client browse
URI_SIZE=1282;

#set web mime type buffer size
MIME_BUFFER_SIZE=20;

#set web server content encoding buffer size
CONTENT_ENCODING_SIZE=40;

#set web server read file of max size(bytes)
#server read the file on disk
FILE_MAX_SIZE=104857;

#end


readme


/* file: readme */

Thanks for using Mutu Web Server!

This mini http server is writted just for fun. Well, you can think about it as a toy web server program.

This version(Mutu 0.2 alpha) is the secend version of Mutu, in the old version(Mutu 0.1 alpha), I have used Muti-process to deal with Muti-access from client browser, but in this version I used Muti-thread(Posix thread library under Red Hat Linux), I change to use thread is not for effective, almost myself do not know the real reason. Perhapse for fun too.

how to use this program?
0. uncompress it . use gzip
    tar zxvf Mutu_0_2_alpha.tar.gz

1. chang directory to src
    cd Mutu_0_2_alpha/src

2. run the makefile to compile the source files
    make

4. run web server
    ./webserver

how to read the source code of this program?
if you have a good knownleagement of C, socket API, and Unix/Linux, you can read it directly, else you may visite my home page(http://cnlinuxfan.cublog.cn), may some help.

any problems please send email to : mushan520@gmail.com

thanks very much!
           
                        mushan
                        2009-10-28




所以源码,配置文件,测试页面,以及整个服务器根目录的压缩档
文件:Mutu_0_2_alpha.tar.gz
大小:62KB
下载:下载

                            回到第一页

阅读(3658) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~