Initial submission

This commit is contained in:
aixiao 2021-12-19 19:01:38 +08:00
commit 3d3169397f
15 changed files with 1559 additions and 0 deletions

10
Android.mk Normal file
View File

@ -0,0 +1,10 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS = -O2 -pie -Wall
LOCAL_LDFLAGS = -O2 -pie -Wall
LOCAL_ARM_MODE = arm
LOCAL_MODULE = httpudp
LOCAL_MODULE_FILENAME = httpudp
c_src_files = $(wildcard $(LOCAL_PATH)/*.c)
LOCAL_SRC_FILES = $(c_src_files:$(LOCAL_PATH)/%=%)
include $(BUILD_EXECUTABLE)

2
Application.mk Normal file
View File

@ -0,0 +1,2 @@
APP_ABI = arm64-v8a armeabi-v7a
APP_PLATFORM = android-29

26
Makefile Normal file
View File

@ -0,0 +1,26 @@
CROSS_COMPILE ?=
CC := $(CROSS_COMPILE)gcc
STRIP := $(CROSS_COMPILE)strip
OBJ := httpudp
#如果是安卓编译
ifeq ($(ANDROID_DATA),/data)
CFLAGS := -O2 -pie
SHELL := /system/bin/sh
else
CFLAGS := -O2 -pthread -Wall
endif
all : main.o conf.o common.o httpudp.o
$(CC) $(CFLAGS) $(DEFS) -o $(OBJ) $^
$(STRIP) $(OBJ)
-chmod 777 $(OBJ) 2>&-
.c.o :
$(CC) $(CFLAGS) $(DEFS) -c $<
clean :
rm -f *.o
rm $(OBJ)
android:
/usr/lib/android-ndk/ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk APP_BUILD_SCRIPT=Android.mk

28
README.md Normal file
View File

@ -0,0 +1,28 @@
# HttpUDP
提取 [mmmdbybyd](https://github.com/mmmdbybyd) CProxy 中 httpudp 核心功能用于Android
## Build
Linux编译:
make clean; make
windows 10子系统交叉编译:
apt-get install gcc-aarch64-linux-gnu
make clean; CROSS_COMPILE=aarch64-linux-gnu- make
Android NDK 编译:
make android
ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk APP_BUILD_SCRIPT=Android.mk
## Help Information
HttpUDP(2.0.1)
启动命令:
httpudp httpudp.conf
结束命令:
killall httpudp

99
common.c Normal file
View File

@ -0,0 +1,99 @@
#include "common.h"
//有些头文件不声明memmem
void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
void error(const char *error_info)
{
fprintf(stderr, "%s\n\n", error_info);
exit(1);
}
int8_t copy_new_mem(char *src, int src_len, char **dest)
{
*dest = (char *)malloc(src_len + 1);
if (*dest == NULL)
return 1;
memcpy(*dest, src, src_len);
*((*dest) + src_len) = '\0';
return 0;
}
/* 字符串替换replace_memory为可以用free释放的指针 */
char *replace(char *replace_memory, int *replace_memory_len, const char *src, const int src_len, const char *dest, const int dest_len)
{
if (!replace_memory || !src || !dest)
return replace_memory;
char *p;
int diff;
if (src_len == dest_len) {
for (p = memmem(replace_memory, *replace_memory_len, src, src_len); p; p = memmem(p, *replace_memory_len - (p - replace_memory), src, src_len)) {
memcpy(p, dest, dest_len);
p += dest_len;
}
} else if (src_len < dest_len) {
int before_len;
char *before_end, *new_replace_memory;
diff = dest_len - src_len;
for (p = memmem(replace_memory, *replace_memory_len, src, src_len); p; p = memmem(p, *replace_memory_len - (p - replace_memory), src, src_len)) {
*replace_memory_len += diff;
before_len = p - replace_memory;
new_replace_memory = (char *)realloc(replace_memory, *replace_memory_len + 1);
if (new_replace_memory == NULL) {
free(replace_memory);
return NULL;
}
replace_memory = new_replace_memory;
before_end = replace_memory + before_len;
p = before_end + dest_len;
memmove(p, p - diff, *replace_memory_len - (p - replace_memory));
memcpy(before_end, dest, dest_len);
}
} else if (src_len > dest_len) {
diff = src_len - dest_len;
for (p = memmem(replace_memory, *replace_memory_len, src, src_len); p; p = memmem(p, *replace_memory_len - (p - replace_memory), src, src_len)) {
*replace_memory_len -= diff;
memcpy(p, dest, dest_len);
p += dest_len;
memmove(p, p + diff, *replace_memory_len - (p - replace_memory));
}
}
replace_memory[*replace_memory_len] = '\0';
return replace_memory;
}
/* 对数据进行编码 */
void dataEncode(char *data, int data_len, unsigned code)
{
while (data_len-- > 0)
data[data_len] ^= code;
}
/* 监听一个UDP接口 */
int udp_listen(char *ip, int port)
{
struct sockaddr_in addr;
int fd, opt = 1;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("udp socket");
exit(1);
}
setsockopt(fd, SOL_IP, IP_TRANSPARENT, &opt, sizeof(opt));
setsockopt(fd, SOL_IP, IP_RECVORIGDSTADDR, &opt, sizeof(opt));
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
perror("udp bind");
exit(1);
}
return fd;
}

22
common.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include "main.h"
extern char *replace(char *str, int *str_len, const char *src, const int src_len, const char *dest, const int dest_len);
extern void error(const char *msg);
extern int udp_listen(char *ip, int port);
extern void dataEncode(char *data, int data_len, unsigned code);
extern int8_t copy_new_mem(char *src, int src_len, char **dest);
#endif

197
conf.c Normal file
View File

@ -0,0 +1,197 @@
#include "conf.h"
/* 字符串预处理,设置转义字符 */
static void string_pretreatment(char *str, int *len)
{
char *lf, *p, *ori_strs[] = { "\\r", "\\n", "\\b", "\\v", "\\f", "\\t", "\\a", "\\b", "\\0" }, to_chrs[] = { '\r', '\n', '\b', '\v', '\f', '\t', '\a', '\b', '\0' };
int i;
while ((lf = strchr(str, '\n')) != NULL) {
for (p = lf + 1; *p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'; p++)
*len -= 1;
strcpy(lf, p);
*len -= 1;
}
for (i = 0; i < sizeof(to_chrs); i++) {
for (p = strstr(str, ori_strs[i]); p; p = strstr(p, ori_strs[i])) {
//支持\\r
*(p - 1) == '\\' ? (*p--) : (*p = to_chrs[i]);
memmove(p + 1, p + 2, strlen(p + 2));
(*len)--;
}
}
}
/* 在content中设置变量(var)的首地址,值(val)的位置首地址和末地址,返回下一行指针 */
static char *set_var_val_lineEnd(char *content, char **var, char **val_begin, char **val_end)
{
char *p, *pn, *lineEnd;
;
int val_len;
while (1) {
if (content == NULL)
return NULL;
for (; *content == ' ' || *content == '\t' || *content == '\r' || *content == '\n'; content++) ;
if (*content == '\0')
return NULL;
*var = content;
pn = strchr(content, '\n');
p = strchr(content, '=');
if (p == NULL) {
if (pn) {
content = pn + 1;
continue;
} else
return NULL;
}
content = p;
//将变量以\0结束
for (p--; *p == ' ' || *p == '\t'; p--) ;
*(p + 1) = '\0';
//值的首地址
for (content++; *content == ' ' || *content == '\t'; content++) ;
if (*content == '\0')
return NULL;
//双引号引起来的值支持换行
if (*content == '"') {
*val_begin = content + 1;
*val_end = strstr(*val_begin, "\";");
if (*val_end != NULL)
break;
} else
*val_begin = content;
*val_end = strchr(content, ';');
if (pn && *val_end > pn) {
content = pn + 1;
continue;
}
break;
}
if (*val_end) {
**val_end = '\0';
val_len = *val_end - *val_begin;
lineEnd = *val_end;
} else {
val_len = strlen(*val_begin);
*val_end = lineEnd = *val_begin + val_len;
}
string_pretreatment(*val_begin, &val_len);
*val_end = *val_begin + val_len;
//printf("var[%s]\nbegin[%s]\n\n", *var, *val_begin);
return lineEnd;
}
/* 在buff中读取模块(global http https httpdns httpudp)内容 */
static char *read_module(char *buff, const char *module_name)
{
int len;
char *p, *p0;
len = strlen(module_name);
p = buff;
while (1) {
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
p++;
if (strncasecmp(p, module_name, len) == 0) {
p += len;
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
p++;
if (*p == '{')
break;
}
if ((p = strchr(p, '\n')) == NULL)
return NULL;
}
if ((p0 = strchr(++p, '}')) == NULL)
return NULL;
//printf("%s\n%s", module_name, content);
return strndup(p, p0 - p);
}
static void parse_global_module(char *content)
{
char *var, *val_begin, *val_end, *lineEnd, *p;
while ((lineEnd = set_var_val_lineEnd(content, &var, &val_begin, &val_end)) != NULL) {
if (strcasecmp(var, "uid") == 0) {
global.uid = atoi(val_begin);
} else if (strcasecmp(var, "procs") == 0) {
global.procs = atol(val_begin);
} else if (strcasecmp(var, "udp_listen") == 0) {
if ((p = strchr(val_begin, ':')) != NULL && p - val_begin <= 15) {
*p = '\0';
global.udp_listen_fd = udp_listen(val_begin, atoi(p + 1));
} else
global.udp_listen_fd = udp_listen((char *)"0.0.0.0", atoi(val_begin));
} else if (strcasecmp(var, "strict") == 0 && strcasecmp(val_begin, "on") == 0) {
global.strict_modify = 1;
} else if (strcasecmp(var, "timeout") == 0) {
global.timeout_m = atoi(val_begin);
}
content = strchr(lineEnd + 1, '\n');
}
}
static int8_t parse_httpudp_module(char *content)
{
char *var, *val_begin, *val_end, *lineEnd, *p;
while ((lineEnd = set_var_val_lineEnd(content, &var, &val_begin, &val_end)) != NULL) {
if (strcasecmp(var, "addr") == 0) {
if ((p = strchr(val_begin, ':')) != NULL && p - val_begin <= 15) {
*p = '\0';
udp.dst.sin_port = htons(atoi(p + 1));
} else {
udp.dst.sin_port = htons(80);
}
udp.dst.sin_addr.s_addr = inet_addr(val_begin);
} else if (strcasecmp(var, "http_req") == 0) {
udp.http_request_len = val_end - val_begin;
if (copy_new_mem(val_begin, udp.http_request_len, &udp.http_request) != 0)
return 1;
} else if (strcasecmp(var, "encode") == 0) {
udp.encodeCode = (unsigned)atoi(val_begin);
}
content = strchr(lineEnd + 1, '\n');
}
return 0;
}
void read_conf(char *path)
{
char *buff, *global_content, *httpudp_content;
FILE *file;
long file_size;
/* 读取配置文件到缓冲区 */
file = fopen(path, "r");
if (file == NULL)
error("cannot open config file.");
fseek(file, 0, SEEK_END);
file_size = ftell(file);
buff = (char *)alloca(file_size + 1);
if (buff == NULL)
error("out of memory.");
rewind(file);
fread(buff, file_size, 1, file);
fclose(file);
buff[file_size] = '\0';
/* 读取global模块内容 */
if ((global_content = read_module(buff, "global")) == NULL)
error("read global module error");
parse_global_module(global_content);
free(global_content);
/* 读取httpudp模块 */
if (global.udp_listen_fd >= 0) {
if ((httpudp_content = read_module(buff, "httpudp")) == NULL || parse_httpudp_module(httpudp_content) != 0)
error("read httpudp module error");
free(httpudp_content);
}
}

10
conf.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef CONF_H
#define CONF_H
#include <ctype.h>
#include <arpa/inet.h>
#include "main.h"
extern void read_conf(char *path);
#endif

434
httpudp.c Normal file
View File

@ -0,0 +1,434 @@
/*
HTTPUDP模块代理UDP过程:
UDP数据
http请求头
: UDP原始目标地址[struct in_addr]() + UDP长度[uint16_t] + UDP真实数据
: UDP包的长度[uint16_t] + UDP真实数据
socket伪装原目标地址向客户端发送返回的数据(rootUDP代理不上QQ语音)
*/
#include "httpudp.h"
#define MAX_CLIENT_INFO 512
#define HTTP_RSP_SIZE 2048
#define CLIENT_BUFFER_SIZE 65535 //如果可以 尽量一次性读完数据
#define SERVER_BUFFER_SIZE 8192
typedef struct connection_info {
char client_data[CLIENT_BUFFER_SIZE + sizeof(struct sockaddr_in) + sizeof(uint16_t)];
struct sockaddr_in inaddr, toaddr;
struct connection_info *next;
char *rsp_data;
int client_data_len, client_data_sent_len, http_request_sent_len, rsp_data_len, rsp_data_sent_len, server_fd, responseClientFd, timer;
} info_t;
static info_t client_info_list[MAX_CLIENT_INFO];
static struct epoll_event udp_evs[MAX_CLIENT_INFO * 2 + 2], udp_ev;
struct httpudp udp;
static int udp_efd;
static void proxyStop(info_t * info)
{
epoll_ctl(udp_efd, EPOLL_CTL_DEL, info->server_fd, NULL);
epoll_ctl(udp_efd, EPOLL_CTL_DEL, info->responseClientFd, NULL);
close(info->server_fd);
close(info->responseClientFd);
free(info->rsp_data);
info->rsp_data = NULL;
do {
info->server_fd = info->responseClientFd = -1;
info->rsp_data_len = info->rsp_data_sent_len = info->client_data_sent_len = info->http_request_sent_len = 0;
} while ((info = info->next) != NULL);
}
void udp_timeout_check()
{
int i;
for (i = 0; i < MAX_CLIENT_INFO; i++) {
if (client_info_list[i].server_fd > -1) {
if (client_info_list[i].timer >= global.timeout_m)
proxyStop(client_info_list + i);
else
client_info_list[i].timer = 0;
}
}
}
/* 创建udpfd回应客户端 */
static int createRspFd(info_t * client)
{
int opt = 1;
client->responseClientFd = socket(AF_INET, SOCK_DGRAM, 0);
if (client->responseClientFd < 0)
return 1;
fcntl(client->responseClientFd, F_SETFL, O_NONBLOCK);
/*
UDP客户端不需要伪装源目标地址
*/
setsockopt(client->responseClientFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
setsockopt(client->responseClientFd, SOL_IP, IP_TRANSPARENT, &opt, sizeof(opt));
//切换root伪装源目标地址
seteuid(0);
setegid(0);
bind(client->responseClientFd, (struct sockaddr *)&client->toaddr, sizeof(struct sockaddr_in));
//切换回用户设置的uid
setegid(global.uid);
seteuid(global.uid);
return 0;
}
/* 将服务端返回的数据发送到客户端 */
static int outputToClient(info_t * client)
{
char *dataPtr;
int write_len;
if (client->responseClientFd < 0 && createRspFd(client) < 0)
return 1;
client->timer = 0;
dataPtr = client->rsp_data;
//至少要有一个完整的udp包才返回客户端
while ((int)(*(uint16_t *) dataPtr + sizeof(uint16_t)) <= client->rsp_data_len) {
write_len = sendto(client->responseClientFd, dataPtr + sizeof(uint16_t) + client->rsp_data_sent_len, *(uint16_t *) dataPtr - client->rsp_data_sent_len, 0, (struct sockaddr *)&client->inaddr, sizeof(struct sockaddr_in));
//printf("rsp: [write_len:%d, dataLen:%u, sent:%u, total:%d]\n", write_len, *(uint16_t *)dataPtr, client->rsp_data_sent_len, client->rsp_data_len);
if (write_len < 0 && errno == EAGAIN)
return 0;
client->rsp_data_sent_len += write_len;
if (write_len == 0 || write_len < 0) {
//perror("toClient write()");
return 1;
}
if (write_len < *(uint16_t *) dataPtr) {
udp_ev.data.ptr = client;
udp_ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
epoll_ctl(udp_efd, EPOLL_CTL_ADD, client->responseClientFd, &udp_ev);
return 0;
}
dataPtr += write_len + sizeof(uint16_t);
client->rsp_data_len -= write_len + sizeof(uint16_t);
client->rsp_data_sent_len = 0;
}
//发送完已读取到的所有数据 释放内存
if (client->rsp_data_len == 0) {
free(client->rsp_data);
client->rsp_data = NULL;
udp_ev.data.ptr = client;
udp_ev.events = EPOLLIN | EPOLLET;
epoll_ctl(udp_efd, EPOLL_CTL_MOD, client->responseClientFd, &udp_ev);
}
//还有数据未返回给客户端,将未返回的数据复制到内存头
else if (dataPtr > client->rsp_data) {
memmove(client->rsp_data, dataPtr, client->rsp_data_len);
}
return 0;
}
/* 读取服务器的数据并返回给客户端 */
static void recvServer(info_t * in)
{
in->timer = 0;
//当条件成立时表示未接收https回应状态码
if (udp.http_request_len == in->http_request_sent_len) {
static char http_rsp[HTTP_RSP_SIZE];
int read_len;
do {
read_len = read(in->server_fd, http_rsp, HTTP_RSP_SIZE);
if (read_len == 0 || (read_len < 0 && errno != EAGAIN)) {
proxyStop(in);
return;
}
} while (read_len == HTTP_RSP_SIZE);
in->http_request_sent_len++; //不再接收http头
udp_ev.data.ptr = in;
udp_ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
epoll_ctl(udp_efd, EPOLL_CTL_MOD, in->server_fd, &udp_ev);
return;
}
char *new_data;
int read_len;
do {
new_data = (char *)realloc(in->rsp_data, in->rsp_data_len + SERVER_BUFFER_SIZE);
if (new_data == NULL) {
proxyStop(in);
return;
}
in->rsp_data = new_data;
read_len = read(in->server_fd, in->rsp_data + in->rsp_data_len, SERVER_BUFFER_SIZE);
/* 判断是否关闭连接 */
if (read_len <= 0) {
if (read_len == 0 || errno != EAGAIN || in->rsp_data_len == 0) {
proxyStop(in);
return;
}
read_len = 0;
break;
}
if (udp.httpsProxy_encodeCode)
dataEncode(in->rsp_data + in->rsp_data_len, read_len, udp.httpsProxy_encodeCode);
if (udp.encodeCode)
dataEncode(in->rsp_data + in->rsp_data_len, read_len, udp.encodeCode);
in->rsp_data_len += read_len;
} while (read_len == SERVER_BUFFER_SIZE);
outputToClient(in);
}
/* 向服务器发送数据 */
static int sendToServer(info_t * out)
{
info_t *send_info;
int len;
out->timer = 0;
/* 发送http请求头到服务器 */
if (udp.http_request_len > out->http_request_sent_len) {
len = write(out->server_fd, udp.http_request + out->http_request_sent_len, udp.http_request_len - out->http_request_sent_len);
if (len <= 0) {
if (len == 0 || errno != EAGAIN)
return 1;
return 0;
}
if (len > 0) {
out->http_request_sent_len += len;
if (udp.http_request_len == out->http_request_sent_len) {
udp_ev.data.ptr = out;
udp_ev.events = EPOLLIN | EPOLLET;
epoll_ctl(udp_efd, EPOLL_CTL_MOD, out->server_fd, &udp_ev);
}
}
return 0;
}
/* 发送UDP目标地址,UDP数据长度和UDP真实数据到服务器 */
for (send_info = out; send_info; send_info = send_info->next) {
if (send_info->client_data_len == send_info->client_data_sent_len)
continue;
len = write(out->server_fd, send_info->client_data + send_info->client_data_sent_len, send_info->client_data_len - send_info->client_data_sent_len);
//printf("server_fd: %d, write_len: %d, udp_len: %d, sent_le: %d\n", out->server_fd, len, send_info->client_data_len - send_info->client_data_sent_len, send_info->client_data_sent_len);
if (len <= 0) {
if (len == 0 || errno != EAGAIN)
return 1;
break;
}
send_info->client_data_sent_len += len;
if (send_info->client_data_sent_len < send_info->client_data_len)
break;
if (send_info != out) {
//此结构体已用完
send_info->server_fd = -1;
send_info->client_data_sent_len = 0;
}
}
if (send_info == NULL) {
udp_ev.data.ptr = out;
udp_ev.events = EPOLLIN | EPOLLET;
epoll_ctl(udp_efd, EPOLL_CTL_MOD, out->server_fd, &udp_ev);
}
out->next = send_info;
return 0;
}
static void outEvent(info_t * out)
{
if (out->server_fd == -1)
return;
if ((out->rsp_data && outputToClient(out) != 0) || sendToServer(out) != 0)
proxyStop(out);
}
static int recvClient(info_t * client)
{
static char control[1024];
struct msghdr msg;
struct iovec io;
struct cmsghdr *cmsg;
msg.msg_name = &client->inaddr;
msg.msg_namelen = sizeof(client->inaddr);
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
io.iov_base = client->client_data + sizeof(struct sockaddr_in) + sizeof(uint16_t);
io.iov_len = CLIENT_BUFFER_SIZE;
client->client_data_len = recvmsg(global.udp_listen_fd, &msg, 0);
if (client->client_data_len <= 0) {
//perror("recvmsg()");
return 1;
}
/* 取得客户端目标地址 */
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_ORIGDSTADDR && cmsg->cmsg_len >= CMSG_LEN(sizeof(client->toaddr))) {
memcpy(&client->toaddr, CMSG_DATA(cmsg), sizeof(client->toaddr));
break;
}
if (cmsg == NULL)
return 1;
/*
printf("src ip: [%s], port: [%d]\n", inet_ntoa(client->inaddr.sin_addr), ntohs(client->inaddr.sin_port));
printf("dst ip: [%s], port: [%d]\n", inet_ntoa(client->toaddr.sin_addr), ntohs(client->toaddr.sin_port));
*/
//printf("client len: %d\n", client->client_data_len);
//复制udp长度和原始目标地址
memcpy(client->client_data, &client->toaddr, sizeof(struct sockaddr_in));
memcpy(client->client_data + sizeof(struct sockaddr_in), &client->client_data_len, sizeof(uint16_t));
client->client_data_len += sizeof(uint16_t) + sizeof(struct sockaddr_in);
if (udp.encodeCode)
dataEncode(client->client_data, client->client_data_len, udp.encodeCode);
if (udp.httpsProxy_encodeCode)
dataEncode(client->client_data, client->client_data_len, udp.httpsProxy_encodeCode);
client->next = NULL;
return 0;
}
static void connectToServer(info_t * info)
{
info->timer = 0;
info->server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (info->server_fd < 0)
return;
fcntl(info->server_fd, F_SETFL, O_NONBLOCK);
udp_ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
udp_ev.data.ptr = info;
if (epoll_ctl(udp_efd, EPOLL_CTL_ADD, info->server_fd, &udp_ev) != 0) {
close(info->server_fd);
info->server_fd = -1;
} else if (connect(info->server_fd, (struct sockaddr *)&udp.dst, sizeof(udp.dst)) != 0 && errno != EINPROGRESS) {
epoll_ctl(udp_efd, EPOLL_CTL_DEL, info->server_fd, NULL);
close(info->server_fd);
info->server_fd = -1;
}
}
/* 源地址跟目标地址一样的话服务端需要同一个socket转发 */
static int margeClient(info_t * client)
{
int i;
for (i = 0; i < MAX_CLIENT_INFO; i++) {
if (client != client_info_list + i && client_info_list[i].server_fd > -1 && memcmp(((char *)&client->toaddr) + 2, ((char *)&client_info_list[i].toaddr) + 2, 6) == 0 && memcmp(((char *)&client->inaddr) + 2, ((char *)&client_info_list[i].inaddr) + 2, 6) == 0) {
info_t *lastInfo;
for (lastInfo = client_info_list + i; lastInfo->next; lastInfo = lastInfo->next) ;
lastInfo->next = client;
client->server_fd = -2; //保证下次调用margeClient()不匹配到这个结构体 并且不被其他客户端连接使用
client->client_data_sent_len = sizeof(struct sockaddr_in); //不再发送UDP目标地址
//没有收到服务端回应前不发送UDP的数据
if (client_info_list[i].http_request_sent_len > udp.http_request_len) {
udp_ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
udp_ev.data.ptr = client_info_list + i;
epoll_ctl(udp_efd, EPOLL_CTL_MOD, client_info_list[i].server_fd, &udp_ev);
}
return 0;
}
}
return 1;
}
static void new_client()
{
int i;
for (i = 0; i < MAX_CLIENT_INFO; i++) {
if (client_info_list[i].server_fd == -1) {
if (recvClient(client_info_list + i) == 0)
if (margeClient(client_info_list + i) != 0)
connectToServer(client_info_list + i);
return;
}
}
}
static void http_udp_req_init()
{
char dest[22];
sprintf(dest, "%s:%u", inet_ntoa(udp.dst.sin_addr), ntohs(udp.dst.sin_port));
if (udp.http_request) {
udp.http_request_len = strlen(udp.http_request) + 2;
udp.http_request = (char *)realloc(udp.http_request, udp.http_request_len + 1);
if (udp.http_request == NULL)
error("httpudp http request initializate failed.");
strcat(udp.http_request, "\r\n");
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[V]", 3, "HTTP/1.1", 8);
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[H]", 3, dest, strlen(dest));
udp.http_request = replace(udp.http_request, &udp.http_request_len, "\\0", 2, "\0", 1);
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[M]", 3, "CONNECT", 7);
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[url]", 5, "/", 1);
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[U]", 3, "/", 1);
} else { /* 默认使用CONNECT请求 */
if (https.encodeCode) {
dataEncode(dest, strlen(dest), https.encodeCode);
udp.httpsProxy_encodeCode = https.encodeCode;
}
udp.http_request_len = default_ssl_request_len;
copy_new_mem(default_ssl_request, default_ssl_request_len, &udp.http_request);
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[H]", 3, dest, strlen(dest));
memcpy(&udp.dst, &https.dst, sizeof(udp.dst));
}
if (udp.http_request == NULL)
error("out of memory.");
/* 保存原始生成的请求头配合usr_hdr使用 */
if (saveHdrs) {
if (copy_new_mem(udp.http_request, udp.http_request_len, &udp.original_http_request) != 0)
error("out of memory.");
udp.original_http_request_len = udp.http_request_len;
}
}
void udp_init()
{
int i;
//初始化http请求
http_udp_req_init();
//初始化结构体
memset(client_info_list, 0, sizeof(info_t) * MAX_CLIENT_INFO);
for (i = 0; i < MAX_CLIENT_INFO; i++)
client_info_list[i].server_fd = client_info_list[i].responseClientFd = -1;
//创建epoll fd
udp_efd = epoll_create(MAX_CLIENT_INFO * 2 + 1);
if (udp_efd < 0) {
perror("udp epoll_create()");
exit(1);
}
//添加监听socket到epoll
fcntl(global.udp_listen_fd, F_SETFL, O_NONBLOCK);
udp_ev.data.fd = global.udp_listen_fd;
udp_ev.events = EPOLLIN;
epoll_ctl(udp_efd, EPOLL_CTL_ADD, global.udp_listen_fd, &udp_ev);
}
void *udp_loop(void *nullPtr)
{
int n;
while (1) {
n = epoll_wait(udp_efd, udp_evs, MAX_CLIENT_INFO * 2 + 1, -1);
while (n-- > 0) {
if (udp_evs[n].data.fd == global.udp_listen_fd) {
new_client();
} else {
if (udp_evs[n].events & EPOLLIN) {
recvServer((info_t *) udp_evs[n].data.ptr);
}
if (udp_evs[n].events & EPOLLOUT) {
outEvent((info_t *) udp_evs[n].data.ptr);
}
}
}
}
return NULL; //消除编译警告
}

9
httpudp.conf Normal file
View File

@ -0,0 +1,9 @@
global {
uid = 3004;
udp_listen = 10010;
}
httpudp {
addr = 47.240.75.93:10010;
http_req = "[M] [U] [V]\r\nHost: [H]\r\n";
}

33
httpudp.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef HTTPUDP_H
#define HTTPUDP_H
#include "main.h"
/* 定义TPROXY模块需要的选项有些编译器不带这些定义 */
#ifndef IP_TRANSPARENT
#define IP_TRANSPARENT 19
#endif
#ifndef IP_RECVORIGDSTADDR
#define IP_RECVORIGDSTADDR 20
#endif
#ifndef IP_ORIGDSTADDR
#define IP_ORIGDSTADDR 20
#endif
//默认使用HTTPS模块
//#define HTTPUDP_REQUEST "GET / HTTP/1.1\r\nHost: [H]\r\nConnection: Upgrade\r\nSec-WebSocket-Key: ChameleonProxy httpUDP Client\r\nSec-WebSocket-Version: "VERSION"\r\nUpgrade: websocket\r\nProxy-Connection: Keep-Alive\r\n\r\n"
struct httpudp {
struct sockaddr_in dst;
char *http_request, *original_http_request; //original_http_request为初始化生成的请求头用来配合use_hdr语法
int http_request_len, original_http_request_len;
unsigned encodeCode, //数据编码传输
httpsProxy_encodeCode; //CONNECT代理编码
};
extern void udp_timeout_check();
extern void *udp_loop(void *nullPtr);
extern void udp_init();
extern struct httpudp udp;
#endif

79
main.c Normal file
View File

@ -0,0 +1,79 @@
#include <dirent.h>
#include <pthread.h>
#include "main.h"
struct global global;
struct tcp_mode http, https;
struct save_header *saveHdrs;
char *default_ssl_request;
int default_ssl_request_len;
void *timeout_check(void *nullPtr)
{
while (1) {
sleep(60);
if (global.udp_listen_fd >= 0)
udp_timeout_check();
}
return NULL;
}
/* 初始化变量 */
static void initVariable()
{
memset(&global, 0, sizeof(global));
memset(&https, 0, sizeof(https));
memset(&udp, 0, sizeof(udp));
saveHdrs = NULL;
http.dst.sin_family = https.dst.sin_family = udp.dst.sin_family = AF_INET;
global.tcp_listen_fd = global.udp_listen_fd = global.uid = -1;
}
static void server_init()
{
/* 忽略PIPE信号 */
signal(SIGPIPE, SIG_IGN);
//不能用setgid和setuid这两个函数不能切换回root可能导致HTTPUDP代理失败
if (global.uid > -1 && (setegid(global.uid) == -1 || seteuid(global.uid) == -1)) {
perror("setegid(or seteuid)");
exit(1);
}
#ifndef DEBUG
if (daemon(1, 1) == -1) {
perror("daemon");
exit(1);
}
#endif
/*
dns缓存
*/
//while (global.procs-- > 1 && (child_pid = fork()) == 0);
}
static void start_server_loop()
{
//printf("%s", udp.http_request);
//printf("%d\n", udp.http_request_len);
pthread_t thread_id;
if (global.timeout_m)
pthread_create(&thread_id, NULL, &timeout_check, NULL);
udp_init();
udp_loop(NULL);
}
int main(int argc, char *argv[])
{
initVariable();
read_conf(argv[1]);
server_init();
start_server_loop();
return 0;
}

44
main.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef MAIN_H
#define MAIN_H
#include <netinet/in.h>
#include <sys/epoll.h>
#include <time.h>
#include "common.h"
#include "httpudp.h"
#include "conf.h"
struct global {
int tcp_listen_fd, dns_listen_fd, udp_listen_fd, uid, procs, timeout_m;
unsigned mode:3, strict_modify:1;
};
struct save_header {
struct save_header *next;
char *key, *value, *replace_string;
int key_len, value_len, replace_string_len, updateTime, timer;
unsigned notUpdate:1;
};
struct modify {
char *first, *del_hdr, *src, *dest;
struct save_header *saveHdr;
struct modify *next;
int first_len, del_hdr_len, src_len, dest_len;
unsigned flag:3; //判断修改请求头的操作
};
struct tcp_mode {
struct sockaddr_in dst;
struct modify *m;
unsigned encodeCode, //wap_connect模式数据编码传输
uri_strict:1, http_only_get_post:1;
};
extern struct global global;
extern struct tcp_mode https;
extern struct save_header *saveHdrs;
extern int default_ssl_request_len;
extern char *default_ssl_request;
#endif

13
udpServer/Makefile Normal file
View File

@ -0,0 +1,13 @@
CROSS_COMPILE ?=
CC := $(CROSS_COMPILE)gcc
STRIP := $(CROSS_COMPILE)strip
CFLAGS := -O2 -pthread -Wall
BIN := udpServer
all : udpServer.o
$(CC) $(CFLAGS) -o $(BIN) $^
$(STRIP) $(BIN)
-chmod a+x $(BIN)
clean :
rm -f *.o $(BIN)

553
udpServer/udpServer.c Normal file
View File

@ -0,0 +1,553 @@
/*
httpUDPServer代理UDP过程:
[http请求并回应http请求]
: UDP目标地址[steuct in_addr]() + UDP数据长度[uint16_t] + UDP真实数据
UDP数据并接收UDP服务器回应的数据
UDP服务器回应的UDP数据返回给客户端: UDP数据长度[uint16_t] + UDP真实数据
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <poll.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/netfilter_ipv4.h>
#define WEB_SOCKET_RSP "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ChameleonProxy httpUDP Server\r\nVia: ChameleonProxy httpUDP Server\r\n\r\n"
#define HTTP_RSP "HTTP/1.1 200 OK\r\nConnection: Keep-Alive\r\nContent-Length: 999999999\r\nServer: ChameleonProxy httpUDP Server\r\n\r\n"
#define SSL_RSP "HTTP/1.1 200 Connection established\r\nConnection: Keep-Alive\r\nServer: ChameleonProxy httpUDP Server\r\n\r\n"
#define BUFFER_SIZE 4096+65535
#define DEFAULT_TIMEOUT_S 20
#define DEFAULT_THEAD_POOL_SIZE 30
#define HTTP_TYPE 0
#define OTHER_TYPE 1
struct clientData {
char buffer[BUFFER_SIZE+1], *client_data, *udpData;
struct sockaddr_in udpDst;
int client_data_len, clientfd, remote_udpfd;
uint16_t udpData_len;
unsigned sentRspHttpReq :1;
};
struct clientData publicConn; //主线程设置该变量,子线程复制
pthread_cond_t thCond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t thMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_t master_thId; //主线程的线程id
int listenfd = -1,
timeout_s = DEFAULT_TIMEOUT_S,
thread_pool_size = DEFAULT_THEAD_POOL_SIZE;
uint8_t encodeCode = 0;
void usage()
{
printf("httpudp server(0.3):\n"
"Author: CuteBi\n"
"E-mail: 915445800@qq.com\n"
" -l \033[20G listen port\n"
" -t \033[20G timeout(s) defaule is %d s\n"
" -w \033[20G worker proc\n"
" -p \033[20G thread pool size default is %d\n"
" -e \033[20G encode data code(128-255) default is 0\n"
" -u \033[20G set uid\n\n", DEFAULT_TIMEOUT_S, DEFAULT_THEAD_POOL_SIZE);
exit(0);
}
/* 对数据进行编码 */
void dataEncode(char *data, int data_len)
{
while (data_len-- > 0)
data[data_len] ^= encodeCode;
}
/* 判断请求类型 */
uint8_t request_type(char *req)
{
if (strncmp(req, "GET", 3) == 0 ||
strncmp(req, "POST", 4) == 0 ||
strncmp(req, "CONNECT", 7) == 0 ||
strncmp(req, "HEAD", 4) == 0 ||
strncmp(req, "PUT", 3) == 0 ||
strncmp(req, "OPTIONS", 7) == 0 ||
strncmp(req, "MOVE", 4) == 0 ||
strncmp(req, "COPY", 4) == 0 ||
strncmp(req, "TRACE", 5) == 0 ||
strncmp(req, "DELETE", 6) == 0 ||
strncmp(req, "LINK", 4) == 0 ||
strncmp(req, "UNLINK", 6) == 0 ||
strncmp(req, "PATCH", 5) == 0 ||
strncmp(req, "WRAPPED", 7) == 0)
return HTTP_TYPE;
else
return OTHER_TYPE;
}
/* 回应HTTP请求 */
int rspHttpReq(struct clientData *client)
{
/* 回应CONNECT请求 */
if (strncmp(client->client_data, "CON", 3) == 0)
{
if (write(client->clientfd, SSL_RSP, sizeof(SSL_RSP) - 1) <= 0)
{
perror("ssl rsp write()");
return 1;
}
}
/* 回应WebSocket请求 */
else if (strstr(client->client_data, "websocket"))
{
if (write(client->clientfd, WEB_SOCKET_RSP, sizeof(WEB_SOCKET_RSP) - 1) <= 0)
{
perror("websocket rsp write()");
return 1;
}
}
/* 回应HTTP请求 */
else
{
if (write(client->clientfd, HTTP_RSP, sizeof(HTTP_RSP) - 1) <= 0)
{
perror("http rsp write()");
return 1;
}
}
client->sentRspHttpReq = 1;
return 0;
}
/* 得到客户端数据中的udpDataLen dstAddr */
int parse_request(struct clientData *client)
{
char *headerEnd;
if (request_type(client->client_data) == OTHER_TYPE)
{
client->udpData = client->client_data;
}
else
{
headerEnd = strstr(client->client_data, "\n\r\n");
if (headerEnd == NULL)
{
//puts("headerEnd NULL.");
return 1;
}
*headerEnd = '\0';
if (client->sentRspHttpReq == 0 && rspHttpReq(client) != 0)
return 1;
*headerEnd = '\n';
client->udpData = headerEnd + 3;
}
if ((int)(client->client_data_len - (client->udpData - client->client_data) - sizeof(struct sockaddr_in) - sizeof(uint16_t)) <= 0)
return 1;
if (encodeCode)
dataEncode(client->udpData, (int)(client->client_data_len - (client->udpData - client->client_data)));
/* 复制UDP目标地址跟UDP长度 */
memcpy(&client->udpDst, client->udpData, sizeof(struct sockaddr_in));
memcpy(&(client->udpData_len), (uint16_t *)(client->udpData + sizeof(struct sockaddr_in)), sizeof(uint16_t));
client->udpData += sizeof(struct sockaddr_in);
//printf("len: [%u] dataLen: [%d], ip: [%s], port: [%d]\n", client->udpData_len, (int)(client->client_data_len - (client->udpData - client->client_data)), inet_ntoa(client->udpDst.sin_addr), ntohs(client->udpDst.sin_port));
return 0;
}
int recvServer(struct clientData *server)
{
int read_len;
while ((read_len = recv(server->remote_udpfd, server->buffer + sizeof(uint16_t), BUFFER_SIZE - sizeof(uint16_t), MSG_DONTWAIT)) > 0)
{
//printf("%u: read remote: [%d]\n", pthread_self(), read_len);
memcpy(server->buffer, &read_len, sizeof(uint16_t));
//printf("server read_len: [%d], server->buffer: [%u]\n", read_len, *(uint16_t *)server->buffer);
read_len += sizeof(uint16_t);
if (encodeCode)
dataEncode(server->buffer, read_len);
if (write(server->clientfd, server->buffer, read_len) != read_len)
{
perror("write to client()");
return 1;
}
}
if (read_len == 0 || errno != EAGAIN)
{
perror("server recv()");
return 1;
}
return 0;
}
/*
null
*/
char *sendServer(struct clientData *client)
{
char *dataPtr;
int write_len;
dataPtr = client->client_data;
//client->client_data_len > 1才能满意uint16_t这个类型的储存空间
while (client->client_data_len > 1 && (int)(*(uint16_t *)dataPtr + sizeof(uint16_t)) <= client->client_data_len)
{
if ((write_len = write(client->remote_udpfd, dataPtr+sizeof(uint16_t), *(uint16_t *)dataPtr)) != *(uint16_t *)dataPtr)
{
perror("write to remote()");
return NULL;
}
//printf("%u, fd: %d, write_len: %d, client_data_len: %d\n", pthread_self(), client->remote_udpfd, write_len, client->client_data_len);
dataPtr += write_len + sizeof(uint16_t);
client->client_data_len -= write_len + sizeof(uint16_t);
}
return client->client_data_len > 0 ? dataPtr : NULL;
}
int recvClient(struct clientData *client)
{
char *new_data, *dataPtr;
int read_len;
do {
new_data = (char *)realloc(client->client_data, client->client_data_len + BUFFER_SIZE);
if (new_data == NULL)
return 1;
client->client_data = new_data;
read_len = recv(client->clientfd, client->client_data + client->client_data_len, BUFFER_SIZE, MSG_DONTWAIT);
printf("%lu: get client len: [%d]\n", pthread_self(), read_len);
if (read_len <= 0)
{
if (read_len == 0 || errno != EAGAIN)
{
perror("client read()");
return 1;
}
return 0;
}
if (encodeCode)
dataEncode(client->client_data + client->client_data_len, read_len);
client->client_data_len += read_len;
dataPtr = sendServer(client);
//write()发生错误
if (dataPtr == NULL && client->client_data_len > 0)
{
return 1;
}
else if (client->client_data_len > 0)
{
memmove(client->client_data, dataPtr, client->client_data_len);
}
else
{
free(client->client_data);
client->client_data = NULL;
client->client_data_len = 0;
}
} while (read_len == BUFFER_SIZE);
return 0;
}
void forwardData(struct clientData *client)
{
struct pollfd pfds[2];
pfds[0].fd = client->remote_udpfd;
pfds[1].fd = client->clientfd;
pfds[0].events = pfds[1].events = POLLIN;
while (poll(pfds, 2, timeout_s*1000) > 0)
{
printf("a event %lu\n", pthread_self());
if (pfds[0].revents & POLLIN)
{
printf("recvServer %lu\n", pthread_self());
if (recvServer(client) != 0)
return;
}
if (pfds[1].revents & POLLIN)
{
printf("recvServer %lu\n", pthread_self());
if (recvClient(client) != 0)
return;
}
}
}
int sendFirstData(struct clientData *client)
{
char *dataPtr;
printf("%lu: sendFirstData\n", pthread_self());
client->remote_udpfd = socket(AF_INET, SOCK_DGRAM, 0);
if (client->remote_udpfd < 0)
{
perror("socket()");
return 1;
}
connect(client->remote_udpfd, (struct sockaddr *)&client->udpDst, sizeof(struct sockaddr_in));
client->client_data = client->udpData;
client->client_data_len = client->udpData_len + sizeof(uint16_t);
dataPtr = sendServer(client);
if (dataPtr == NULL)
{
if (client->client_data_len > 0)
return 1;
client->client_data = NULL;
}
else
{
client->client_data = (char *)malloc(client->client_data_len);
if (client->client_data == NULL)
return 1;
memcpy(client->client_data, dataPtr, client->client_data_len);
}
printf("%lu: sendFirstData end\n", pthread_self());
return 0;
}
int parseClient(struct clientData *client)
{
int read_len, count;
printf("%lu: parseClient\n", pthread_self());
count = 0;
client->client_data = client->buffer;
do {
//printf("%u: start read\n", pthread_self());
read_len = read(client->clientfd, client->client_data + client->client_data_len, BUFFER_SIZE - client->client_data_len);
//printf("%u: read_len = %d\n", pthread_self(), read_len);
if (read_len <= 0)
{
perror("parseClient read()");
return 1;
}
client->client_data_len += read_len;
client->client_data[client->client_data_len] = '\0';
count++;
} while (parse_request(client) != 0 && count < 5);
//printf("%u: parseClient end\n", pthread_self());
return count == 5 ? 1 : 0;
}
void *new_connection(void *nullPtr)
{
#define NO_COPY_SIZE (BUFFER_SIZE + 1 + (sizeof(char *)<<1) + sizeof(struct sockaddr_in)) //struct clientData不需要全部复制
struct clientData client;
//printf("new_connection: %u\n", pthread_self())
memcpy((void *)(&client) + NO_COPY_SIZE, (void *)(&publicConn) + NO_COPY_SIZE, sizeof(struct clientData) - NO_COPY_SIZE);
pthread_kill(master_thId, SIGUSR1);
/* 读取客户端数据 */
if (parseClient(&client) == 0 && sendFirstData(&client) == 0)
forwardData(&client);
else
puts("parseClient() client error");
close(client.remote_udpfd);
close(client.clientfd);
if (client.client_data != client.buffer && client.client_data != client.udpData)
free(client.client_data);
//printf("new_connection end: %u\n", pthread_self());
return NULL;
}
int accept_client()
{
struct sockaddr_in addr;
struct timeval tv = {timeout_s, 0};
socklen_t addr_len = sizeof(addr);
publicConn.clientfd = accept(listenfd, (struct sockaddr *)&addr, &addr_len);
if (publicConn.clientfd < 0)
{
perror("accept()");
return 1;
}
setsockopt(publicConn.clientfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
return 0;
}
void *threadPool_waitTask(void *ptr)
{
int *isBusy;
isBusy = (int *)ptr;
while (1)
{
pthread_cond_wait(&thCond, &thMutex);
pthread_mutex_unlock(&thMutex); //解锁,让其他线程可以并发
*isBusy = 1;
new_connection(NULL);
*isBusy = 0;
}
return NULL;
}
void loop()
{
pthread_t th_id;
pthread_attr_t attr;
sigset_t sig;
int *th_isBusy, //线程执行繁忙值为1空闲值为0
i, signum;
//初始化publicConn
memset(&publicConn, 0, sizeof(struct clientData));
publicConn.remote_udpfd = -1;
/* 创建线程池 */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
th_isBusy = (int *)calloc(thread_pool_size, sizeof(int));
if (th_isBusy == NULL)
{
perror("calloc()");
return;
}
for (i = 0; i < thread_pool_size; i++)
pthread_create(&th_id, &attr, &threadPool_waitTask, (void *)(th_isBusy + i));
/* 初始化信号设置,用于子线程告诉主线程内存已经拷贝完毕 */
sigemptyset(&sig);
sigaddset(&sig, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &sig, NULL);
master_thId = pthread_self();
while (1)
{
if (accept_client() != 0)
{
sleep(3);
continue;
}
/* 如果线程池有空闲线程则调用空闲线程处理 */
for (i = 0; i < thread_pool_size; i++)
{
if (th_isBusy[i] == 0)
{
pthread_cond_signal(&thCond);
break;
}
}
/* 线程池没有空闲线线程,创建新线程运行任务 */
if (i == thread_pool_size)
{
if (pthread_create(&th_id, &attr, &new_connection, NULL) != 0)
{
close(publicConn.clientfd);
continue;
}
}
sigwait(&sig, &signum);
}
}
int create_listen(char *ip, int port)
{
int fd, optval = 1;
struct sockaddr_in addr;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket()");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
{
close(fd);
perror("setsockopt()");
return -1;
}
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
{
close(fd);
perror("bind()");
return -1;
}
if (listen(fd, 500) != 0)
{
close(fd);
perror("listen()");
return -1;
}
return fd;
}
void readCmd(int argc, char **argv)
{
int opt, worker_proc;
while ((opt = getopt(argc, argv, "l:u:e:w:p:t:h")) != -1)
{
switch (opt)
{
case 't':
timeout_s = atoi(optarg);
break;
case 'e':
encodeCode = atoi(optarg);
break;
case 'l':
listenfd = create_listen((char *)"0.0.0.0", atoi(optarg));
break;
case 'u':
if (setgid(atoi(optarg)) || setuid(atoi(optarg)))
perror("setgid(or setuid)()");
break;
case 'w':
worker_proc = atoi(optarg);
while (worker_proc-- > 1 && fork());
break;
case 'p':
thread_pool_size = atoi(optarg);
break;
case 'h':
usage();
break;
}
}
}
int main(int argc, char **argv)
{
readCmd(argc, argv);
if (listenfd < 0)
{
usage();
return 1;
}
if (daemon(1, 1) == -1)
{
perror("daemon()");
return 1;
}
signal(SIGPIPE, SIG_IGN);
loop();
return 0;
}