| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- /*
- * kcptun server
- *
- * @build: ./configure --with-kcp && make clean && make kcptun examples
- * @tcp_server: bin/tcp_echo_server 1234
- * @kcptun_server: bin/kcptun_server -l :4000 -t 127.0.0.1:1234
- * @kcptun_client: bin/kcptun_client -l :8388 -r 127.0.0.1:4000
- * @tcp_client: bin/nc 127.0.0.1 8388
- * > hello
- * < hello
- */
- #define WITH_KCP 1
- #include "hversion.h"
- #include "hmain.h"
- #include "hsocket.h"
- #include "hloop.h"
- #include "../smux/smux.h"
- // config
- static const char* localaddr = ":4000";
- static const char* targetaddr = "127.0.0.1:8080";
- static const char* mode = "fast";
- static int mtu = 1350;
- static int sndwnd = 1024;
- static int rcvwnd = 1024;
- // short options
- static const char options[] = "hvdl:t:m:";
- // long options
- static const option_t long_options[] = {
- {'h', "help", NO_ARGUMENT},
- {'v', "version", NO_ARGUMENT},
- {'d', "daemon", NO_ARGUMENT},
- {'l', "listen", REQUIRED_ARGUMENT},
- {'t', "target", REQUIRED_ARGUMENT},
- {'m', "mode", REQUIRED_ARGUMENT},
- { 0, "mtu", REQUIRED_ARGUMENT},
- { 0, "sndwnd", REQUIRED_ARGUMENT},
- { 0, "rcvwnd", REQUIRED_ARGUMENT},
- };
- static const char detail_options[] = R"(
- -h|--help Print this information
- -v|--version Print version
- -d|--daemon Daemonize
- -l|--listen value kcp server listen address (default: ":4000")
- -t|--target value target server address (default: "127.0.0.1:8080")
- -m|--mode value profiles: fast3, fast2, fast, normal (default: "fast")
- --mtu value set maximum transmission unit for UDP packets (default: 1350)
- --sndwnd value set send window size(num of packets) (default: 1024)
- --rcvwnd value set receive window size(num of packets) (default: 1024)
- )";
- static void print_version() {
- printf("%s version %s\n", g_main_ctx.program_name, hv_compile_version());
- }
- static void print_help() {
- printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
- printf("Options:\n%s\n", detail_options);
- }
- static kcp_setting_t s_kcp_setting;
- static char kcp_host[64] = "0.0.0.0";
- static int kcp_port = 4000;
- static hio_t* kcp_io = NULL;
- static char target_host[64] = "127.0.0.1";
- static int target_port = 8080;
- static smux_config_t smux_config;
- static smux_session_t smux_session;
- static int verbose = 1;
- /* workflow:
- *
- * hloop_create_udp_server -> on_recvfrom ->
- *
- * SYN -> hloop_create_tcp_client ->
- * on_connect -> hio_write(kcp_io, SYN) ->
- * on_read -> hio_write(kcp_io) ->
- * on_close -> hio_write(kcp_io, FIN) -> smux_session_close_stream
- *
- * PSH -> smux_session_get_stream -> hio_write(stream_io)
- *
- * FIN -> smux_session_get_stream -> hio_close(stream_io)
- *
- */
- // hloop_create_udp_server -> hio_set_kcp -> on_recvfrom ->
- // SYN -> hloop_create_tcp_client -> smux_session_open_stream ->
- // PSH -> hio_write(io)
- static void on_close(hio_t* io) {
- // printf("on_close fd=%d error=%d\n", hio_fd(io), hio_error(io));
- if (verbose) {
- char localaddrstr[SOCKADDR_STRLEN] = {0};
- char peeraddrstr[SOCKADDR_STRLEN] = {0};
- printf("disconnected connfd=%d [%s] => [%s]\n", hio_fd(io),
- SOCKADDR_STR(hio_localaddr(io), localaddrstr),
- SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
- }
- smux_stream_t* smux_stream = (smux_stream_t*)hevent_userdata(io);
- if (smux_stream == NULL) return;
- // FIN
- int packlen = smux_stream_output(smux_stream, SMUX_CMD_FIN);
- if (packlen > 0) {
- // printf("FIN %d\n", packlen);
- hio_write(kcp_io, smux_stream->wbuf.base, packlen);
- }
- // kill timer
- if (smux_stream->timer) {
- htimer_del(smux_stream->timer);
- smux_stream->timer = NULL;
- }
- // free buffer
- HV_FREE(smux_stream->rbuf.base);
- HV_FREE(smux_stream->wbuf.base);
- smux_session_close_stream(&smux_session, smux_stream->stream_id);
- hevent_set_userdata(io, NULL);
- }
- static void on_recv(hio_t* io, void* buf, int readbytes) {
- // printf("on_recv %.*s \n", readbytes, (char*)buf);
- smux_stream_t* smux_stream = (smux_stream_t*)hevent_userdata(io);
- if (smux_stream == NULL) return;
- // PSH
- smux_frame_t frame;
- smux_frame_init(&frame);
- frame.head.sid = smux_stream->stream_id;
- frame.head.cmd = SMUX_CMD_PSH;
- frame.head.length = readbytes;
- frame.data = (const char*)buf;
- int packlen = smux_frame_pack(&frame, smux_stream->wbuf.base, smux_stream->wbuf.len);
- if (packlen > 0) {
- // printf("PSH %d\n", packlen);
- int nwrite = hio_write(kcp_io, smux_stream->wbuf.base, packlen);
- // printf("PSH ret=%d\n", nwrite);
- }
- }
- static void on_connect(hio_t* io) {
- // printf("on_connect fd=%d\n", hio_fd(io));
- if (verbose) {
- char localaddrstr[SOCKADDR_STRLEN] = {0};
- char peeraddrstr[SOCKADDR_STRLEN] = {0};
- printf("connected connfd=%d [%s] => [%s]\n", hio_fd(io),
- SOCKADDR_STR(hio_localaddr(io), localaddrstr),
- SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
- }
- smux_stream_t* smux_stream = (smux_stream_t*)hevent_userdata(io);
- if (smux_stream == NULL) return;
- // SYN
- int packlen = smux_stream_output(smux_stream, SMUX_CMD_SYN);
- if (packlen > 0) {
- // printf("SYN %d\n", packlen);
- hio_write(kcp_io, smux_stream->wbuf.base, packlen);
- }
- hio_setcb_read(io, on_recv);
- hio_read(io);
- }
- static void on_kcp_recvfrom(hio_t* io, void* buf, int readbytes) {
- // printf("on_kcp_recvfrom %d\n", readbytes);
- smux_frame_t frame;
- smux_frame_init(&frame);
- int packlen = smux_frame_unpack(&frame, buf, readbytes);
- assert(packlen == readbytes);
- if (packlen < 0 ||
- frame.head.version > 2 ||
- frame.head.cmd > SMUX_CMD_UPD) {
- fprintf(stderr, "smux_frame_unpack error: %d\n", packlen);
- return;
- }
- // printf("smux sid=%u cmd=%d length=%d\n", frame.head.sid, (int)frame.head.cmd, (int)frame.head.length);
- smux_stream_t* smux_stream = NULL;
- if (frame.head.cmd == SMUX_CMD_SYN) {
- hio_t* target_io = hio_create_socket(hevent_loop(kcp_io), target_host, target_port, HIO_TYPE_TCP, HIO_CLIENT_SIDE);
- if (target_io == NULL) {
- fprintf(stderr, "create tcp client error!\n");
- return;
- }
- smux_stream = smux_session_open_stream(&smux_session, frame.head.sid, target_io);
- // alloc buffer
- smux_stream->rbuf.len = mtu;
- smux_stream->wbuf.len = mtu;
- HV_ALLOC(smux_stream->rbuf.base, smux_stream->rbuf.len);
- HV_ALLOC(smux_stream->wbuf.base, smux_stream->wbuf.len);
- hio_set_readbuf(target_io, smux_stream->rbuf.base, smux_config.max_frame_size);
- hevent_set_userdata(target_io, smux_stream);
- hio_setcb_connect(target_io, on_connect);
- hio_setcb_close(target_io, on_close);
- hio_connect(target_io);
- } else {
- smux_stream = smux_session_get_stream(&smux_session, frame.head.sid);
- }
- if (smux_stream == NULL) {
- if (frame.head.sid != 0 && frame.head.cmd != SMUX_CMD_FIN) {
- fprintf(stderr, "recvfrom invalid smux package!\n");
- }
- return;
- }
- switch (frame.head.cmd) {
- case SMUX_CMD_FIN:
- hio_close(smux_stream->io);
- break;
- case SMUX_CMD_PSH:
- hio_write(smux_stream->io, frame.data, frame.head.length);
- break;
- case SMUX_CMD_NOP:
- break;
- default:
- break;
- }
- }
- int main(int argc, char** argv) {
- if (argc < 2) {
- print_help();
- exit(0);
- }
- // g_main_ctx
- main_ctx_init(argc, argv);
- //int ret = parse_opt(argc, argv, options);
- int ret = parse_opt_long(argc, argv, long_options, ARRAY_SIZE(long_options));
- if (ret != 0) {
- print_help();
- exit(ret);
- }
- // help
- if (get_arg("h")) {
- print_help();
- exit(0);
- }
- // version
- if (get_arg("v")) {
- print_version();
- exit(0);
- }
- #ifdef OS_UNIX
- // daemon
- if (get_arg("d")) {
- // nochdir, noclose
- int ret = daemon(1, 1);
- if (ret != 0) {
- printf("daemon error: %d\n", ret);
- exit(-10);
- }
- }
- #endif
- const char* arg = get_arg("l");
- if (arg) {
- localaddr = arg;
- }
- arg = get_arg("t");
- if (arg) {
- targetaddr = arg;
- }
- arg = get_arg("m");
- if (arg) {
- mode = arg;
- }
- arg = get_arg("mtu");
- if (arg) {
- mtu = atoi(arg);
- }
- arg = get_arg("sndwnd");
- if (arg) {
- sndwnd = atoi(arg);
- }
- arg = get_arg("rcvwnd");
- if (arg) {
- rcvwnd = atoi(arg);
- }
- const char* pos = strchr(localaddr, ':');
- int len = 0;
- if (pos) {
- len = pos - localaddr;
- if (len > 0) {
- memcpy(kcp_host, localaddr, len);
- kcp_host[len] = '\0';
- }
- kcp_port = atoi(pos + 1);
- }
- pos = strchr(targetaddr, ':');
- if (pos) {
- len = pos - targetaddr;
- if (len > 0) {
- memcpy(target_host, targetaddr, len);
- target_host[len] = '\0';
- }
- target_port = atoi(pos + 1);
- }
- if (strcmp(mode, "normal") == 0) {
- kcp_setting_init_with_normal_mode(&s_kcp_setting);
- } else if (strcmp(mode, "fast") == 0) {
- kcp_setting_init_with_fast_mode(&s_kcp_setting);
- } else if (strcmp(mode, "fast2") == 0) {
- kcp_setting_init_with_fast2_mode(&s_kcp_setting);
- } else if (strcmp(mode, "fast3") == 0) {
- kcp_setting_init_with_fast3_mode(&s_kcp_setting);
- } else {
- fprintf(stderr, "Unknown mode '%s'\n", mode);
- exit(-20);
- }
- s_kcp_setting.mtu = mtu;
- s_kcp_setting.sndwnd = sndwnd;
- s_kcp_setting.rcvwnd = rcvwnd;
- printf("smux version: 1\n");
- printf("%s:%d => %s:%d\n", kcp_host, kcp_port, target_host, target_port);
- printf("mode: %s\n", mode);
- printf("mtu: %d\n", mtu);
- printf("sndwnd: %d rcvwnd: %d\n", sndwnd, rcvwnd);
- hloop_t* loop = hloop_new(0);
- kcp_io = hloop_create_udp_server(loop, kcp_host, kcp_port);
- if (kcp_io == NULL) {
- fprintf(stderr, "create udp server error!\n");
- return -20;
- }
- hio_set_kcp(kcp_io, &s_kcp_setting);
- hio_setcb_read(kcp_io, on_kcp_recvfrom);
- hio_read(kcp_io);
- // smux
- smux_config.max_frame_size = 1024;
- smux_session.next_stream_id = 0;
- hloop_run(loop);
- hloop_free(&loop);
- return 0;
- }
|