diff --git a/conev.c b/conev.c index 713a69a..f4c6d49 100644 --- a/conev.c +++ b/conev.c @@ -89,10 +89,9 @@ void del_event(struct poolhd *pool, struct eval *val) #else epoll_ctl(pool->efd, EPOLL_CTL_DEL, val->fd, 0); #endif - if (val->buff.data) { - assert(val->buff.size); - free(val->buff.data); - val->buff.data = 0; + if (val->buff && val->buff->lock) { + val->buff->lock = 0; + val->buff->offset = 0; } close(val->fd); val->fd = -1; @@ -130,10 +129,6 @@ void destroy_pool(struct poolhd *pool) close(val->fd); val->fd = 0; } - if (val->buff.data) { - free(val->buff.data); - val->buff.data = 0; - } } free(pool->items); free(pool->links); @@ -142,6 +137,7 @@ void destroy_pool(struct poolhd *pool) if (pool->efd) close(pool->efd); #endif + buff_destroy(pool->root_buff); memset(pool, 0, sizeof(*pool)); free(pool); } @@ -216,3 +212,43 @@ int mod_etype(struct poolhd *pool, struct eval *val, int type) return 0; } #endif + + +struct buffer *buff_get(struct buffer *root, size_t size) +{ + struct buffer *prev = root; + + while (root) { + if (!root->lock) { + return root; + } + prev = root; + root = root->next; + } + struct buffer *buff = malloc(sizeof(struct buffer) + size); + if (!buff) { + uniperror("malloc"); + return 0; + } + LOG(LOG_S, "alloc new buffer\n"); + + memset(buff, 0, sizeof(struct buffer)); + buff->data = (char *)buff + sizeof(struct buffer); + buff->size = size; + + if (prev) { + prev->next = buff; + } + return buff; +} + + +void buff_destroy(struct buffer *root) +{ + while (root) { + struct buffer *c = root; + root = root->next; + free(c); + } +} + diff --git a/conev.h b/conev.h index 4fdc391..0d280f4 100644 --- a/conev.h +++ b/conev.h @@ -70,6 +70,8 @@ struct buffer { size_t size; unsigned int offset; char *data; + size_t lock; + struct buffer *next; }; struct eval { @@ -78,7 +80,7 @@ struct eval { unsigned long long mod_iter; enum eid type; struct eval *pair; - struct buffer buff; + struct buffer *buff; int flag; union sockaddr_u addr; ssize_t recv_count; @@ -101,6 +103,7 @@ struct poolhd { struct pollfd *pevents; #endif unsigned long long iters; + struct buffer *root_buff; }; struct poolhd *init_pool(int count); @@ -117,4 +120,7 @@ struct eval *next_event(struct poolhd *pool, int *offs, int *type); int mod_etype(struct poolhd *pool, struct eval *val, int type); +struct buffer *buff_get(struct buffer *root, size_t size); + +void buff_destroy(struct buffer *root); #endif diff --git a/extend.c b/extend.c index 58e069a..0ed1380 100644 --- a/extend.c +++ b/extend.c @@ -164,7 +164,7 @@ static int reconnect(struct poolhd *pool, struct eval *val, int m) //client->type = EV_IGNORE; client->attempt = m; client->cache = 1; - client->buff.offset = 0; + client->buff->offset = 0; client->round_sent = 0; return 0; } @@ -258,8 +258,9 @@ static int on_trigger(int type, struct poolhd *pool, struct eval *val) { int m = val->pair->attempt + 1; + struct buffer *pair_buff = val->pair->buff; bool can_reconn = ( - val->pair->buff.data && !val->recv_count + pair_buff && pair_buff->lock && !val->recv_count && params.auto_level > AUTO_NOBUFF ); if (!can_reconn && params.auto_level <= AUTO_NOSAVE) { @@ -317,8 +318,8 @@ static int on_response(struct poolhd *pool, struct eval *val, { int m = val->pair->attempt + 1; - char *req = val->pair->buff.data; - ssize_t qn = val->pair->buff.size; + char *req = val->pair->buff->data; + ssize_t qn = val->pair->buff->size; for (; m < params.dp_count; m++) { struct desync_params *dp = ¶ms.dp[m]; @@ -346,9 +347,8 @@ static inline void free_first_req(struct eval *client) { client->type = EV_TUNNEL; client->pair->type = EV_TUNNEL; - - free(client->buff.data); - memset(&client->buff, 0, sizeof(client->buff)); + client->buff->lock = 0; + client->buff->offset = 0; } @@ -395,19 +395,19 @@ static int cancel_setup(struct eval *remote) } -static int send_saved_req(struct poolhd *pool, - struct eval *client, char *buffer, ssize_t bfsize) +static int send_saved_req(struct poolhd *pool, struct eval *client) { - ssize_t offset = client->buff.offset; - ssize_t n = client->buff.size - offset; - assert(bfsize >= n); - memcpy(buffer, client->buff.data + offset, n); + struct buffer *buff = buff_get(pool->root_buff, params.bfsize); - ssize_t sn = tcp_send_hook(client->pair, buffer, bfsize, n); + ssize_t offset = client->buff->offset; + ssize_t n = client->buff->lock - offset; + memcpy(buff->data, client->buff->data + offset, n); + + ssize_t sn = tcp_send_hook(pool, client->pair, buff, n); if (sn < 0) { return -1; } - client->buff.offset += sn; + client->buff->offset += sn; if (sn < n) { if (mod_etype(pool, client->pair, POLLOUT) || mod_etype(pool, client, 0)) { @@ -419,9 +419,10 @@ static int send_saved_req(struct poolhd *pool, } -int on_first_tunnel(struct poolhd *pool, - struct eval *val, char *buffer, size_t bfsize, int etype) +int on_first_tunnel(struct poolhd *pool, struct eval *val, int etype) { + struct buffer *buff = buff_get(pool->root_buff, params.bfsize); + if ((etype & POLLOUT) && val->flag == FLAG_CONN) { if (mod_etype(pool, val, POLLIN) || mod_etype(pool, val->pair, POLLIN)) { @@ -429,31 +430,28 @@ int on_first_tunnel(struct poolhd *pool, return -1; } val->pair->type = EV_FIRST_TUNNEL; - return send_saved_req(pool, val->pair, buffer, bfsize); + return send_saved_req(pool, val->pair); } - ssize_t n = tcp_recv_hook(pool, val, buffer, bfsize); + ssize_t n = tcp_recv_hook(pool, val, buff); if (n < 1) { return n; } if (val->flag != FLAG_CONN) { - val->buff.size += n; - - if (val->buff.size >= bfsize) { + if (!val->buff) { + val->buff = buff; + } + val->buff->lock += n; + if (val->buff->lock >= val->buff->size) { free_first_req(val); - } + } else { - val->buff.data = realloc(val->buff.data, val->buff.size); - - if (val->buff.data == 0) { - uniperror("realloc"); - return -1; - } - memcpy(val->buff.data + val->buff.size - n, buffer, n); - return send_saved_req(pool, val, buffer, bfsize); + if (buff != val->buff) + memcpy(val->buff->data + val->buff->lock - n, buff->data, n); + return send_saved_req(pool, val); } } else { - if (on_response(pool, val, buffer, n) == 0) { + if (on_response(pool, val, buff->data, n) == 0) { return 0; } free_first_req(val->pair); @@ -463,24 +461,25 @@ int on_first_tunnel(struct poolhd *pool, return -1; } } - if (tcp_send_hook(val->pair, buffer, bfsize, n) < n) { + if (tcp_send_hook(pool, val->pair, buff, n) < n) { return -1; } return 0; } -ssize_t tcp_send_hook(struct eval *remote, - char *buffer, size_t bfsize, ssize_t n) +ssize_t tcp_send_hook(struct poolhd *pool, + struct eval *remote, struct buffer *buff, ssize_t n) { ssize_t sn = -1; int skip = remote->flag != FLAG_CONN; + size_t off = buff->offset; if (!skip) { struct eval *client = remote->pair; if (client->recv_count == n - && setup_conn(client, buffer, n) < 0) { + && setup_conn(client, buff->data, n) < 0) { return -1; } int m = client->attempt, r = client->round_count; @@ -494,11 +493,11 @@ ssize_t tcp_send_hook(struct eval *remote, if (!offset && remote->round_count) offset = -1; sn = desync(remote->fd, - buffer, bfsize, n, offset, m); + buff->data + off, buff->size - off, n, offset, m); } } if (skip) { - sn = send(remote->fd, buffer, n, 0); + sn = send(remote->fd, buff->data + off, n, 0); if (sn < 0 && get_e() == EAGAIN) { return 0; } @@ -509,9 +508,9 @@ ssize_t tcp_send_hook(struct eval *remote, ssize_t tcp_recv_hook(struct poolhd *pool, - struct eval *val, char *buffer, size_t bfsize) + struct eval *val, struct buffer *buff) { - ssize_t n = recv(val->fd, buffer, bfsize, 0); + ssize_t n = recv(val->fd, buff->data, buff->size, 0); if (n < 1) { if (!n) { if (val->flag != FLAG_CONN) { diff --git a/extend.h b/extend.h index b653e9d..6e8d916 100644 --- a/extend.h +++ b/extend.h @@ -10,17 +10,16 @@ int socket_mod(int fd); int connect_hook(struct poolhd *pool, struct eval *val, const union sockaddr_u *dst, int next); -ssize_t tcp_send_hook(struct eval *val, - char *buffer, size_t bfsize, ssize_t n); +ssize_t tcp_send_hook(struct poolhd *pool, + struct eval *remote, struct buffer *buff, ssize_t n); -ssize_t tcp_recv_hook(struct poolhd *pool, struct eval *val, - char *buffer, size_t bfsize); +ssize_t tcp_recv_hook(struct poolhd *pool, + struct eval *val, struct buffer *buff); ssize_t udp_hook(struct eval *val, char *buffer, ssize_t n, const union sockaddr_u *dst); -int on_first_tunnel(struct poolhd *pool, - struct eval *val, char *buffer, size_t bfsize, int etype); +int on_first_tunnel(struct poolhd *pool, struct eval *val, int etype); #ifdef __linux__ static int protect(int conn_fd, const char *path); diff --git a/proxy.c b/proxy.c index cf74765..9454d1f 100644 --- a/proxy.c +++ b/proxy.c @@ -646,8 +646,7 @@ static int on_accept(struct poolhd *pool, const struct eval *val) } -static int on_tunnel(struct poolhd *pool, struct eval *val, - char *buffer, size_t bfsize, int etype) +static int on_tunnel(struct poolhd *pool, struct eval *val, int etype) { ssize_t n = 0; struct eval *pair = val->pair; @@ -657,26 +656,23 @@ static int on_tunnel(struct poolhd *pool, struct eval *val, val = pair; pair = val->pair; } - if (val->buff.data) { + if (val->buff && val->buff->lock) { if (etype & POLLHUP) { return -1; } - n = val->buff.size - val->buff.offset; + n = val->buff->lock - val->buff->offset; - ssize_t sn = tcp_send_hook(pair, - val->buff.data + val->buff.offset, n, n); + ssize_t sn = tcp_send_hook(pool, pair, val->buff, n); if (sn < 0) { uniperror("send"); return -1; } if (sn < n) { - val->buff.offset += sn; + val->buff->offset += sn; return 0; } - free(val->buff.data); - val->buff.data = 0; - val->buff.size = 0; - val->buff.offset = 0; + val->buff->lock = 0; + val->buff->offset = 0; if (mod_etype(pool, val, POLLIN) || mod_etype(pool, pair, POLLIN)) { @@ -684,8 +680,9 @@ static int on_tunnel(struct poolhd *pool, struct eval *val, return -1; } } + struct buffer *buff = buff_get(pool->root_buff, params.bfsize); do { - n = tcp_recv_hook(pool, val, buffer, bfsize); + n = tcp_recv_hook(pool, val, buff); //if (n < 0 && get_e() == EAGAIN) { if (n == 0) { break; @@ -693,21 +690,17 @@ static int on_tunnel(struct poolhd *pool, struct eval *val, if (n < 0) { return -1; } - ssize_t sn = tcp_send_hook(pair, buffer, bfsize, n); + ssize_t sn = tcp_send_hook(pool, pair, buff, n); if (sn < 0) { uniperror("send"); return -1; } if (sn < n) { LOG(LOG_S, "send: %zd != %zd (fd=%d)\n", sn, n, pair->fd); - assert(!(val->buff.size || val->buff.offset)); - val->buff.size = n - sn; - if (!(val->buff.data = malloc(n - sn))) { - uniperror("malloc"); - return -1; - } - memcpy(val->buff.data, buffer + sn, n - sn); + val->buff = buff; + buff->lock = n; + buff->offset = sn; if (mod_etype(pool, val, 0) || mod_etype(pool, pair, POLLOUT)) { @@ -716,15 +709,17 @@ static int on_tunnel(struct poolhd *pool, struct eval *val, } break; } - } while (n == (ssize_t )bfsize); + } while (n == (ssize_t )buff->size); return 0; } -static int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize) +static int on_udp_tunnel(struct poolhd *pool, struct eval *val) { - char *data = buffer; - size_t data_len = bfsize; + struct buffer *buff = buff_get(pool->root_buff, params.bfsize); + + char *data = buff->data; + size_t data_len = buff->size; if (val->flag != FLAG_CONN) { data += S_SIZE_I6; @@ -788,7 +783,7 @@ static int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize) } else { map_fix(&addr, 0); - memset(buffer, 0, S_SIZE_I6); + memset(buff->data, 0, S_SIZE_I6); int offs = s5_set_addr(data, S_SIZE_I6, &addr, 1); if (offs < 0 || offs > S_SIZE_I6) { @@ -805,21 +800,21 @@ static int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize) } -static inline int on_request(struct poolhd *pool, struct eval *val, - char *buffer, size_t bfsize) +static inline int on_request(struct poolhd *pool, struct eval *val) { union sockaddr_u dst = {0}; + struct buffer *buff = buff_get(pool->root_buff, params.bfsize); - ssize_t n = recv(val->fd, buffer, bfsize, 0); + ssize_t n = recv(val->fd, buff->data, buff->size, 0); if (n < 1) { if (n) uniperror("ss recv"); return -1; } int error = 0; - if (*buffer == S_VER5) { + if (*buff->data == S_VER5) { if (val->flag != FLAG_S5) { - if (auth_socks5(val->fd, buffer, n)) { + if (auth_socks5(val->fd, buff->data, n)) { return -1; } val->flag = FLAG_S5; @@ -829,18 +824,18 @@ static inline int on_request(struct poolhd *pool, struct eval *val, LOG(LOG_E, "ss: request too small (%zd)\n", n); return -1; } - struct s5_req *r = (struct s5_req *)buffer; + struct s5_req *r = (struct s5_req *)buff->data; int s5e = 0; switch (r->cmd) { case S_CMD_CONN: - s5e = s5_get_addr(buffer, n, &dst, SOCK_STREAM); + s5e = s5_get_addr(buff->data, n, &dst, SOCK_STREAM); if (s5e >= 0) { error = connect_hook(pool, val, &dst, EV_CONNECT); } break; case S_CMD_AUDP: if (params.udp) { - s5e = s5_get_addr(buffer, n, &dst, SOCK_DGRAM); + s5e = s5_get_addr(buff->data, n, &dst, SOCK_DGRAM); if (s5e >= 0) { error = udp_associate(pool, val, &dst); } @@ -857,10 +852,10 @@ static inline int on_request(struct poolhd *pool, struct eval *val, return -1; } } - else if (*buffer == S_VER4) { + else if (*buff->data == S_VER4) { val->flag = FLAG_S4; - error = s4_get_addr(buffer, n, &dst); + error = s4_get_addr(buff->data, n, &dst); if (error) { if (resp_error(val->fd, error, FLAG_S4) < 0) uniperror("send"); @@ -869,16 +864,16 @@ static inline int on_request(struct poolhd *pool, struct eval *val, error = connect_hook(pool, val, &dst, EV_CONNECT); } else if (params.http_connect - && n > 7 && !memcmp(buffer, "CONNECT", 7)) { + && n > 7 && !memcmp(buff->data, "CONNECT", 7)) { val->flag = FLAG_HTTP; - if (http_get_addr(buffer, n, &dst)) { + if (http_get_addr(buff->data, n, &dst)) { return -1; } error = connect_hook(pool, val, &dst, EV_CONNECT); } else { - LOG(LOG_E, "ss: invalid version: 0x%x (%zd)\n", *buffer, n); + LOG(LOG_E, "ss: invalid version: 0x%x (%zd)\n", *buff->data, n); return -1; } if (error) { @@ -950,9 +945,8 @@ int event_loop(int srvfd) close(srvfd); return -1; } - char *buffer = malloc(params.bfsize); - if (!buffer) { - uniperror("malloc"); + pool->root_buff = buff_get(0, params.bfsize); + if (!pool->root_buff) { destroy_pool(pool); return -1; } @@ -981,22 +975,22 @@ int event_loop(int srvfd) case EV_REQUEST: if ((etype & POLLHUP) || - on_request(pool, val, buffer, bfsize)) + on_request(pool, val)) close_conn(pool, val); continue; case EV_FIRST_TUNNEL: - if (on_first_tunnel(pool, val, buffer, bfsize, etype)) + if (on_first_tunnel(pool, val, etype)) close_conn(pool, val); continue; case EV_TUNNEL: - if (on_tunnel(pool, val, buffer, bfsize, etype)) + if (on_tunnel(pool, val, etype)) close_conn(pool, val); continue; case EV_UDP_TUNNEL: - if (on_udp_tunnel(val, buffer, bfsize)) + if (on_udp_tunnel(pool, val)) close_conn(pool, val); continue; @@ -1016,7 +1010,6 @@ int event_loop(int srvfd) } } LOG(LOG_S, "exit\n"); - free(buffer); destroy_pool(pool); return 0; }