szp %!s(int64=2) %!d(string=hai) anos
achega
cdc99b6363
Modificáronse 14 ficheiros con 1699 adicións e 0 borrados
  1. 113 0
      buffer.c
  2. 20 0
      buffer.h
  3. 481 0
      client.c
  4. 17 0
      client.h
  5. 297 0
      mem_pool.c
  6. 28 0
      mem_pool.h
  7. 496 0
      server.c
  8. 16 0
      server.h
  9. 25 0
      socket_comm.c
  10. 38 0
      socket_comm.h
  11. BIN=BIN
      tunnel
  12. 152 0
      tunnel.c
  13. 1 0
      tunnel.d
  14. 15 0
      tunnel.h

+ 113 - 0
buffer.c

@@ -0,0 +1,113 @@
+#include "tunnel.h"
+#include "buffer.h"
+
+#include <assert.h>
+
+struct ring_buffer*
+alloc_ring_buffer(int len) {
+    struct ring_buffer* rb = (struct ring_buffer*)malloc(sizeof(*rb));
+    memset(rb, 0, sizeof(*rb));
+
+    rb->data_ptr = (char *)malloc(len);
+    rb->max_len = len;
+
+    return rb;
+}
+
+void
+free_ring_buffer(struct ring_buffer* rb) {
+    free(rb->data_ptr);
+    free(rb);
+}
+
+char*
+get_ring_buffer_write_ptr(struct ring_buffer* rb, int* max_len) {
+    int read_pos = rb->read_pos;
+    if (rb->write_pos < read_pos) {
+        read_pos -= 2 * rb->max_len;
+    }
+
+    assert(rb->write_pos >= read_pos);
+    if (rb->write_pos - read_pos == rb->max_len) {
+        return NULL;
+    }
+
+    int w_idx = rb->write_pos % rb->max_len;
+    int r_idx = read_pos % rb->max_len;
+
+    if (w_idx >= r_idx) {
+        *max_len = rb->max_len - w_idx;
+    }else {
+        *max_len = r_idx - w_idx;
+    }
+
+    return rb->data_ptr + w_idx;
+}
+
+void
+move_ring_buffer_write_pos(struct ring_buffer*rb, int len) {
+    int tmp = rb->write_pos + len;
+    if (tmp > 3 * rb->max_len && rb->write_pos > rb->read_pos) {
+        tmp -= 2 * rb->max_len;
+    }
+
+    rb->write_pos = tmp;
+}
+
+char*
+get_ring_buffer_read_ptr(struct ring_buffer* rb, int* read_len) {
+    int write_pos = rb->write_pos;
+    int read_pos = rb->read_pos;
+
+    if (write_pos < read_pos) {
+        read_pos -= 2 * rb->max_len;
+    }
+
+    assert(write_pos >= read_pos);
+    if (read_pos == write_pos) {
+        return NULL;
+    }
+
+    int w_idx = write_pos % rb->max_len;
+    int r_idx = read_pos % rb->max_len;
+    if (w_idx > r_idx) {
+        *read_len = w_idx - r_idx;
+    }else {
+        *read_len = rb->max_len - r_idx;
+    }
+
+    return rb->data_ptr + read_pos % rb->max_len;
+}
+
+void
+move_ring_buffer_read_pos(struct ring_buffer*rb, int len) {
+    // int read_pos = rb->read_pos;
+    // if (rb->write_pos < read_pos) {
+    //  read_pos -= 2 * rb->max_len;
+    // }
+
+    rb->read_pos += len;
+}
+
+int
+is_ring_buffer_empty(struct ring_buffer* rb) {
+    int write_pos = rb->write_pos;
+    int read_pos = rb->read_pos;
+
+    if (write_pos < read_pos) {
+        read_pos -= 2 * rb->max_len;
+    }
+
+    assert(write_pos >= read_pos);
+    if (read_pos == write_pos) {
+        return 1;
+    }
+
+    return 0;
+}
+
+void
+reset_ring_buffer(struct ring_buffer* rb) {
+    rb->read_pos = 0;
+    rb->write_pos = 0;
+}

+ 20 - 0
buffer.h

@@ -0,0 +1,20 @@
+#ifndef	BUFFER_H
+#define BUFFER_H
+
+struct ring_buffer
+{
+	char* data_ptr;
+	int max_len;
+	volatile int read_pos;
+	volatile int write_pos;
+};
+
+struct ring_buffer* alloc_ring_buffer(int len);
+void free_ring_buffer(struct ring_buffer* rb);
+char* get_ring_buffer_write_ptr(struct ring_buffer* rb, int* max_len);
+void move_ring_buffer_write_pos(struct ring_buffer*rb, int len);
+char* get_ring_buffer_read_ptr(struct ring_buffer* rb, int* read_len);
+void move_ring_buffer_read_pos(struct ring_buffer*rb, int len);
+int is_ring_buffer_empty(struct ring_buffer* rb);
+void reset_ring_buffer(struct ring_buffer* rb);
+#endif

+ 481 - 0
client.c

@@ -0,0 +1,481 @@
+#include "tunnel.h"
+#include "client.h"
+#include "socket_comm.h"
+#include "sys/time.h"
+
+#include <assert.h>
+
+struct client {
+	char remote_ip[128];
+	int remote_port;
+	int ssh_port;
+	int free_connection;
+	int id_idx;
+
+	struct ring_buffer* wait_closed;
+
+	int max_fd;
+	fd_set fd_rset;
+	fd_set fd_wset;
+
+	int time;
+	int cnt;
+	struct client_info all_fds[TOTAL_CONNECTION];
+	int all_ids[TOTAL_CONNECTION];
+};
+
+static int
+get_id(struct client* c) {
+	int i, ret = -1;
+	for (i = c->id_idx; i < c->id_idx + TOTAL_CONNECTION; ++i) {
+		int idx = i % TOTAL_CONNECTION;
+		++c->id_idx;
+
+		if (c->all_fds[idx].fd == 0) {
+			ret = i;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int
+connect_to(struct client* c, int ssh_id){
+	if (c->cnt >= TOTAL_CONNECTION) {
+		fprintf(stderr, "%s client max connection.....\n", get_time());
+		return -1;
+	}
+	
+	const char* ip;
+	int port;
+	if (ssh_id < 0) {
+		if (c->free_connection > 0) return -1;
+
+		struct timeval tv;
+		gettimeofday(&tv, NULL);
+		if (tv.tv_sec - c->time < FREE_CONNECT_TIME) {
+			return -1;
+		}else {
+			c->time = tv.tv_sec;
+		}
+
+		ip = c->remote_ip;
+		port = c->remote_port;
+	} else {
+		ip = "0.0.0.0";
+		port = c->ssh_port;
+	}
+
+	int id;
+	int idx;
+	struct client_info* info;
+	struct ring_buffer* rb;
+
+	struct addrinfo hints;
+	struct addrinfo* res = NULL;
+	struct addrinfo* ai_ptr = NULL;
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_protocol = IPPROTO_TCP;
+
+	char portstr[16];
+	sprintf(portstr, "%d", port);
+	int status = getaddrinfo(ip, portstr, &hints, &res);
+	if (status != 0) {
+		return -1;
+	}
+
+	int sock = -1;
+	for (ai_ptr = res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
+		sock = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
+		if (sock < 0) {
+			continue;
+		}
+
+		set_keep_alive(sock);
+		sp_nonblocking(sock);
+		status = connect(sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+		if (status != 0 && errno != EINPROGRESS) {
+			close(sock);
+			sock = -1;
+			continue;
+		}
+
+		break;
+	}
+
+	if (sock < 0) {
+		goto _failed;
+	}
+
+	id = get_id(c);
+	assert(id != -1);
+
+	idx = id % TOTAL_CONNECTION;
+	info = &c->all_fds[idx];
+	info->fd = sock;
+	info->id = id;
+	info->to_id = ssh_id;
+	snprintf(info->client_ip, sizeof(info->client_ip), "%s:%d", ip, port);
+
+	rb = alloc_ring_buffer(MAX_CLIENT_BUFFER);
+	info->buffer = rb;
+
+	c->all_ids[c->cnt++] = id;
+
+	if (ssh_id < 0) {
+		c->free_connection += 1;
+	}
+
+	if (status != 0) {
+		//connect no block, need check after
+		FD_SET(sock, &c->fd_wset);
+		info->connect_type = SOCKET_CONNECTING;
+	}else {
+		//success
+		FD_SET(sock, &c->fd_rset);
+		info->connect_type = SOCKET_CONNECTED;
+
+		struct sockaddr* addr = ai_ptr->ai_addr;
+		void* sin_addr = (ai_ptr->ai_family == AF_INET) ? (void*)&((struct sockaddr_in*)addr)->sin_addr : (void*)&((struct sockaddr_in6*)addr)->sin6_addr;
+
+		inet_ntop(ai_ptr->ai_family, sin_addr, info->client_ip, sizeof(info->client_ip));
+		fprintf(stderr, "%s connected to %s. \n", get_time(), info->client_ip);
+	}
+
+	if (c->max_fd < sock + 1) {
+		c->max_fd = sock + 1;
+	}
+
+	return id;
+
+_failed:
+	freeaddrinfo(res);
+	return -1;
+}
+
+static void
+do_close(struct client* c, struct client_info* info) {
+	int i;
+	for (i = 0; i < c->cnt; ++i) {
+		if (c->all_ids[i] == info->id) {
+			memcpy(c->all_ids + i, c->all_ids + i + 1, (c->cnt - i - 1) * sizeof(int));
+			--c->cnt;
+			break;
+		}
+	}
+
+	FD_CLR(info->fd, &c->fd_rset);
+	FD_CLR(info->fd, &c->fd_wset);
+	close(info->fd);
+
+	if (info->to_id == -1) {
+		assert(c->free_connection == 1);
+
+		c->free_connection = 0;
+	}
+
+	if (info->to_id >= 0 && c->all_fds[info->to_id % TOTAL_CONNECTION].id == info->to_id ) {
+		int len;
+		char* id_buffer = get_ring_buffer_write_ptr(c->wait_closed, &len);
+		int id_len = sizeof(int);
+		assert(id_buffer && len >= id_len);
+		memcpy(id_buffer, &info->to_id, id_len);
+		move_ring_buffer_write_pos(c->wait_closed, id_len);
+	}
+
+	if (info->connect_type == SOCKET_CONNECTED)
+	{
+		fprintf(stderr, "%s client disconnect from %s.\n", get_time(), info->client_ip);
+	}
+
+	info->to_id = -1;
+	info->id = -1;
+	info->fd = 0;
+	info->connect_type = 0;
+	free_ring_buffer(info->buffer);
+	info->buffer = NULL;
+
+	memset(info->client_ip, 0, sizeof(info->client_ip));
+}
+
+static int
+report_connect(struct client* c, struct client_info* info) {
+	int error;
+	socklen_t len = sizeof(error);
+	int code = getsockopt(info->fd, SOL_SOCKET, SO_ERROR, &error, &len);
+	if (code != 0 || error != 0) {
+		//connect fail, close it
+		fprintf(stderr, "%s client: connect to %s error :%s. \n", get_time(), info->client_ip, strerror(error));
+		do_close(c, info);
+		return -1;
+	}
+
+	info->connect_type = SOCKET_CONNECTED;
+	FD_SET(info->fd, &c->fd_rset);
+
+	union sockaddr_all u;
+	socklen_t slen = sizeof(u);
+	if (getpeername(info->fd, &u.s, &slen) == 0){
+		void* sin_addr = (u.s.sa_family == AF_INET) ? (void*)&u.v4.sin_addr : (void*)&u.v6.sin6_addr;
+		inet_ntop(u.s.sa_family, sin_addr, info->client_ip, sizeof(info->client_ip));
+	}
+
+	fprintf(stderr, "%s connected to %s. \n", get_time(), info->client_ip);
+
+	return 0;
+}
+
+static int
+do_read(struct client* c, struct client_info* info) {
+	assert(info->connect_type == SOCKET_CONNECTED);
+
+	int to_id = info->to_id;
+	if (to_id < 0) {
+		to_id = connect_to(c, info->id);
+		if (to_id == -1) {
+			do_close(c, info);
+			return -1;
+		}
+
+		info->to_id = to_id;
+
+		c->free_connection -= 1;
+		c->time = 0;
+	}
+
+	int len;
+	struct client_info* to_info = &c->all_fds[to_id % TOTAL_CONNECTION];
+	if (to_info->id != to_id) {
+		do_close(c, info);
+		return -1;
+	}
+
+	char* buffer = get_ring_buffer_write_ptr(to_info->buffer, &len);
+	if (!buffer) {
+		return 0; //buff fulled
+	}
+
+	int n = (int)read(info->fd, buffer, len);
+	if (n == -1) {
+		switch (errno) {
+		case EAGAIN:
+			fprintf(stderr, "%s read fd error:EAGAIN.\n", get_time());
+			break;
+		case EINTR:
+			break;
+		default:
+			fprintf(stderr, "%s client: read (id=%d) error :%s. \n", get_time(), info->id, strerror(errno));
+			do_close(c, info);
+			return -1;
+		}
+
+		return 1;
+	}
+
+	if (n == 0) {
+		do_close(c, info); //normal close
+		return -1;
+	}
+
+	move_ring_buffer_write_pos(to_info->buffer, n);
+	FD_SET(to_info->fd, &c->fd_wset);
+
+	if (n == len && !is_ring_buffer_empty(to_info->buffer)) {
+		fprintf(stderr, "%s client: read again.\n", get_time());
+		return do_read(c, info);
+	}
+
+	return 1;
+}
+
+static int
+do_write(struct client* c, struct client_info* info, int wait_closed) {
+	if (info->connect_type == SOCKET_CONNECTING) {
+		if (wait_closed) return 0;
+
+		if (report_connect(c, info) == -1) {
+			return -1;
+		}else if (is_ring_buffer_empty(info->buffer)) {
+			FD_CLR(info->fd, &c->fd_wset);
+		}
+
+		return 0;
+	}
+
+	int len;
+	char* buffer = get_ring_buffer_read_ptr(info->buffer, &len);
+	if (!buffer) {
+		return 0;
+	}
+
+	int writed_len = 0;
+	char need_break = 0;
+	while (!need_break && writed_len < len) {
+		int n = write(info->fd, buffer, len - writed_len);
+		if (n < 0) {
+			switch (errno) {
+			case EINTR:
+				n = 0;
+				break;
+			case EAGAIN:
+				n = 0;
+				need_break = 1;
+				break;
+			default:
+				need_break = 1;
+				fprintf(stderr, "%s socket-client: write to (id=%d) error :%s.\n", get_time(), info->id, strerror(errno));
+				do_close(c, info);
+				return -1;
+			}
+		}
+		else {
+			writed_len += n;
+			buffer += n;
+		}
+	}
+
+	move_ring_buffer_read_pos(info->buffer, writed_len);
+
+	if (is_ring_buffer_empty(info->buffer)) {
+		FD_CLR(info->fd, &c->fd_wset);
+	} else if (writed_len == len) {
+		fprintf(stderr, "%s client: write again.\n", get_time());
+		return do_write(c, info, wait_closed);
+	}
+
+	return 1;
+}
+
+static void
+pre_check_close(struct client* c) {
+	int len;
+	char* id_buffer = get_ring_buffer_read_ptr(c->wait_closed, &len);
+	if (!id_buffer) return;
+
+	int id_len = sizeof(int);
+	assert(len % id_len == 0);
+        int tmp = len;
+
+	while (len > 0) {
+		int* id = (int*)id_buffer;
+		int idx = *id % TOTAL_CONNECTION;
+		id_buffer += id_len;
+		len -= len;
+
+		struct client_info* info = c->all_fds + idx;
+		if (info->fd > 0 && info->id == *id) {
+			if (do_write(c, info, 1) != -1) {
+				do_close(c, info);
+			}
+		}
+	}
+
+        move_ring_buffer_read_pos(c->wait_closed, tmp);
+}
+
+static void*
+client_thread(void* param) {
+	struct client_param* cp = (struct client_param*)param;
+
+	struct client c;
+	memset(&c, 0, sizeof(c));
+	sprintf(c.remote_ip, "%s", cp->remote_ip);
+	c.remote_port = cp->p1;
+	c.ssh_port = cp->p2;
+	c.wait_closed = alloc_ring_buffer(sizeof(int) * TOTAL_CONNECTION);
+
+	FD_ZERO(&c.fd_rset);
+	FD_ZERO(&c.fd_wset);
+	FD_SET(cp->pid, &c.fd_rset);
+	c.max_fd = cp->pid + 1;
+	sp_nonblocking(cp->pid);
+
+	while (1) {
+		pre_check_close(&c);
+		
+		if (connect_to(&c, -1) == -1 && c.cnt == 0) {
+			c.max_fd = cp->pid + 1;
+
+			int buff = 0;
+			int n = (int)read(cp->pid, &buff, sizeof(int));
+			if (n > 0) {
+				break;
+			}
+
+			sleep(1);
+			continue;
+		}
+
+		fd_set r_set = c.fd_rset;
+		fd_set w_set = c.fd_wset;
+
+		int cnt = select(c.max_fd, &r_set, &w_set, NULL, NULL);
+		if (cnt == -1) {
+			fprintf(stderr, "%s select error: %s.\n", get_time(), strerror(errno));
+			continue;
+		}
+
+		int i;
+		for (i = c.cnt - 1; i >= 0 && cnt > 0; --i) {
+			int id = c.all_ids[i] % TOTAL_CONNECTION;
+			struct client_info* info = &c.all_fds[id];
+			assert(c.all_ids[i] == info->id);
+
+			int fd = info->fd;
+			assert(fd > 0);
+
+			if (FD_ISSET(fd, &r_set)) {
+				// read
+				--cnt;
+				if (do_read(&c, info) == -1) continue;
+			}
+
+			if (FD_ISSET(fd, &w_set)) {
+				//write
+				--cnt;
+				if (do_write(&c, info, 0) == -1) continue;
+			}
+		}
+
+		if (FD_ISSET(cp->pid, &r_set)) {
+			//exit
+			break;
+		}
+	}
+
+	fprintf(stderr, "%s ====================CLIENT: SEND LAST DATA BEGIN===================.\n", get_time());
+
+	int i;
+	for (i = c.cnt - 1; i >= 0; --i) {
+		int id = c.all_ids[i] % TOTAL_CONNECTION;
+		struct client_info* info = &c.all_fds[id];
+		assert(c.all_ids[i] == info->id);
+
+		if (do_write(&c, info,	1) != -1) {
+			do_close(&c, info);
+		}
+	}
+
+	fprintf(stderr, "%s ====================CLIENT: SEND LAST DATA END=====================.\n", get_time());
+
+	free_ring_buffer(c.wait_closed);
+	assert(c.cnt == 0);
+
+	return NULL;
+}
+
+pthread_t
+start_client(struct client_param* cp) {
+	pthread_t pid;
+	if (pthread_create(&pid, NULL, client_thread, cp)) {
+		fprintf(stderr, "%s Create client thread failed.\n", get_time());
+		exit(1);
+
+		return 0;
+	}
+
+	return pid;
+}

+ 17 - 0
client.h

@@ -0,0 +1,17 @@
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include <pthread.h>
+
+#define FREE_CONNECT_TIME 60
+
+struct client_param {
+	int p1;
+	int p2;
+	int pid;
+	char remote_ip[128];
+};
+
+pthread_t start_client(struct client_param* cp);
+
+#endif

+ 297 - 0
mem_pool.c

@@ -0,0 +1,297 @@
+#include "mem_pool.h"
+
+#define TEST                            int
+#define OFFSET_SIZE                     sizeof(int)
+#define OFFSET_NEXT_PTR_SIZE		sizeof(void *)
+#define OFFSET_PRE_PTR_BEGIN            OFFSET_SIZE + OFFSET_NEXT_PTR_SIZE
+#define OFFSET_PRE_PTR_SIZE             sizeof(void *)
+#define MIN_ALLOC_CNT                   OFFSET_SIZE + OFFSET_NEXT_PTR_SIZE + OFFSET_PRE_PTR_SIZE
+
+struct msg_pool *
+create_pool(int max_size) {
+	struct msg_pool* p = (struct msg_pool*)malloc(sizeof(*p));
+	memset(p, 0, sizeof(*p));
+
+	p->max_size = max_size;
+	p->free_cnt = max_size;
+	p->list_cnt = 1;
+	p->data_ptr = malloc(max_size);
+	p->free_list = p->data_ptr;
+
+	*(TEST*)p->free_list = max_size;
+	void** next = (void**)((char *)p->data_ptr + OFFSET_SIZE);
+	*next = NULL;
+	void** pre = (void**)((char *)p->data_ptr + OFFSET_PRE_PTR_BEGIN);
+	*pre = NULL;
+
+	return p;
+}
+
+static struct msg_pool *
+msg_pool_expand(struct msg_pool* p) {
+	assert(p && p->max_size > 0);
+
+	while (p->next) {
+		p = p->next;
+	}
+
+	p->next = create_pool(p->max_size);
+
+	return p->next;
+}
+
+void *
+msg_pool_alloc(struct msg_pool* p, size_t size) {
+	size_t real_size = size + OFFSET_SIZE;
+	real_size = real_size < MIN_ALLOC_CNT ? MIN_ALLOC_CNT : real_size;
+	assert(real_size <= p->max_size);
+
+	void* ret = NULL;
+	if (p->free_cnt >= real_size) {
+		void* block = p->free_list;
+		assert(block != NULL);
+
+		while (block) {
+			void* next = *(void **)((char*)block + OFFSET_SIZE);
+			TEST block_cnt = *(TEST*)block;
+			assert(block_cnt >= MIN_ALLOC_CNT && block_cnt <= p->max_size);
+			if (block_cnt < real_size) {
+				block = next;
+				continue;
+			}
+
+			if (block_cnt - real_size < MIN_ALLOC_CNT) {
+				real_size = block_cnt;
+			}
+
+			void **pre_next = NULL;
+			void *pre_block = *(void **)((char *)block + OFFSET_PRE_PTR_BEGIN);
+			if (pre_block) {
+				pre_next = (void **)((char*)pre_block + OFFSET_SIZE);
+				assert(*pre_next == block);
+			}
+
+			if (0 == block_cnt - real_size) {
+				if (pre_next && *pre_next) {
+					*pre_next = next;
+				}
+				else {
+					p->free_list = next;
+				}
+
+				if (next) {
+					*(void **)((char *)next + OFFSET_PRE_PTR_BEGIN) = pre_block;
+				}
+
+				p->list_cnt -= 1;
+			}
+			else {
+				void *rest_block = (char *)block + real_size;
+				*(TEST*)rest_block = block_cnt - real_size;
+				*(void **)((char *)rest_block + OFFSET_PRE_PTR_BEGIN) = pre_block;
+				*(void **)((char *)rest_block + OFFSET_SIZE) = *(void **)((char *)block + OFFSET_SIZE);
+
+				if (next) {
+					*(void **)((char *)next + OFFSET_PRE_PTR_BEGIN) = rest_block;
+				}
+
+				if (pre_next && *pre_next) {
+					*pre_next = rest_block;
+				}
+				else {
+					p->free_list = rest_block;
+				}
+			}
+
+			*(TEST*)block = real_size;
+			ret = (char*)block + OFFSET_SIZE;
+			p->free_cnt -= real_size;
+			return ret;
+		}
+	}
+
+	if (p->next) {
+		return msg_pool_alloc(p->next, size);
+	}
+	else {
+		return msg_pool_alloc(msg_pool_expand(p), size);
+	}
+}
+
+static void
+msg_pool_delete_one(struct msg_pool* p) {
+	free(p->data_ptr);
+	free(p);
+}
+
+void
+msg_pool_free(struct msg_pool* p, void* ptr, char* freed) {
+	if (ptr == NULL || p == NULL) return;
+
+	*freed = 0;
+	ptr = (char*)ptr - OFFSET_SIZE;
+
+	struct msg_pool *pre_p = p;
+	while (p != NULL) {
+		void *max_ptr = (char*)p->data_ptr + p->max_size;
+
+		if (ptr >= p->data_ptr && ptr < max_ptr) {
+			break;
+		}
+
+		pre_p = p;
+		p = p->next;
+	}
+
+	if (p == NULL) {
+		fprintf(stderr, "error: call msg_pool free a block not alloc from pool");
+		return;
+	}
+
+	TEST size = *(TEST*)ptr;
+	memset((char*)ptr + OFFSET_SIZE, 0, MIN_ALLOC_CNT - OFFSET_SIZE);
+	assert(size >= MIN_ALLOC_CNT && size <= p->max_size);
+
+	void *block = p->free_list;
+	void *pre_block = NULL;
+	while (block && block > ptr) {
+		void* next = *(void **)((char*)block + OFFSET_SIZE);
+		pre_block = block;
+		block = next;
+	}
+
+	if (block) {
+		*(void **)((char *)block + OFFSET_PRE_PTR_BEGIN) = ptr;
+	}
+
+	if (pre_block) {
+		void **pre_next = (void **)((char*)pre_block + OFFSET_SIZE);
+		*pre_next = ptr;
+	}
+
+	*(void **)((char *)ptr + OFFSET_PRE_PTR_BEGIN) = pre_block;
+	*(void **)((char*)ptr + OFFSET_SIZE) = block;
+
+	//merge
+	int merge_cnt = block ? 2 : 1;
+	void* merge_ptr = block ? block : ptr;
+
+	while (merge_cnt > 0 && merge_ptr) {
+		TEST size = *(TEST*)merge_ptr;
+		void* pre_ptr = *(void **)((char *)merge_ptr + OFFSET_PRE_PTR_BEGIN);
+
+		if ((char *)merge_ptr + size == pre_ptr) {
+			TEST pre_size = *(TEST*)pre_ptr;
+			*(TEST*)merge_ptr = size + pre_size;
+
+			void* pre_pre_ptr = *(void **)((char *)pre_ptr + OFFSET_PRE_PTR_BEGIN);
+			*(void **)((char *)merge_ptr + OFFSET_PRE_PTR_BEGIN) = pre_pre_ptr;
+
+			if (pre_pre_ptr) {
+				*(void **)((char*)pre_pre_ptr + OFFSET_SIZE) = merge_ptr;
+			}
+
+			if (pre_ptr == p->free_list) {
+				p->free_list = merge_ptr;
+			}
+
+			--p->list_cnt;
+		}
+		else {
+			if (p->free_list < merge_ptr) {
+				p->free_list = merge_ptr;
+			}
+			merge_ptr = pre_ptr;
+		}
+		--merge_cnt;
+	}
+
+	p->free_cnt += size;
+	p->list_cnt += 1;
+	if (p->free_cnt == p->max_size && pre_p != p) {
+		pre_p->next = p->next;
+		//delete p
+		msg_pool_delete_one(p);
+
+		*freed = 1;
+	}
+}
+
+void
+msg_pool_delete(struct msg_pool *p) {
+	if (p == NULL) return;
+
+	do {
+		struct msg_pool* next = p->next;
+		msg_pool_delete_one(p);
+		p = next;
+	} while (p != NULL);
+}
+/*
+int
+main(int argc, char *argv[]) {
+	msg_pool *p = create_pool(1024);
+
+	void *b1 = msg_pool_alloc(p, 300);
+	void *b2 = msg_pool_alloc(p        , 600);
+
+	bool b;
+	msg_pool_free(p, b1, b);
+	void *b3 = msg_pool_alloc(p, 96);
+	void *b4 = msg_pool_alloc(p, 100);
+	void *b5 = msg_pool_alloc(p, 90);
+
+	msg_pool_free(p, b2, b);
+	msg_pool_free(p, b3, b);
+	msg_pool_free(p, b4, b);
+	msg_pool_free(p, b5, b);
+       
+
+	int alloced = 0;
+	int max_alloced = 1024;
+	void **vec_alloc = (void **)malloc(sizeof(void *) * 1024);
+	int tmp1 = 0, tmp2 = 0;
+	while (1) {
+		srand(time(0));
+		int r = rand() % 2;
+		if (r) {
+			if (alloced >= max_alloced) {
+				void **tmp = (void **)malloc(sizeof(void *) * max_alloced * 2);
+				memcpy(tmp, vec_alloc, max_alloced * sizeof(void *));
+				max_alloced *= 2;
+				free(vec_alloc);
+				vec_alloc = tmp;
+			}
+
+			int size = rand() % 1020 + 1;
+			void* b = msg_pool_alloc(p, size);
+			vec_alloc[alloced++] = b;
+
+			memset(b, 0, size);
+			tmp1++;
+		}
+		else {
+			if (alloced > 0) {
+				void *b = vec_alloc[0];
+				char freed = 0;
+				msg_pool_free(p, b, &freed);
+
+				alloced -= 1;
+				memmove(vec_alloc, (char*)vec_alloc + sizeof(void *), alloced * sizeof(void *));
+
+				if (!freed) {
+					void *ptr = (char*)b - OFFSET_SIZE;
+					TEST size = *(TEST*)ptr;
+					memset((char *)ptr + MIN_ALLOC_CNT, 0, size - MIN_ALLOC_CNT);
+				}
+
+				tmp2++;
+			}
+		}
+
+		usleep(1);
+	}
+	msg_pool_delete(p);
+	return 0;
+}
+*/

+ 28 - 0
mem_pool.h

@@ -0,0 +1,28 @@
+#ifndef MEM_POOL_H
+#define MEN_POOL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+//#include <time.h>
+
+struct msg_pool {
+        int max_size;
+
+        void *data_ptr;
+
+        int list_cnt;
+        void *free_list;
+        int free_cnt;
+
+        struct msg_pool *next;
+};
+
+void* msg_pool_alloc(struct msg_pool* p, size_t size);
+struct msg_pool* create_pool(int max_size);
+void msg_pool_free(struct msg_pool *p, void *ptr, char* freed);
+void msg_pool_delete(struct msg_pool *p);
+
+#endif

+ 496 - 0
server.c

@@ -0,0 +1,496 @@
+#include "tunnel.h"
+#include "server.h"
+#include "buffer.h"
+#include "socket_comm.h"
+
+#include <assert.h>
+#include <unistd.h>
+
+struct server_info
+{
+	int listen_port[2];
+	int listen_fd[2];
+	struct client_info client[TOTAL_CONNECTION];
+	int client_id[TOTAL_CONNECTION];
+	int client_cnt;
+	int max_fd;
+	int id_idx;
+
+	struct ring_buffer* wait_closed;
+
+	int listen_id;
+
+	fd_set fd_rset;
+	fd_set fd_wset;
+};
+
+static int
+server_init(const char* host, int port) {
+	int fd;
+	int reuse = 1;
+	struct addrinfo ai_hints;
+	struct addrinfo *ai_list = NULL;
+	char portstr[16];
+	if (host == NULL || host[0] == 0){
+		host = "0.0.0.0";
+	}
+	sprintf(portstr, "%d", port);
+	memset(&ai_hints, 0, sizeof(ai_hints));
+	ai_hints.ai_protocol = IPPROTO_TCP;
+	ai_hints.ai_socktype = SOCK_STREAM;
+	ai_hints.ai_family = AF_UNSPEC;
+
+	int status = getaddrinfo(host, portstr, &ai_hints, &ai_list);
+	if (status != 0) {
+		return -1;
+	}
+
+	fd = socket(ai_list->ai_family, ai_list->ai_socktype, 0);
+	if (fd < 0) {
+		goto _failed_fd;
+	}
+
+	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(int)) == -1) {
+		goto _failed;
+	}
+
+	/*bind*/
+	status = bind(fd, (struct sockaddr *)ai_list->ai_addr, ai_list->ai_addrlen);
+	if (status != 0)
+		goto _failed;
+
+	//listen
+	if (listen(fd, 32) == -1) {
+		close(fd);
+		fprintf(stderr, "%s listen port %d failed.\n", get_time(), port);
+		return -1;
+	}
+
+	freeaddrinfo(ai_list);
+	sp_nonblocking(fd);
+	return fd;
+
+_failed:
+	close(fd);
+_failed_fd:
+	freeaddrinfo(ai_list);
+	return -1;
+}
+
+static int
+get_id(struct server_info* s) {
+	int i, ret = -1;
+	for (i = s->id_idx; i < s->id_idx + TOTAL_CONNECTION; ++i) {
+		int idx = i % TOTAL_CONNECTION;
+		++s->id_idx;
+
+		if (s->client[idx].fd == 0) {
+			ret = i;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void
+do_accept(struct server_info* s, int listen_fd) {
+	union sockaddr_all addr;
+	socklen_t len = sizeof(addr);
+
+	int fd = accept(listen_fd, &addr.s, &len);
+	if (fd == -1) {
+		int err = errno;
+		if (err != EAGAIN) {
+			fprintf(stderr, "%s accept error: %s.\n", get_time(), strerror(err));
+		}
+
+		return;
+	}
+
+	if (s->client_cnt >= TOTAL_CONNECTION) {
+		close(fd);
+		fprintf(stderr, "%s accept error, connection max.............\n", get_time());
+		return;
+	}
+
+	if (listen_fd == s->listen_fd[0]) {
+		if (s->listen_id < 0) {
+			//TODO:可以加个连接缓存,等待下个tunnel上来后,直接连上
+			close(fd);
+			fprintf(stderr, "%s accept error, no available connection for now.............\n", get_time());
+			return;
+		}
+	}else {
+		if (s->listen_id >= 0) {
+			close(fd);
+			fprintf(stderr, "%s accept error, tunnel only need one available.............\n", get_time());
+			return;
+		}
+	}
+
+	int id = get_id(s);
+	assert(id != -1);
+
+	struct ring_buffer* rb = alloc_ring_buffer(MAX_CLIENT_BUFFER);
+
+	struct client_info* nc = s->client + id % TOTAL_CONNECTION;
+	assert(nc->fd == 0);
+
+	nc->id = id;
+	nc->fd = fd;
+	nc->buffer = rb;
+	nc->to_id = -1;
+
+	void* sin_addr = (addr.s.sa_family == AF_INET) ? (void*)&addr.v4.sin_addr : (void *)&addr.v6.sin6_addr;
+	int sin_port = ntohs((addr.s.sa_family == AF_INET) ? addr.v4.sin_port : addr.v6.sin6_port);
+
+	static char tmp[128];
+	if (inet_ntop(addr.s.sa_family, sin_addr, tmp, sizeof(tmp))) {
+		snprintf(nc->client_ip, sizeof(nc->client_ip), "%s:%d", tmp, sin_port);
+	}
+
+	fprintf(stderr, "%s client %s connected.\n", get_time(), nc->client_ip);
+
+	s->client_id[s->client_cnt++] = id;
+
+	FD_SET(fd, &s->fd_rset);
+	if (s->max_fd < fd + 1) {
+		s->max_fd = fd + 1;//TODO:最大的fd被close后是否要处理下
+	}
+
+	set_keep_alive(fd);
+	sp_nonblocking(fd);
+
+	if (listen_fd == s->listen_fd[0]) {
+		nc->to_id = s->listen_id;
+		struct client_info* listen_nc = s->client + nc->to_id % TOTAL_CONNECTION;
+		assert(listen_nc->fd >= 0 && listen_nc->id == nc->to_id);
+		listen_nc->to_id = nc->id;
+		s->listen_id = -1;
+	}else {
+		s->listen_id = id;
+	}
+}
+
+static void
+do_close(struct server_info* s, struct client_info* c) {
+	int i;
+	for (i = 0; i < s->client_cnt; ++i) {
+		if (s->client_id[i] == c->id) {
+			memcpy(s->client_id + i, s->client_id + i + 1, (s->client_cnt - i - 1) * sizeof(int));
+			--s->client_cnt;
+			break;
+		}
+	}
+
+	FD_CLR(c->fd, &s->fd_rset);
+	FD_CLR(c->fd, &s->fd_wset);
+	close(c->fd);
+
+	int idx = c->id % TOTAL_CONNECTION;
+	assert(&s->client[idx] == c);
+
+	if (c->id == s->listen_id) {
+		s->listen_id = -1;
+	}
+
+	if (c->to_id >= 0 && s->client[c->to_id % TOTAL_CONNECTION].id == c->to_id) {
+		int len;
+		char* id_buffer = get_ring_buffer_write_ptr(s->wait_closed, &len);
+		int id_len = sizeof(int);
+		assert(id_buffer && len >= id_len);
+		memcpy(id_buffer, &c->to_id, id_len);
+		move_ring_buffer_write_pos(s->wait_closed, id_len);
+	}
+
+	c->to_id = -1;
+	c->id = -1;
+	c->fd = 0;
+	free_ring_buffer(c->buffer);
+	c->buffer = NULL;
+
+	fprintf(stderr, "%s client %s disconnect.\n", get_time(), c->client_ip);
+	memset(c->client_ip, 0, sizeof(c->client_ip));
+}
+
+/*
+static int
+try_write(struct server_info* s, struct client_info* c) {
+	int len;
+	char* buffer = get_ring_buffer_read_ptr(c->buffer, &len);
+	if (!buffer) {
+		return 0; //empty
+	}
+
+	int n = write(c->fd, buffer, len);
+	if (n < 0) {
+		switch (errno) {
+		case EINTR:
+		case EAGAIN:
+			break;
+		default:
+			fprintf(stderr, "server: write to (id=%d) error :%s.\n", c->id, strerror(errno));
+			do_close(s, c);
+			return -1;
+		}
+	}else {
+		move_ring_buffer_read_pos(c->buffer, n);
+	}
+
+	if (!is_ring_buffer_empty(c->buffer)) {
+		FD_SET(c->fd, &s->fd_wset);
+	}
+
+	return 1;
+}
+*/
+
+static int
+do_read(struct server_info* s, struct client_info* c) {
+	int id = c->to_id;
+	if (id < 0) {
+		do_close(s, c); //only when client disconnect
+		return -1;
+	}
+
+	struct client_info* to_c = s->client + id % TOTAL_CONNECTION;
+	if (to_c->id != id) {
+		do_close(s, c);
+		return -1;
+	}
+
+	struct ring_buffer* rb = to_c->buffer;
+
+	int len;
+	char* start_buffer = get_ring_buffer_write_ptr(rb, &len);
+	if (!start_buffer) {
+		return 0; //buff fulled
+	}
+
+	int n = (int)read(c->fd, start_buffer, len);
+	if (n == -1) {
+		switch (errno) {
+		case EAGAIN:
+			fprintf(stderr, "%s read fd error:EAGAIN.\n", get_time());
+			break;
+		case EINTR:
+			break;
+		default:
+			fprintf(stderr, "%s server: read (id=%d) error :%s.\n", get_time(), c->id, strerror(errno));
+			do_close(s, c);
+			return -1;
+		}
+
+		return 1;
+	}
+
+	if (n == 0) {
+		do_close(s, c); //normal close
+		return -1;
+	}
+
+	move_ring_buffer_write_pos(rb, n);
+	FD_SET(to_c->fd, &s->fd_wset);
+
+	if (n == len && !is_ring_buffer_empty(rb)) {
+		fprintf(stderr, "%s server: read again.\n", get_time());
+		return do_read(s, c);
+	}
+
+	return 1;
+}
+
+static int
+do_write(struct server_info* s, struct client_info* c) {
+	int len;
+	char* buffer = get_ring_buffer_read_ptr(c->buffer, &len);
+	if (!buffer) {
+		return 0;
+	}
+
+	int writed_len = 0;
+	char need_break = 0;
+	while (!need_break && writed_len < len) {
+		int n = write(c->fd, buffer, len - writed_len);
+		if (n < 0) {
+			switch (errno) {
+			case EINTR:
+				n = 0;
+				break;
+			case EAGAIN:
+				n = 0;
+				need_break = 1;
+				break;
+			default:
+				need_break = 1;
+				fprintf(stderr, "%s socket-server: write to (id=%d) error :%s.\n", get_time(), c->id, strerror(errno));
+				do_close(s, c);
+				return -1;
+			}
+		} else {
+			writed_len += n;
+			buffer += n;
+		}
+	}
+
+	move_ring_buffer_read_pos(c->buffer, writed_len);
+
+	if (is_ring_buffer_empty(c->buffer)) {
+		FD_CLR(c->fd, &s->fd_wset);
+	} else if (writed_len == len) {
+		fprintf(stderr, "%s server: write again.\n", get_time());
+		return do_write(s, c);
+	}
+
+	return 1;
+}
+
+static void
+pre_check_close(struct server_info* s) {
+	int len;
+	char* id_buffer = get_ring_buffer_read_ptr(s->wait_closed, &len);
+	if (!id_buffer) return;
+
+	int id_len = sizeof(int);
+	assert(len % id_len == 0);
+        int tmp = len;
+        
+	while (len > 0) {
+		int* id = (int*)id_buffer;
+		int idx = *id % TOTAL_CONNECTION;
+		id_buffer += id_len;
+		len -= len;
+
+		struct client_info* c = s->client + idx;
+		if (c->fd > 0) {
+			if (do_write(s, c) != -1) {
+				do_close(s, c);
+			}
+		}
+	}
+
+        move_ring_buffer_read_pos(s->wait_closed, tmp);
+}
+
+static void*
+server_thread(void* param) {
+	struct server_param *tp = (struct server_param*)param;
+	int fd1 = server_init(NULL, tp->listen_port[0]);
+	if (fd1 == -1) {
+		return NULL;
+	}
+	
+	int fd2 = server_init(NULL, tp->listen_port[1]);
+	if (fd2 == -1) {
+		close(fd1);
+		return NULL;
+	}
+
+	struct server_info s;
+	memset(&s, 0, sizeof(s));
+
+	s.listen_fd[0] = fd1;
+	s.listen_fd[1] = fd2;
+	s.listen_port[0] = tp->listen_port[0];
+	s.listen_port[1] = tp->listen_port[1];
+	int tmp_fd = fd1 > fd2 ? fd1: fd2;
+	tmp_fd = tp->pid > tmp_fd ? tp->pid : tmp_fd;
+
+	s.max_fd = tmp_fd + 1;
+	s.listen_id = -1;
+	s.wait_closed = alloc_ring_buffer(TOTAL_CONNECTION * sizeof(int));
+
+	FD_ZERO(&s.fd_wset);
+	FD_ZERO(&s.fd_rset);
+	FD_SET(fd1, &s.fd_rset);
+	FD_SET(fd2, &s.fd_rset);
+	FD_SET(tp->pid, &s.fd_rset);
+
+	while (1) {
+		pre_check_close(&s);
+
+		fd_set r_set = s.fd_rset;
+		fd_set w_set = s.fd_wset;
+
+		int cnt = select(s.max_fd, &r_set, &w_set, NULL, NULL);
+		if (cnt == -1) {
+			fprintf(stderr, "%s select error %s.\n", get_time(), strerror(errno));
+			continue;
+		}
+
+		if (FD_ISSET(s.listen_fd[1], &r_set)) {
+			//accept
+			--cnt;
+			do_accept(&s, s.listen_fd[1]);
+		}
+
+		if (FD_ISSET(s.listen_fd[0], &r_set)) {
+			//accept
+			--cnt;
+			do_accept(&s, s.listen_fd[0]);
+		}
+
+		int i;
+		for (i = s.client_cnt - 1; i >= 0 && cnt > 0; --i) {
+			int id = s.client_id[i] % TOTAL_CONNECTION;
+			struct client_info* c = &s.client[id];
+			int fd = c->fd;
+			assert(fd > 0);
+
+			if (FD_ISSET(fd, &r_set)) {
+				//read
+				--cnt;
+				if (do_read(&s, c) == -1) continue;
+			}
+
+			if (FD_ISSET(fd, &w_set)) {
+				//write
+				--cnt;
+				if (do_write(&s, c) == -1) continue;
+			}
+		}
+
+		if (FD_ISSET(tp->pid, &r_set)) {
+			//exit
+			break;
+		}
+	}
+
+	close(s.listen_fd[0]);
+	close(s.listen_fd[1]);
+
+	//try send the last buffer
+	fprintf(stderr, "%s ====================SERVER: SEND LAST DATA BEGIN===================.\n", get_time());
+
+	int i;
+	for (i = s.client_cnt - 1; i >= 0; --i) {
+		int id = s.client_id[i] % TOTAL_CONNECTION;
+		struct client_info* c = &s.client[id];
+		int fd = c->fd;
+		assert(fd > 0);
+
+		if (do_write(&s, c) != -1) {
+			do_close(&s, c);
+		}
+	}
+
+	fprintf(stderr, "%s ====================SERVER SEND LAST DATA END=====================.\n", get_time());
+
+	free_ring_buffer(s.wait_closed);
+	assert(s.client_cnt == 0);
+	return NULL;
+}
+
+pthread_t
+start_server(struct server_param* tp) {
+	pthread_t pid;
+	if (pthread_create(&pid, NULL, server_thread, tp)) {
+		fprintf(stderr, "%s Create server thread failed.\n", get_time());
+		exit(1);
+
+		return 0;
+	}
+
+	return pid;
+}

+ 16 - 0
server.h

@@ -0,0 +1,16 @@
+#ifndef SERVER_H
+#define SERVER_H
+
+#include <pthread.h>
+
+struct buffer_array;
+
+struct server_param {
+        int listen_port[2];
+		int pid;
+};
+
+pthread_t start_server(struct server_param* tp);
+void accept_info_init();
+
+#endif

+ 25 - 0
socket_comm.c

@@ -0,0 +1,25 @@
+#include "socket_comm.h"
+
+void
+sp_nonblocking(int fd) {
+	int flag = fcntl(fd, F_GETFL, 0);
+	if (-1 == flag) {
+		return;
+	}
+
+	fcntl(fd, F_SETFL, flag | O_NONBLOCK);
+}
+
+void
+set_keep_alive(int fd) {
+	//set keep alive
+	int keepAlive = 1; // 开启keepalive属性
+	int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测
+	int keepInterval = 5; // 探测时发包的时间间隔为5 秒
+	int keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.
+
+	setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
+	setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
+	setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
+	setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
+}

+ 38 - 0
socket_comm.h

@@ -0,0 +1,38 @@
+#ifndef SOCKET_COMM_H
+#define SOCKET_COMM_H
+
+#include "buffer.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define SOCKET_CONNECTED        1
+#define SOCKET_CONNECTING       2
+
+struct client_info
+{
+	int id;
+	int fd;
+	int to_id;
+	int connect_type;
+
+	struct ring_buffer* buffer;
+	char client_ip[128];
+};
+
+union sockaddr_all {
+	struct sockaddr s;          /*normal storage*/
+	struct sockaddr_in v4;      /*ipv4 storage*/
+	struct sockaddr_in6 v6;     /*ipv6 storage*/
+};
+
+void sp_nonblocking(int fd);
+void set_keep_alive(int fd);
+
+#endif

BIN=BIN
tunnel


+ 152 - 0
tunnel.c

@@ -0,0 +1,152 @@
+#include "tunnel.h"
+#include "server.h"
+#include "client.h"
+#include "buffer.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+static int pid = -1;
+
+static void
+set_terminated(int siga) {
+	int buffer = 1;
+	write(pid, &buffer, 1);
+
+	fprintf(stderr, "%s Receive exit signal,please wait.\n", get_time());
+
+	struct sigaction sa;
+	sa.sa_handler = SIG_IGN;
+	sigaction(SIGTERM, &sa, 0);
+	sigaction(SIGINT, &sa, 0);
+}
+
+static void
+deal_signal() {
+	struct sigaction sa, oldsa;
+	sa.sa_handler = SIG_IGN;
+	sigaction(SIGPIPE, &sa, 0);
+
+	sa.sa_handler = set_terminated;
+	sa.sa_flags = SA_NODEFER;
+	sigemptyset(&sa.sa_mask);
+
+	//kill
+	sigaction(SIGTERM, &sa, &oldsa);
+	//ctrl + c
+	sigaction(SIGINT, &sa, &oldsa);
+}
+
+static int
+check_port(int port_1, int port_2) {
+	if (port_1 <= 0 || port_1 > 65535 || port_1 <= 0 || port_2 >= 65535) {
+		return 0;
+	}
+
+	return 1;
+}
+
+char *
+get_time() {
+	//not for mul theread
+	static char st[50] = { 0 };
+	time_t tNow = time(NULL);
+
+	struct tm* ptm = localtime(&tNow);
+	strftime(st, 50, "%Y-%m-%d %H:%M:%S", ptm);
+
+	return st;
+}
+
+
+static void
+do_server(int p1, int p2, int pid) {
+	struct server_param sp;
+	sp.listen_port[0] = p1;
+	sp.listen_port[1] = p2;
+	sp.pid = pid;
+
+	pthread_t tid = start_server(&sp);
+
+	pthread_join(tid, NULL);
+
+	fprintf(stderr, "%s SERVER EXIT SUCCESS.................\n", get_time());
+}
+
+static void
+do_client(const char* ip, int p1, int p2, int pid) {
+	struct client_param cp;
+	cp.p1 = p1;
+	cp.p2 = p2;
+	cp.pid = pid;
+	strncpy(cp.remote_ip, ip, sizeof(cp.remote_ip));
+
+	pthread_t tid = start_client(&cp);
+	pthread_join(tid, NULL);
+
+	fprintf(stderr, "%s CLIENT EXIT SUCCESS.................\n", get_time());
+}
+
+static void
+error_param_tip() {
+	fprintf(stderr, "Usage:\n1.transfer -s port1[bind port for ssh server] prot2[bind port for ssh client]\n2.transfer -c remoteIp[remote server ip] port1[connect port to remote server] prot2[connect port to local ssh server]\n");
+}
+
+int
+main(int argc, char *argv[]) {
+	//usage:
+	//-s port1[bind port for ssh server] prot2[bind port for ssh client]
+	//-c port1[connect port to local ssh server] prot2[connect port to remote server]
+
+	if (argc <= 1){
+		error_param_tip();
+		return 0;
+	}
+
+	int port_1, port_2;
+	int fd[2];
+	if (pipe(fd)) {
+		fprintf(stderr, "%s create pipe error.................\n", get_time());
+		return -1;
+	}
+
+	pid = fd[1];
+	deal_signal();
+
+	if (argc == 4){
+		if (strncmp(argv[1], "-s", 2) == 0){
+			//do server
+			port_1 = atoi(argv[2]);
+			port_2 = atoi(argv[3]);
+			if (!check_port(port_1, port_2)) {
+				error_param_tip();
+				goto __fails;
+			}
+
+			do_server(port_1, port_2, fd[0]);
+		} else{
+			goto __fails;
+		}
+	} else if (argc == 5) {
+		if (strncmp(argv[1], "-c", 2) == 0){
+			// do client
+			const char* ip = argv[2];
+			port_1 = atoi(argv[3]);
+			port_2 = atoi(argv[4]);
+			if (!check_port(port_1, port_2)) {
+				error_param_tip();
+				goto __fails;
+			}
+
+			do_client(ip, port_1, port_2, fd[0]);
+		} else{
+			error_param_tip();
+		}
+	}
+
+__fails:
+	close(fd[0]);
+	close(fd[1]);
+	return 0;
+
+}

+ 1 - 0
tunnel.d

@@ -0,0 +1 @@
+tunnel: tunnel.c tunnel.h server.h client.h buffer.h

+ 15 - 0
tunnel.h

@@ -0,0 +1,15 @@
+#ifndef TUNNEL_H
+#define TUNNEL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#define MAX_CONNECTION 64
+#define TOTAL_CONNECTION 128
+#define MAX_CLIENT_BUFFER 65536
+
+char *get_time();
+
+#endif