├── lxasync ├── home └── webhome │ ├── 404.html │ ├── index.html │ └── test.html ├── lx_async_handler.h ├── lx_epoll.h ├── .gitattributes ├── README.md ├── .gitignore ├── lx_async_server.h ├── lx_epoll.c ├── main.c ├── lx_conn_ctx.h ├── lx_async_server.c └── lx_async_handler.c /lxasync: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jindc/lx_async_server/HEAD/lxasync -------------------------------------------------------------------------------- /home/webhome/404.html: -------------------------------------------------------------------------------- 1 | 2 | 404 File Not Found 3 |

404,FILE NOT FOUND

4 | 5 | -------------------------------------------------------------------------------- /home/webhome/index.html: -------------------------------------------------------------------------------- 1 | 2 | welcome to lanxin server 3 |

welcome to lanxin server

4 | 5 | -------------------------------------------------------------------------------- /home/webhome/test.html: -------------------------------------------------------------------------------- 1 | 2 | welcome to lanxin server 3 |

welcome to lanxin server

this a test page!

4 | 5 | -------------------------------------------------------------------------------- /lx_async_handler.h: -------------------------------------------------------------------------------- 1 | #ifndef LX_ASYNC_HANDLER_H 2 | #define LX_ASYNC_HANDLER_H 3 | #include "lx_conn_ctx.h" 4 | 5 | int handle_events(int ep_fd,struct epoll_event * events, int nevent,lx_rbtree_t * timer); 6 | int listen_handle(lxasync_conn_ctx * ); 7 | int conn_handle(lxasync_conn_ctx * ); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /lx_epoll.h: -------------------------------------------------------------------------------- 1 | #ifndef LX_EPOLL_H 2 | #define LX_EPOLL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "lx_types.h" 8 | 9 | int lx_set_epoll(int ep_fd, int fd, void * data, int events,lx_bool_t is_nblk,lx_bool_t is_add); 10 | 11 | char * lx_get_events(unsigned int events,char * buff, size_t len ); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lx_async_server 2 | 一个基于epoll的linux c web服务器 3 | 4 | lx_async_server使用epoll实现异步web服务,同时可以指定线程的数量,每一个线程独立工作以充分利用硬件的cpu及内存等资源。默认情况下,服务器会根据cpu的个数起相应的线程数。定时器使用红黑树实现。整个架构参考nginx。 5 | 6 | 服务器经valgrind 内存测试及压力测试. 7 | 要被访问的网页放到 home/webhome 目录下 8 | 9 | 编译: 10 | 项目会用到其他模块 11 | 12 | lx_http https://github.com/jindc/lx_rbtree.git 13 | lx_http https://github.com/jindc/lx_http.git 14 | lxlib https://github.com/jindc/lxlib.git 15 | lxlog https://github.com/jindc/lxlog.git 16 | 17 | ./build.sh 18 | ./lxasync -h 19 | 20 | usage:lxmt [-h] [--port] [--home] [--thread_num] [--daemon] 21 | 22 | --thread_num 启动的独立线程数,默认与cpu数相同 23 | 24 | 作者:德才 25 | email: jindc@163.com 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /lx_async_server.h: -------------------------------------------------------------------------------- 1 | #ifndef LX_ASYNC_SERVER_H 2 | #define LX_ASYNC_SERVER_H 3 | #include 4 | #include 5 | #include "lx_socket.h" 6 | #include "lxlog.h" 7 | #include "lx_types.h" 8 | #include "lx_http.h" 9 | #include "lx_rbtree.h" 10 | 11 | typedef struct lxasync_server_ctx lxasync_server_ctx; 12 | struct lxasync_server_ctx 13 | { 14 | long conn_timeout; 15 | 16 | int epoll_timeout; 17 | int epoll_maxevents; 18 | 19 | lx_bool_t is_nostub; 20 | 21 | int thread_num; 22 | pthread_mutex_t mutex; 23 | 24 | struct lxlog log; 25 | struct lxlog_dailyas asarg; 26 | 27 | } *g_lxasync_server_ctx; 28 | 29 | #define g_ctx (g_lxasync_server_ctx) 30 | 31 | typedef struct lxasync_thread_ctx lxasync_thread_ctx; 32 | struct lxasync_thread_ctx 33 | { 34 | lx_rbtree_t timer; 35 | }; 36 | 37 | 38 | typedef enum lxasync_handle_stat lxasync_handle_stat; 39 | enum lxasync_handle_stat 40 | { 41 | HANDLE_DONE = 0, 42 | HANDLE_NEED_MORE, 43 | HANDLE_ERR 44 | }; 45 | 46 | static char * g_home = "home"; 47 | static char * g_whome = "webhome"; 48 | static char * g_loghome = "logs"; 49 | 50 | int init_lxasync_server(lx_bool_t is_nostub, const char * home,int thread_num); 51 | 52 | int start_lxasync_server(int port); 53 | 54 | int cleanup_lxasync_server(); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /lx_epoll.c: -------------------------------------------------------------------------------- 1 | #include "lx_epoll.h" 2 | 3 | int lx_set_epoll(int ep_fd, int fd, void * data, int events,lx_bool_t is_nblk,lx_bool_t is_add) 4 | { 5 | int op,ret = 0; 6 | struct epoll_event ev; 7 | 8 | if( is_nblk && lx_set_nonblocking(fd )){ 9 | ret = -1; goto end; 10 | } 11 | 12 | op = is_add? EPOLL_CTL_ADD:EPOLL_CTL_MOD; 13 | 14 | ev.data.ptr = data; 15 | ev.events = events; 16 | 17 | if( epoll_ctl(ep_fd,op,fd,&ev) ){ 18 | ret = -1; goto end; 19 | } 20 | ret = 0; 21 | end: 22 | return ret; 23 | } 24 | 25 | char * lx_get_events(unsigned int events,char * buff, size_t len ) 26 | { 27 | int ret = 0,curlen = 0,i = 0; 28 | static char sbuff[1024]; 29 | unsigned int flags[]= {EPOLLIN,EPOLLPRI,EPOLLOUT,EPOLLRDNORM,EPOLLRDBAND,EPOLLWRNORM,EPOLLWRBAND 30 | ,EPOLLMSG,EPOLLERR,EPOLLHUP,EPOLLONESHOT,EPOLLET}; 31 | char * names[] = {"EPOLLIN","EPOLLPRI","EPOLLOUT","EPOLLRDNORM","EPOLLRDBAND","EPOLLWRNORM","EPOLLWRBAND","EPOLLMSG" 32 | ,"EPOLLERR","EPOLLHUP","EPOLLONESHOT","EPOLLET"}; 33 | 34 | if(len < 1){ 35 | buff[0] =0; 36 | return buff; 37 | } 38 | 39 | if(buff == NULL) 40 | buff = sbuff,len = 1024; 41 | 42 | for(; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i ){ 43 | if( events & flags[i]){ 44 | ret = snprintf(buff+curlen,len - curlen," %s",names[i]); 45 | if(ret < 0){ 46 | buff[0]=0; 47 | return buff; 48 | } 49 | curlen += ret; 50 | } 51 | } 52 | 53 | return buff; 54 | } 55 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "lx_serror.h" 7 | #include "lx_types.h" 8 | #include "lx_daemon.h" 9 | #include "lx_async_server.h" 10 | 11 | int main(int argc ,char * argv[]) 12 | { 13 | lx_bool_t is_nostub = LX_FALSE,is_daemon = LX_FALSE ; 14 | int port = 8989,ret,thread_num = 0; 15 | char * host = NULL, *home = "home"; 16 | char * help = "usage:lxmt [-h] [--port] [--home] [--thread_num]"; 17 | struct option opts [] ={ 18 | {"help",0,NULL,'h'}, 19 | 20 | {"daemon",0,NULL,'d'}, 21 | 22 | {"port",1,NULL,'p'}, 23 | 24 | {"thread_num",1,NULL,'1'}, 25 | 26 | {"home",1,NULL,'2'}, 27 | 28 | {NULL,0,NULL,0} 29 | }; 30 | 31 | while(1){ 32 | char c ; 33 | int opt_index; 34 | 35 | c = getopt_long(argc,argv,"hp:",opts,&opt_index); 36 | if( c == -1) 37 | break; 38 | switch(c){ 39 | case '?': 40 | case 'h': 41 | default : 42 | err_quit("%s",help); 43 | 44 | case 'p': 45 | port = atoi(optarg); 46 | break; 47 | case 'd': 48 | is_daemon = LX_TRUE; 49 | break; 50 | case '1': 51 | thread_num = atoi(optarg); 52 | break; 53 | case '2': 54 | home = optarg; 55 | break; 56 | } 57 | }; 58 | 59 | if(is_daemon){ 60 | if(lx_daemon()){ 61 | printf("lx_daemon() error,%d:%s\n",errno, strerror(errno)); 62 | exit(EXIT_FAILURE); 63 | } 64 | printf("run daemon mode\n"); 65 | } 66 | printf("host:%s,port:%d,home:%s,thread_num:%d,daemon:%d\n",host,port,home,thread_num,is_daemon); 67 | 68 | if(init_lxasync_server(is_nostub,home,thread_num)){ 69 | perror("init server error\n"); 70 | return EXIT_FAILURE; 71 | } 72 | printf("init server ok\n"); 73 | 74 | if(start_lxasync_server(port)){ 75 | perror("start server error\n"); 76 | ret = EXIT_FAILURE; 77 | goto end; 78 | } 79 | ret = EXIT_SUCCESS; 80 | 81 | end: 82 | if(cleanup_lxasync_server()){ 83 | perror("clean up server error\n"); 84 | return EXIT_FAILURE; 85 | } 86 | 87 | return ret; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /lx_conn_ctx.h: -------------------------------------------------------------------------------- 1 | #ifndef LX_CONN_CTX_H 2 | #define LX_CONN_CTX_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "lx_socket.h" 8 | #include "lx_async_server.h" 9 | #include "lxlog.h" 10 | #include "lx_http.h" 11 | #include "lx_epoll.h" 12 | #include "lx_rbtree.h" 13 | 14 | #define MAX_HEADER_LEN (2048) 15 | #define MAX_PATH_LEN (1024) 16 | 17 | typedef struct lxasync_conn_ctx lxasync_conn_ctx; 18 | struct lxasync_conn_ctx 19 | { 20 | int ep_fd; 21 | int fd; 22 | unsigned int events; 23 | 24 | struct sockaddr_in peer_addr; 25 | struct timeval accept_time; 26 | uint64_t timeout;//timeout time for timer 27 | lx_rbtree_t * timer; 28 | 29 | h_stage_t stage; 30 | int (*handle)(lxasync_conn_ctx * arg ); 31 | 32 | h_parser_ctx req_ctx; 33 | h_parser_ctx resp_ctx; 34 | lx_buffer data_buff; 35 | char path[MAX_PATH_LEN]; 36 | FILE * fh; 37 | int contlen; 38 | int inoutlen; 39 | 40 | void * arg; 41 | int (*cleanup)(lxasync_conn_ctx * arg ); 42 | }; 43 | 44 | static lxasync_conn_ctx * new_conn_ctx(int ep_fd,int fd,int (*handle)(lxasync_conn_ctx * ctx),lx_rbtree_t *timer) 45 | { 46 | char * buff; 47 | int ret = 0; 48 | lxasync_conn_ctx *pctx = NULL; 49 | 50 | if( (pctx = (lxasync_conn_ctx *)calloc(1, sizeof(lxasync_conn_ctx))) == NULL) 51 | return NULL; 52 | 53 | http_set_uri_sep(&pctx->req_ctx,'?','&','='); 54 | http_set_memory_msuit(&pctx->req_ctx,malloc,free,http_extend); 55 | if(http_ctx_init(&pctx->req_ctx,T_REQ,256)){ 56 | ret =-1;goto err; 57 | } 58 | 59 | http_set_uri_sep(&pctx->resp_ctx,'?','&','='); 60 | http_set_memory_msuit(&pctx->resp_ctx,malloc,free,http_extend); 61 | if(http_ctx_init(&pctx->resp_ctx,T_RESP,2 )){ 62 | ret = -1; goto err1; 63 | } 64 | 65 | if( (buff = (char *)malloc(MAX_HEADER_LEN)) == NULL){ 66 | ret = -1;goto err2; 67 | } 68 | lx_buffer_init(&pctx->data_buff,buff,0,0,MAX_HEADER_LEN); 69 | 70 | pctx->ep_fd = ep_fd; 71 | pctx->fd = fd; 72 | gettimeofday(&pctx->accept_time,NULL); 73 | 74 | pctx->stage = STAGE_START; 75 | pctx->handle = handle; 76 | pctx->timer = timer; 77 | 78 | return pctx; 79 | 80 | err2: 81 | http_ctx_cleanup(&pctx->resp_ctx); 82 | err1: 83 | http_ctx_cleanup(&pctx->req_ctx ); 84 | err: 85 | free(pctx); 86 | return NULL; 87 | 88 | } 89 | 90 | static int cleanup_conn_ctx(lxasync_conn_ctx * pctx) 91 | { 92 | int ret = 0; 93 | 94 | // if(pctx->fd >= 0) 95 | // close(pctx->fd); 96 | pctx->fd = -1; 97 | 98 | http_ctx_cleanup(&pctx->req_ctx); 99 | http_ctx_cleanup(&pctx->resp_ctx); 100 | 101 | free(pctx->data_buff.base); 102 | 103 | if(pctx->cleanup){ 104 | if( pctx->cleanup(pctx)){ 105 | ret = -1; 106 | } 107 | } 108 | 109 | free(pctx); 110 | 111 | return ret = 0; 112 | } 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /lx_async_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "lx_socket.h" 5 | #include "lx_async_server.h" 6 | #include "lxlog.h" 7 | #include "lx_http.h" 8 | #include "lx_epoll.h" 9 | #include "lx_conn_ctx.h" 10 | #include "lx_async_handler.h" 11 | 12 | int init_lxasync_server(lx_bool_t is_nostub, const char * home,int thread_num) 13 | { 14 | char buff[1024]; 15 | int ret = 0; 16 | struct lxasync_server_ctx * ctx; 17 | ctx = (lxasync_server_ctx *)calloc(1,sizeof(lxasync_server_ctx)); 18 | if( ctx == NULL) 19 | { 20 | perror("malloc in init error\n"); 21 | return -1; 22 | } 23 | 24 | ctx->conn_timeout = 2000;//milli second 25 | ctx->epoll_timeout = 2000; 26 | ctx->epoll_maxevents = 100; 27 | 28 | ctx->is_nostub = is_nostub; 29 | 30 | if(home) 31 | g_home = (char *)home; 32 | 33 | if(pthread_mutex_init(&ctx->mutex,NULL) ){ 34 | perror("pthread_mutex_init error"); 35 | free(ctx); 36 | return -1; 37 | } 38 | 39 | newlxlog( (&ctx->log)); 40 | ctx->asarg.newhour = 18; 41 | ctx->log.arg = &ctx->asarg; 42 | if(snprintf(buff,1024,"%s/%s",g_home,g_loghome) <=0){ 43 | perror("snprintf log path error"); 44 | goto err1; 45 | } 46 | 47 | if(lxlog_init(&ctx->log,buff,"access.log", LX_LOG_DEBUG)) { 48 | printf("init log error,ret=%d",ret); 49 | ret = -1;goto err1; 50 | } 51 | ctx->log.flushnow = 1; 52 | ctx->log.tlockflag = 1; 53 | ctx->log.plockflag = 0; 54 | ctx->log.showpid = 1; 55 | // ctx->log.showtid = 0; 56 | 57 | g_lxasync_server_ctx = ctx; 58 | if ( thread_num <= 0 && (thread_num = sysconf(_SC_NPROCESSORS_ONLN) ) < 0){ 59 | perror("get cpu core number error"); 60 | ret = -1;goto err; 61 | } 62 | g_ctx->thread_num = thread_num; 63 | 64 | return 0; 65 | 66 | err: 67 | ctx->log.cleanup(&g_ctx->log); 68 | err1: 69 | pthread_mutex_destroy(&g_ctx->mutex); 70 | if(ctx != NULL) 71 | free(ctx); 72 | return ret; 73 | } 74 | 75 | int cleanup_lxasync_server() 76 | { 77 | if( g_ctx != NULL) 78 | { 79 | g_ctx->log.cleanup(&g_ctx->log); 80 | 81 | pthread_mutex_destroy(&g_ctx->mutex); 82 | 83 | free(g_ctx); 84 | 85 | g_ctx = NULL; 86 | } 87 | return 0; 88 | } 89 | 90 | static int do_service(void * arg); 91 | 92 | int start_lxasync_server(int port) 93 | { 94 | int i,ret,listen_fd ; 95 | pthread_t tid; 96 | if( (listen_fd = lx_listen(port)) < 0 ){ 97 | g_ctx->log.logerror( &g_ctx->log, "lx_listen error[%d:%s]",ret, strerror(ret)); 98 | return -1; 99 | } 100 | 101 | for(i = 0; i < g_ctx->thread_num; ++i){ 102 | if( ret = pthread_create(&tid,NULL,(void * (*)(void *))do_service,(void *)(long)listen_fd )){ 103 | g_ctx->log.logerror( &g_ctx->log, "pthread_create error[%d:%s]",ret, strerror(ret)); 104 | return -1; 105 | } 106 | 107 | if( ret = pthread_detach(tid)){ 108 | g_ctx->log.logerror( &g_ctx->log, "pthread_detach error[%d:%s]",ret, strerror(ret)); 109 | return -1; 110 | } 111 | 112 | g_ctx->log.loginfo(&g_ctx->log,"server %ld start",(long)tid); 113 | } 114 | 115 | g_ctx->log.loginfo(&g_ctx->log,"start server ok. the work thread number is %d",g_ctx->thread_num); 116 | 117 | while(1) 118 | sleep(5); 119 | end: 120 | if(listen_fd >=0) 121 | close(listen_fd); 122 | 123 | return 0; 124 | } 125 | 126 | static int do_service(void * arg) 127 | { 128 | int ret = 0, ep_fd = -1,listen_fd = -1; 129 | struct epoll_event *events = NULL; 130 | lxasync_conn_ctx* listen_ctx = NULL; 131 | lx_rbtree_t timer; 132 | 133 | lx_rbtree_init(&timer,malloc,free); 134 | listen_fd = (int)(long)arg; 135 | 136 | if( (ep_fd = epoll_create(9)) < 0 ){ 137 | g_ctx->log.logerror(&g_ctx->log,"epoll_create error"); 138 | return -1; 139 | } 140 | 141 | if( (events = (struct epoll_event *)malloc( g_ctx->epoll_maxevents * sizeof(struct epoll_event) ) ) 142 | == NULL){ 143 | g_ctx->log.logerror(&g_ctx->log,"malloc epoll events error"); 144 | ret = -1; goto end; 145 | } 146 | 147 | if( (listen_ctx = new_conn_ctx(ep_fd,listen_fd,listen_handle,&timer)) == NULL) 148 | { 149 | g_ctx->log.logerror(&g_ctx->log,"new_conn_ctx error"); 150 | ret = -1;goto end; 151 | } 152 | listen_ctx->stage = STAGE_LISTENING; 153 | 154 | if( lx_set_epoll(ep_fd,listen_fd,listen_ctx,EPOLLIN|EPOLLET,LX_TRUE,LX_TRUE )){ 155 | g_ctx->log.logerror(&g_ctx->log,"lx_set_epoll error" ); 156 | ret = -1; goto end; 157 | } 158 | 159 | for(;;){ 160 | ret = epoll_wait(ep_fd,events,g_ctx->epoll_maxevents,g_ctx->epoll_timeout); 161 | if(ret < 0){ 162 | if(errno != EINTR){ 163 | g_ctx->log.logerror(&g_ctx->log,"epoll_wait error"); 164 | ret = -1;goto end; 165 | }else 166 | continue; 167 | }else if(ret > 0) 168 | handle_events(ep_fd,events,ret,&timer); 169 | } 170 | 171 | ret = 0; 172 | end: 173 | lx_rbtree_free(&timer); 174 | 175 | if(ep_fd >=0) 176 | close(ep_fd); 177 | 178 | if(events) 179 | free(events); 180 | 181 | if(listen_ctx) 182 | if(cleanup_conn_ctx(listen_ctx)){ 183 | g_ctx->log.logerror(&g_ctx->log,"cleanup conn ctx error"); 184 | } 185 | return ret; 186 | } 187 | 188 | 189 | -------------------------------------------------------------------------------- /lx_async_handler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "lx_async_server.h" 4 | #include "lx_async_handler.h" 5 | #include "lx_fileio.h" 6 | #include "lxtime.h" 7 | 8 | int req_head_handle(lxasync_conn_ctx * ); 9 | int req_body_handle(lxasync_conn_ctx * ); 10 | int resp_head_handle(lxasync_conn_ctx * ); 11 | int resp_body_handle(lxasync_conn_ctx *); 12 | 13 | #define AGAIN_FLAG (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) 14 | int remove_conn(lxasync_conn_ctx *pctx) 15 | { 16 | if(pctx->fd >=0 && epoll_ctl(pctx->ep_fd,EPOLL_CTL_DEL,pctx->fd,NULL)){ 17 | g_ctx->log.logerror(&g_ctx->log,"delete fd:%d from epll error",pctx->fd); 18 | } 19 | 20 | if(pctx->fd >=0){ 21 | close(pctx->fd); 22 | pctx->fd = -1; 23 | } 24 | 25 | cleanup_conn_ctx(pctx); 26 | return 0; 27 | } 28 | 29 | int handle_events(int ep_fd,struct epoll_event * events, int nevent,lx_rbtree_t * timer) 30 | { 31 | int i = 0, ret = 0; 32 | uint64_t key_temp; 33 | char ebuff[1024] ,*pebuff; 34 | lxasync_conn_ctx * cctx; 35 | lx_rbtree_node * n; 36 | 37 | //if (nevent) printf("handle events ,nevent :%d\n",nevent); 38 | for(; i < nevent;++i){ 39 | cctx = (lxasync_conn_ctx*)events[i].data.ptr; 40 | cctx->events = events[i].events; 41 | 42 | pebuff = lx_get_events(cctx->events,ebuff,1024 ); 43 | //printf("events flags:%s\n",pebuff); 44 | 45 | ret = cctx->handle( cctx); 46 | } 47 | 48 | key_temp = (uint64_t)get_micros(); 49 | while(1){ 50 | n = lx_rbtree_min( timer,timer->root); 51 | if(n != &timer->nil ){ 52 | 53 | if(n->key == 0){ 54 | printf("you\n"); 55 | } 56 | 57 | if (n->key < key_temp){ 58 | uint64_t key = n->key; 59 | 60 | g_ctx->log.loginfo(&g_ctx->log,"timer:connection timeout"); 61 | //printf("delete key in timer check:%lu\n",(unsigned long)n->key); 62 | 63 | remove_conn(n->data); 64 | if(lx_rbtree_delete(timer,n->key ) != 0){ 65 | g_ctx->log.logfatal(&g_ctx->log,"timer: cannot find key %lu for delete",(unsigned long) key); 66 | } 67 | 68 | //assert( !lx_rbtree_find(timer,key)); 69 | 70 | }else{ 71 | break; 72 | } 73 | }else{ 74 | break; 75 | } 76 | } 77 | 78 | return 0; 79 | } 80 | 81 | int listen_handle(lxasync_conn_ctx *arg ) 82 | { 83 | int ret = 0,addrlen = 0,fd = -1; 84 | struct sockaddr_in addr; 85 | lxasync_conn_ctx * cctx = NULL; 86 | uint64_t l_temp; 87 | 88 | //printf("listen handle call\n"); 89 | if(arg->events & EPOLLERR ){ 90 | g_ctx->log.logerror(&g_ctx->log,"listen fd from epoll error"); 91 | return 0; 92 | } 93 | 94 | addrlen = sizeof(struct sockaddr_in); 95 | if(pthread_mutex_trylock(&g_ctx->mutex) == 0){ 96 | fd = accept(arg->fd,(struct sockaddr *)&addr,&addrlen); 97 | if(pthread_mutex_unlock(&g_ctx->mutex)){ 98 | g_ctx->log.logerror(&g_ctx->log,"%s:pthread_mutex_unlock error",__FUNCTION__); 99 | } 100 | }else{ 101 | return 0; 102 | } 103 | 104 | if(fd < 0){ 105 | if(errno == EAGAIN|| errno == EWOULDBLOCK) { 106 | //g_ctx->log.logdebug(&g_ctx->log,"accept return again or block,%d:%s",errno,strerror(errno)); 107 | return 0; 108 | }else{ 109 | g_ctx->log.logerror(&g_ctx->log,"accept error"); 110 | return 0; 111 | } 112 | } 113 | 114 | if((cctx = new_conn_ctx(arg->ep_fd,fd,conn_handle,arg->timer )) == NULL){ 115 | g_ctx->log.logerror(&g_ctx->log,"%s:new_conn_ctx error",__FUNCTION__); 116 | ret = -1; goto err; 117 | } 118 | cctx->peer_addr = addr; 119 | 120 | if(lx_set_epoll(arg->ep_fd,cctx->fd,cctx,EPOLLIN|EPOLLET,LX_TRUE,LX_TRUE)){ 121 | g_ctx->log.logerror(&g_ctx->log,"lx_set_epoll error"); 122 | ret = -1;goto err; 123 | } 124 | 125 | l_temp = get_micros() + g_ctx->conn_timeout*1000; 126 | while( lx_rbtree_insert(arg->timer,(uint64_t)l_temp,cctx ) != 0){ 127 | l_temp += 1; 128 | } 129 | cctx->timeout = l_temp; 130 | //printf("insert key:%lu\n",(unsigned long)l_temp); 131 | 132 | ret = 0; 133 | //printf("listen handle call end\n"); 134 | return ret; 135 | err: 136 | if(cctx) 137 | cleanup_conn_ctx(cctx); 138 | 139 | if(fd >= 0){ 140 | close(fd); 141 | } 142 | return ret; 143 | } 144 | 145 | int record_end_log(lxasync_conn_ctx * cctx) 146 | { 147 | char buff[1024]; 148 | int ret; 149 | 150 | if( !inet_ntop(AF_INET, (void *)&cctx->peer_addr.sin_addr, buff,16) ){ 151 | g_ctx->log.logerror(&g_ctx->log,"inet_ntop error"); 152 | ret = -1;goto end; 153 | } 154 | 155 | if(getwidetime(time(NULL),buff +16,32) <=0){ 156 | g_ctx->log.logerror(&g_ctx->log,"get_wide_time error"); 157 | ret = -1;goto end; 158 | } 159 | 160 | g_ctx->log.loginfo(&g_ctx->log,"uri:%s,addr:%s:%d,start:%s,duration:%ld" 161 | ,http_get_uri(&cctx->req_ctx.info),buff,(int)ntohs(cctx->peer_addr.sin_port), 162 | buff+16,get_inval_micros(&cctx->accept_time ,NULL)); 163 | 164 | ret = 0; 165 | end: 166 | return ret; 167 | } 168 | 169 | int conn_handle(lxasync_conn_ctx * cctx) 170 | { 171 | int ret; 172 | //printf("conn_handle call\n"); 173 | 174 | #define lx_handle_macro( handle ) \ 175 | if( (ret = (handle)(cctx) ) == HANDLE_NEED_MORE )\ 176 | return 0;\ 177 | else if( ret == HANDLE_ERR )\ 178 | goto done; 179 | 180 | if(cctx->events & EPOLLERR || cctx->events &EPOLLHUP){ 181 | g_ctx->log.logerror(&g_ctx->log,"%s:connection error occur",__FUNCTION__); 182 | goto done; 183 | } 184 | 185 | switch(cctx->stage){ 186 | 187 | case STAGE_START: 188 | cctx->stage = STAGE_REQ_HEAD; 189 | 190 | case STAGE_REQ_HEAD: 191 | lx_handle_macro(req_head_handle) 192 | cctx->stage = STAGE_REQ_BODY; 193 | cctx->contlen = cctx->inoutlen = 0; 194 | /* 195 | if(http_print_http(&cctx->req_ctx)){ 196 | g_ctx->log.logerror(&g_ctx->log,"print_pare_info error"); 197 | } 198 | */ 199 | case STAGE_REQ_BODY: 200 | lx_handle_macro(req_body_handle) 201 | cctx->stage = STAGE_RESP_HEAD; 202 | cctx->data_buff.offset = cctx->data_buff.len = 0; 203 | if(lx_set_epoll(cctx->ep_fd,cctx->fd,cctx,EPOLLOUT|EPOLLET,LX_TRUE,LX_FALSE )){ 204 | g_ctx->log.logerror(&g_ctx->log,"%s:lx_set_epoll error",__FUNCTION__); 205 | goto done; 206 | } 207 | return 0; 208 | 209 | case STAGE_RESP_HEAD: 210 | lx_handle_macro(resp_head_handle) 211 | cctx->stage = STAGE_RESP_BODY; 212 | cctx->fh = NULL; 213 | 214 | case STAGE_RESP_BODY: 215 | lx_handle_macro(resp_body_handle) 216 | cctx->stage = STAGE_DONE; 217 | record_end_log(cctx); 218 | default: 219 | goto done; 220 | } 221 | #undef lx_handle_macro 222 | 223 | done: 224 | 225 | ret = lx_rbtree_delete(cctx->timer,(uint64_t)cctx->timeout); 226 | //printf("delete in done, key:%lu,ret:%d\n",(unsigned long)cctx->timeout,ret); 227 | remove_conn(cctx); 228 | return 0; 229 | } 230 | 231 | 232 | int req_head_handle(lxasync_conn_ctx *pctx ) 233 | { 234 | int ret = 0,read_num = 0,to_read_num = 0; 235 | char * buff; 236 | while(1) 237 | { 238 | buff = lx_buffer_lenp(&pctx->req_ctx.orig_buff); 239 | to_read_num = lx_buffer_freenum(&pctx->req_ctx.orig_buff); 240 | 241 | read_num = recv(pctx->fd,buff,to_read_num,0); 242 | if( read_num < 0){ 243 | if(AGAIN_FLAG){ 244 | ret = HANDLE_NEED_MORE; 245 | goto end; 246 | }else{ 247 | g_ctx->log.logerror(&g_ctx->log,"%s:recv error",__FUNCTION__); 248 | ret = HANDLE_ERR;goto end; 249 | } 250 | }else if( read_num == 0){ 251 | g_ctx->log.logerror(&g_ctx->log,"cannot get enough head info"); 252 | ret = HANDLE_ERR;goto end; 253 | }else{ 254 | pctx->req_ctx.orig_buff.len += read_num; 255 | ret = http_parse(&pctx->req_ctx); 256 | 257 | if( ret == HEC_OK){ 258 | //copy to data_buff 259 | int tocopy = lx_buffer_unscannum( &pctx->req_ctx.orig_buff); 260 | if(tocopy >= pctx->data_buff.maxlen){ 261 | g_ctx->log.logerror(&g_ctx->log,"req body too big to copy to data_buff"); 262 | ret = HANDLE_ERR; 263 | goto end; 264 | } 265 | memcpy(pctx->data_buff.base,lx_buffer_offsetp(&pctx->req_ctx.orig_buff),tocopy); 266 | pctx->data_buff.len = tocopy; 267 | 268 | ret = HANDLE_DONE; 269 | goto end; 270 | }else if( ret == HEC_NEED_MORE) 271 | continue; 272 | else{ 273 | g_ctx->log.logerror(&g_ctx->log,"parser error[%d]",ret); 274 | ret = HANDLE_ERR;goto end; 275 | } 276 | } 277 | } 278 | 279 | end: 280 | return ret; 281 | } 282 | 283 | int req_body_handle(lxasync_conn_ctx *pctx ) 284 | { 285 | int ret,nleft,to_read_num,read_num ; 286 | lx_buffer *data; 287 | 288 | data = &pctx->data_buff; 289 | pctx->contlen =http_get_contlen(&pctx->req_ctx.info); 290 | 291 | if(pctx->contlen <= 0 ) 292 | return HANDLE_DONE; 293 | 294 | if(pctx->inoutlen == 0){ 295 | pctx->inoutlen = pctx->contlen > data->len? data->len:pctx->contlen ; 296 | 297 | printf("req_body:\n"); 298 | printf("%.*s",pctx->inoutlen,data->base); 299 | } 300 | 301 | while( pctx->inoutlen < pctx->contlen ){ 302 | 303 | nleft = pctx->contlen - pctx->inoutlen; 304 | to_read_num = nleft < data->maxlen? nleft : data->maxlen; 305 | read_num = recv(pctx->fd,data->base, to_read_num,0 ); 306 | 307 | if(read_num < 0){ 308 | if(AGAIN_FLAG ){ 309 | ret = HANDLE_NEED_MORE; 310 | goto end; 311 | }else{ 312 | g_ctx->log.logerror(&g_ctx->log,"%s:recv err",__FUNCTION__); 313 | ret = HANDLE_ERR; 314 | goto end; 315 | } 316 | }else if(read_num == 0){ 317 | g_ctx->log.logerror(&g_ctx->log,"%s:can not get enough req body",__FUNCTION__); 318 | ret = HANDLE_ERR; 319 | goto end; 320 | }else{ 321 | printf("%.*s",read_num,data->base ); 322 | pctx->inoutlen += read_num; 323 | } 324 | } 325 | 326 | ret = HANDLE_DONE; 327 | 328 | end: 329 | return ret; 330 | } 331 | 332 | int resp_head_handle(lxasync_conn_ctx *cctx ) 333 | { 334 | int ret, send_num,to_send_num, rcode; 335 | char date[64] ,* uri,*rstr; 336 | h_parser_ctx * resp_ctx; 337 | 338 | char * headers[] = { 339 | "Content-Type" ,"text/html", 340 | "Connection" ,"Keep-Alive", 341 | "Server" ,"lanxin/spl 1.0", 342 | NULL,NULL 343 | }; 344 | 345 | resp_ctx = &cctx->resp_ctx; 346 | if(cctx->data_buff.len == 0){ 347 | if( !(ret = get_browser_time( time(NULL),date,64 ) ) ){ 348 | g_ctx->log.logerror(&g_ctx->log,"%s:snprintf date error",__FUNCTION__); 349 | ret = HANDLE_ERR;goto err; 350 | } 351 | 352 | uri = http_get_uri(&cctx->req_ctx.info); 353 | if( uri == NULL || strcmp(uri, "/") == 0) 354 | uri = "/index.html"; 355 | if( (ret = snprintf(cctx->path,MAX_PATH_LEN,"%s/%s%s",g_home,g_whome,uri)) <= 0 ){ 356 | g_ctx->log.logerror(&g_ctx->log,"%s:snprintf path error",__FUNCTION__); 357 | ret = HANDLE_ERR;goto err; 358 | } 359 | 360 | if( (cctx->contlen = lx_get_fsize(cctx->path) )== -1){ 361 | rcode = 404; 362 | rstr = "File Not Found"; 363 | 364 | g_ctx->log.logerror(&g_ctx->log,"uri invalid ,404,uri:%s", uri); 365 | 366 | if( (ret = snprintf(cctx->path,MAX_PATH_LEN,"%s/%s%s",g_home,g_whome,"/404.html")) <= 0 ){ 367 | g_ctx->log.logerror(&g_ctx->log,"%s:snprintf path error,ret = %d",__FUNCTION__,ret); 368 | ret = HANDLE_ERR;goto err; 369 | } 370 | if( ( cctx->contlen = lx_get_fsize(cctx->path))== -1){ 371 | g_ctx->log.logerror(&g_ctx->log,"open 404 file error:%s",cctx->path); 372 | ret = HANDLE_ERR;goto err; 373 | } 374 | }else{ 375 | rcode = RESP_OK; 376 | rstr = NULL; 377 | } 378 | 379 | if( http_set_prot(resp_ctx,P_HTTP_1_1)) 380 | { 381 | g_ctx->log.logerror(&g_ctx->log,"set prot error"); 382 | ret = HANDLE_ERR;goto err; 383 | } 384 | 385 | if( http_set_rcode(resp_ctx,rcode,rstr)) 386 | { 387 | g_ctx->log.logerror(&g_ctx->log,"set resp code error"); 388 | ret = HANDLE_ERR;goto err; 389 | } 390 | 391 | if(http_set_headers(resp_ctx,headers,cctx->contlen )){ 392 | g_ctx->log.logerror(&g_ctx->log,"set headers error"); 393 | ret = HANDLE_ERR; goto err; 394 | } 395 | 396 | if(http_set_header(resp_ctx,"Date",date )){ 397 | g_ctx->log.logerror(&g_ctx->log,"set headers error"); 398 | ret = HANDLE_ERR; goto err; 399 | } 400 | 401 | if((cctx->data_buff.len = http_seri_head(&resp_ctx->info,T_RESP,cctx->data_buff.base,cctx->data_buff.maxlen)) <= 0){ 402 | g_ctx->log.logerror(&g_ctx->log,"http_ctx_serihead error"); 403 | ret = HANDLE_ERR;goto err; 404 | } 405 | } 406 | 407 | while( lx_buffer_unscannum(&cctx->data_buff) > 0 ){ 408 | to_send_num = lx_buffer_unscannum(&cctx->data_buff); 409 | send_num = send(cctx->fd,lx_buffer_offsetp(&cctx->data_buff),to_send_num,0); 410 | if(send_num < 0){ 411 | if( AGAIN_FLAG ){ 412 | ret = HANDLE_NEED_MORE; 413 | goto err; 414 | }else{ 415 | g_ctx->log.logerror(&g_ctx->log,"%s:send error", __FUNCTION__); 416 | ret = HANDLE_ERR;goto err; 417 | } 418 | }else{ 419 | cctx->data_buff.offset += send_num; 420 | continue; 421 | } 422 | } 423 | 424 | ret = HANDLE_DONE; 425 | err: 426 | return ret; 427 | } 428 | 429 | int fill_send_buff(lxasync_conn_ctx * pctx) 430 | { int read_num,to_read_num; 431 | 432 | to_read_num = pctx->contlen - pctx->inoutlen > pctx->data_buff.maxlen ? pctx->data_buff.maxlen:pctx->contlen - pctx->inoutlen; 433 | read_num =freadn(pctx->fh,pctx->data_buff.base,to_read_num); 434 | 435 | if(read_num <= 0){ 436 | g_ctx->log.logerror(&g_ctx->log, "%s:read response file %s error",__FUNCTION__,pctx->path); 437 | return -1; 438 | } 439 | 440 | pctx->data_buff.len = read_num; 441 | pctx->data_buff.offset = 0; 442 | 443 | return 0; 444 | } 445 | 446 | int resp_body_handle(lxasync_conn_ctx *pctx ) 447 | { 448 | int ret = HANDLE_DONE; 449 | if(pctx->fh == NULL){ 450 | if( (pctx->fh = fopen(pctx->path,"rb" )) ==NULL){ 451 | g_ctx->log.logerror(&g_ctx->log, "%s:open file %s error",__FUNCTION__,pctx->path); 452 | ret = HANDLE_ERR;goto end; 453 | } 454 | pctx->data_buff.offset = pctx->data_buff.len = 0; 455 | pctx->inoutlen = 0; 456 | 457 | if( fill_send_buff(pctx)){ 458 | g_ctx->log.logerror(&g_ctx->log, "%s:fill_send_buff error %s ",__FUNCTION__,pctx->path); 459 | ret = HANDLE_ERR;goto end; 460 | } 461 | pctx->inoutlen += pctx->data_buff.len; 462 | } 463 | 464 | while(1){ 465 | int send_num,to_send_num; 466 | 467 | to_send_num = lx_buffer_unscannum(&pctx->data_buff); 468 | send_num = send(pctx->fd,lx_buffer_offsetp(&pctx->data_buff ), to_send_num,0); 469 | if( send_num < 0){ 470 | if(AGAIN_FLAG){ 471 | ret = HANDLE_NEED_MORE;goto end; 472 | }else{ 473 | g_ctx->log.logerror(&g_ctx->log, "%s:send response body error",__FUNCTION__); 474 | ret = HANDLE_ERR;goto end; 475 | } 476 | }else if(send_num == 0){ 477 | g_ctx->log.logerror(&g_ctx->log, "%s:send response body error,send_num = 0",__FUNCTION__); 478 | ret = HANDLE_ERR;goto end; 479 | }else{ 480 | pctx->data_buff.offset += send_num; 481 | 482 | if( pctx->data_buff.offset == pctx->data_buff.len){ 483 | if( pctx->inoutlen == pctx->contlen){ 484 | ret = HANDLE_DONE; goto end; 485 | }else{ 486 | if( fill_send_buff(pctx)){ 487 | g_ctx->log.logerror(&g_ctx->log, "%s:fill_send_buff error %s ",__FUNCTION__,pctx->path); 488 | ret = HANDLE_ERR;goto end; 489 | } 490 | pctx->inoutlen += pctx->data_buff.len; 491 | continue; 492 | } 493 | }else{ 494 | continue; 495 | } 496 | } 497 | }//end send loop 498 | 499 | ret = HANDLE_DONE; 500 | 501 | end: 502 | if(ret == HANDLE_ERR || ret == HANDLE_DONE){ 503 | if(pctx->fh != NULL){ 504 | fclose(pctx->fh); 505 | pctx->fh = NULL; 506 | } 507 | } 508 | return ret; 509 | } 510 | --------------------------------------------------------------------------------