├── 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 |
--------------------------------------------------------------------------------