CProxy/cproxy.c
aixiao e0261c8942 修改: Makefile
修改:     README.md
	修改:     conf.c
	修改:     conf.h
	修改:     conf/cproxy.ini
	修改:     cproxy.c
	修改:     cproxy.h
	新文件:   cproxy_help.c
	新文件:   cproxy_help.h
	修改:     cproxy_request.c
	修改:     cproxy_request.h
	修改:     log/cproxy.pid
2019-02-07 17:26:48 +08:00

297 lines
7.5 KiB
C

#include "cproxy.h"
char *read_data(int client_sock, char *data, int *data_len)
{
char *new_data;
int read_len;
do {
new_data = (char *)realloc(data, *data_len + BUF_SIZE + 1);
if (new_data == NULL) {
free(data);
return NULL;
}
data = new_data;
read_len = read(client_sock, data + *data_len, BUF_SIZE);
if (read_len <= 0) {
if (read_len == 0 || *data_len == 0 || errno != EAGAIN) {
free(data);
return NULL;
}
break;
}
*data_len += read_len;
} while (read_len == BUF_SIZE);
*(data + *data_len) = '\0';
return data;
}
void servertoclient(int remote_sock, int client_sock, char *complete_data, int *len_complete_data)
{
while ((*len_complete_data = read(remote_sock, complete_data, BUF_SIZE)) > 0) {
write(client_sock, complete_data, *len_complete_data);
}
}
void clienttoserver(int remote_sock, char *complete_data, int *len_complete_data)
{
write(remote_sock, complete_data, *len_complete_data);
complete_data = NULL;
complete_data = 0;
}
// 处理客户端的连接
void handle_client(int client_sock, struct sockaddr_in client_addr, conf *configure)
{
read_data(client_sock, header_buffer, &len_header_buffer); // 第一次读取客户端(浏览器)数据
SIGN = request_type(header_buffer); // 获取请求消息类型
extract_host(header_buffer); // 提取真实Host
replacement_http_head(header_buffer, remote_host, &remote_port, &SIGN, configure);
//printf("%s", header_buffer);
//printf("%s\n", remote_host);
//printf("%d\n", remote_port);
if ((remote_sock = create_connection(configure, SIGN)) < 0) {
return;
}
if (fork() == 0) {
if (SIGN == HTTP_CONNECT) {
clienttoserver(remote_sock, header_buffer, &len_header_buffer);
forward_data(client_sock, remote_sock);
} else if (SIGN == HTTP_OTHERS || SIGN == HTTP) {
forward_header(remote_sock); //普通的http请求先转发header
forward_data(client_sock, remote_sock);
}
exit(0);
}
if (fork() == 0) {
if (SIGN == HTTP_CONNECT) {
servertoclient(remote_sock, client_sock, complete_data, &len_complete_data);
} else if (SIGN == HTTP_OTHERS || SIGN == HTTP) {
forward_data(remote_sock, client_sock);
}
exit(0);
}
close(client_sock);
close(remote_sock);
}
int send_data(int socket, char *buffer, int len)
{
return send(socket, buffer, len, 0);
}
int receive_data(int socket, char *buffer, int len)
{
int n = recv(socket, buffer, len, 0);
return n;
}
void forward_data(int source_sock, int destination_sock)
{
char buffer[BUF_SIZE];
int n;
while ((n = receive_data(source_sock, buffer, BUF_SIZE)) > 0) {
send_data(destination_sock, buffer, n);
}
shutdown(destination_sock, SHUT_RDWR);
shutdown(source_sock, SHUT_RDWR);
}
int create_connection(conf * configure, int SIGN)
{
struct sockaddr_in server_addr;
struct hostent *server;
int sock;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return CLIENT_SOCKET_ERROR;
}
if (SIGN == HTTP_CONNECT) {
if ((server = gethostbyname(configure->https_ip)) == NULL) {
errno = EFAULT;
return CLIENT_RESOLVE_ERROR;
}
} else if (SIGN == HTTP_OTHERS || SIGN == HTTP) {
if ((server = gethostbyname(configure->http_ip)) == NULL) {
errno = EFAULT;
return CLIENT_RESOLVE_ERROR;
}
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length);
if (SIGN == HTTP_CONNECT) {
server_addr.sin_port = htons(configure->https_port);
} else if (SIGN == HTTP_OTHERS || SIGN == HTTP) {
server_addr.sin_port = htons(configure->http_port);
}
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
return CLIENT_CONNECT_ERROR;
}
return sock;
}
int create_server_socket(int port)
{
int server_sock, optval;
struct sockaddr_in server_addr;
if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return SERVER_SOCKET_ERROR;
}
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
return SERVER_SETSOCKOPT_ERROR;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))
!= 0) {
return SERVER_BIND_ERROR;
}
if (listen(server_sock, 20) < 0) {
return SERVER_LISTEN_ERROR;
}
return server_sock;
}
// 守护
int init_daemon(int nochdir, int noclose, conf * configure)
{
FILE *fp = fopen(configure->server_pid_file, "w");
int pid;
if ((pid = fork()) < 0) {
return -1;
} else if (0 != pid) {
exit(0);
}
//child 1 continues...
//become session leader
if (setsid() < 0) {
return -1;
}
signal(SIGHUP, SIG_IGN);
if ((pid = fork()) < 0) {
return -1;
} else if (0 != pid) {
fprintf(fp, "%d", pid);
exit(0);
}
//child 2 continues...
//change working directory
if (0 == nochdir) {
chdir("/");
}
//redirect stdin,stdout,stderror to "/dev/null"
if (0 == noclose) {
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR);
}
fclose(fp);
return 0;
}
// 处理僵尸进程
void sigchld_handler(int signal)
{
while (waitpid(-1, NULL, WNOHANG) > 0) ;
}
void server_loop(conf * configure)
{
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
while (1) {
client_sock =
accept(server_sock, (struct sockaddr *)&client_addr, &addrlen);
if (fork() == 0) { // 创建子进程处理客户端连接请求
handle_client(client_sock, client_addr, configure);
close(client_sock);
exit(0);
}
}
close(server_sock);
}
void start_server(conf * configure)
{
signal(SIGCHLD, sigchld_handler); // 防止子进程变成僵尸进程
if ((server_sock = create_server_socket(local_port)) < 0) {
exit(server_sock);
}
server_loop(configure);
}
int _main(int argc, char *argv[])
{
//初始化全局变量
header_buffer = (char *)malloc(BUF_SIZE);
len_header_buffer = strlen(header_buffer);
complete_data = (char *)malloc(BUF_SIZES);
len_complete_data = strlen(complete_data);
char *inifile = "conf/cproxy.ini";
conf *configure = (struct CONF *)malloc(sizeof(struct CONF));
read_conf(inifile, configure);
local_port = configure->server_port;
int opt;
char optstrs[] = ":l:dh";
while (-1 != (opt = getopt(argc, argv, optstrs))) {
switch (opt) {
case 'l':
local_port = atoi(optarg);
break;
case 'd':
init_daemon(1, 1, configure);
break;
case 'h':
help_information();
exit(0);
break;
default:
;
}
}
start_server(configure);
free_conf(configure);
free(complete_data);
free(header_buffer);
return 0;
}
int main(int argc, char *argv[])
{
return _main(argc, argv);
}