-
Notifications
You must be signed in to change notification settings - Fork 2
/
cgi.cpp
146 lines (139 loc) · 4 KB
/
cgi.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include "processpool.h"
//用于处理客户CGI请求的类,它可以作为processpool类的模板参数
class cgi_conn
{
private:
//读缓冲区的大小
static const int BUFFER_SIZE = 1024;
static int m_epollfd;
int m_sockfd;
sockaddr_in m_address;
char m_buf[BUFFER_SIZE];
//标记读缓冲中已经读入的客户数据的最后一个字节的下一个位置
int m_read_idx;
public:
cgi_conn(){}
~cgi_conn(){}
//初始化客户链接,清空读缓冲区
void init(int epollfd, int sockfd, const sockaddr_in& client_addr)
{
m_epollfd = epollfd;
m_sockfd = sockfd;
m_address = client_addr;
memset(m_buf, '\0', BUFFER_SIZE);
m_read_idx = 0;
}
void process()
{
int idx = 0;
int ret = -1;
//循环读取和分析客户数据
while(true)
{
idx = m_read_idx;
ret = recv(m_sockfd, m_buf + idx, BUFFER_SIZE - 1 - idx, 0);
//如果读操作发送错误,则关闭客户连接。但如果是暂时无数据可读,则退出循环
if(ret < 0)
{
if(errno != EAGAIN)
{
removefd(m_epollfd, m_sockfd);
}
break;
}
//如果对方关闭连接,则服务器也关闭连接
else if(ret == 0)
{
removefd(m_epollfd, m_sockfd);
break;
}
else
{
m_read_idx += ret;
printf("user content is:%s\n", m_buf);
//如果遇到字符“\r\n”,则开始处理客户请求
for(;idx < m_read_idx; ++ idx)
{
if((idx >= 1) && (m_buf[idx - 1] == '\r') && (m_buf[idx] == '\n'))
{
break;
}
}
if(idx == m_read_idx) continue;
m_buf[idx - 1] = '\0';
char* file_name = m_buf;
//判断客户要运行的cgi程序是否存在
if(access(file_name, F_OK) == -1)
{
removefd(m_epollfd, m_sockfd);
break;
}
//创建子进程来执行CGI程序
ret = fork();
if(ret == -1)
{
removefd(m_epollfd, m_sockfd);
break;
}
else if(ret > 0)
{
removefd(m_epollfd, m_sockfd);
break;
}
else
{
close(STDOUT_FILENO);
dup(m_sockfd);
execl(m_buf, m_buf, 0);
exit(0);
}
}
}
}
};
int cgi_conn::m_epollfd = -1;
int main(int argc, char* argv[])
{
if(argc <= 2)
{
printf("usage: %s ip_adress port_number\n", basename(argv[0]));
return 1;
}
const char* ip = argv[1];
int port = atoi(argv[2]);
int listenfd = socket(PF_INET, SOCK_STREAM, 0);
assert(listenfd >= 0);
int ret = 0;
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);
ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));
assert(ret != -1);
ret = listen(listenfd, 5);
assert(ret != -1);
Processpool<cgi_conn>* pool = Processpool<cgi_conn>::create(listenfd);
if(pool)
{
pool->run();
delete pool;
}
close(listenfd);
return 0;
}