Prechádzať zdrojové kódy

New feature: tcp_upstream, udp_upstream

hewei.it 4 rokov pred
rodič
commit
4b7168d62f
9 zmenil súbory, kde vykonal 202 pridanie a 121 odobranie
  1. 8 4
      Makefile
  2. 2 1
      README.md
  3. 2 0
      event/hevent.h
  4. 79 35
      event/hloop.c
  5. 36 5
      event/hloop.h
  6. 8 4
      examples/CMakeLists.txt
  7. 15 71
      examples/tcp_proxy_server.c
  8. 50 0
      examples/udp_proxy_server.c
  9. 2 1
      readme_cn.md

+ 8 - 4
Makefile

@@ -34,10 +34,11 @@ default: all
 all: libhv examples
 examples: hmain_test htimer_test hloop_test \
 	nc nmap httpd curl wget \
-	udp_echo_server \
 	tcp_echo_server \
 	tcp_chat_server \
 	tcp_proxy_server \
+	udp_echo_server \
+	udp_proxy_server \
 	http_server_test http_client_test \
 	websocket_server_test \
 	websocket_client_test \
@@ -71,9 +72,6 @@ htimer_test: prepare
 hloop_test: prepare
 	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/hloop_test.c"
 
-udp_echo_server: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/udp_echo_server.c"
-
 tcp_echo_server: prepare
 	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/tcp_echo_server.c"
 
@@ -83,6 +81,12 @@ tcp_chat_server: prepare
 tcp_proxy_server: prepare
 	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/tcp_proxy_server.c"
 
+udp_echo_server: prepare
+	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/udp_echo_server.c"
+
+udp_proxy_server: prepare
+	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/udp_proxy_server.c"
+
 nc: prepare
 	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/nc.c"
 

+ 2 - 1
README.md

@@ -11,7 +11,7 @@ but simpler api and richer protocols.
 
 - Cross-platform (Linux, Windows, Mac, Solaris)
 - EventLoop (IO, timer, idle)
-- TCP/UDP client/server
+- TCP/UDP client/server/proxy
 - SSL/TLS support: WITH_OPENSSL or WITH_MBEDTLS
 - HTTP client/server (include https http1/x http2 grpc)
 - HTTP file service, indexof service, api service (support RESTful)
@@ -166,6 +166,7 @@ wrk -c 100 -t 4 -d 10s http://127.0.0.1:8080/
 - [examples/tcp_chat_server.c](examples/tcp_chat_server.c)
 - [examples/tcp_proxy_server.c](examples/tcp_proxy_server.c)
 - [examples/udp_echo_server.c](examples/udp_echo_server.c)
+- [examples/udp_proxy_server.c](examples/udp_proxy_server.c)
 - [examples/nc.c](examples/nc.c)
 
 ### c++ version

+ 2 - 0
event/hevent.h

@@ -125,6 +125,8 @@ struct hio_s {
     int         heartbeat_interval; // ms
     hio_send_heartbeat_fn heartbeat_fn;
     htimer_t*   heartbeat_timer;
+    // upstream
+    struct hio_s*   upstream_io;
 // private:
     int         event_index[2]; // for poll,kqueue
     void*       hovlp;          // for iocp/overlapio

+ 79 - 35
event/hloop.c

@@ -675,6 +675,8 @@ void hio_ready(hio_t* io) {
     io->heartbeat_interval = 0;
     io->heartbeat_fn = NULL;
     io->heartbeat_timer = NULL;
+    // upstream
+    io->upstream_io = NULL;
     // private:
     io->event_index[0] = io->event_index[1] = -1;
     io->hovlp = NULL;
@@ -750,7 +752,7 @@ hio_t* hio_get(hloop_t* loop, int fd) {
 }
 
 int hio_add(hio_t* io, hio_cb cb, int events) {
-    printd("hio_add fd=%d events=%d\n", io->fd, events);
+    printd("hio_add fd=%d io->events=%d events=%d\n", io->fd, io->events, events);
 #ifdef OS_WIN
     // Windows iowatcher not work on stdio
     if (io->fd < 3) return -1;
@@ -769,8 +771,10 @@ int hio_add(hio_t* io, hio_cb cb, int events) {
         io->cb = (hevent_cb)cb;
     }
 
-    iowatcher_add_event(loop, io->fd, events);
-    io->events |= events;
+    if (!(io->events & events)) {
+        iowatcher_add_event(loop, io->fd, events);
+        io->events |= events;
+    }
     return 0;
 }
 
@@ -782,7 +786,7 @@ int hio_del(hio_t* io, int events) {
 #endif
     if (!io->active) return -1;
 
-    if (io->events) {
+    if (io->events & events) {
         iowatcher_del_event(io->loop, io->fd, events);
         io->events &= ~events;
     }
@@ -878,19 +882,7 @@ hio_t* hsendto (hloop_t* loop, int sockfd, const void* buf, size_t len, hwrite_c
     return hwrite(loop, sockfd, buf, len, write_cb);
 }
 
-hio_t* hloop_create_tcp_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb) {
-    int listenfd = Listen(port, host);
-    if (listenfd < 0) {
-        return NULL;
-    }
-    hio_t* io = haccept(loop, listenfd, accept_cb);
-    if (io == NULL) {
-        closesocket(listenfd);
-    }
-    return io;
-}
-
-hio_t* hloop_create_tcp_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb) {
+hio_t* hio_create(hloop_t* loop, const char* host, int port, int type) {
     sockaddr_u peeraddr;
     memset(&peeraddr, 0, sizeof(peeraddr));
     int ret = sockaddr_set_ipport(&peeraddr, host, port);
@@ -898,7 +890,7 @@ hio_t* hloop_create_tcp_client (hloop_t* loop, const char* host, int port, hconn
         //printf("unknown host: %s\n", host);
         return NULL;
     }
-    int connfd = socket(peeraddr.sa.sa_family, SOCK_STREAM, 0);
+    int connfd = socket(peeraddr.sa.sa_family, type, 0);
     if (connfd < 0) {
         perror("socket");
         return NULL;
@@ -907,11 +899,28 @@ hio_t* hloop_create_tcp_client (hloop_t* loop, const char* host, int port, hconn
     hio_t* io = hio_get(loop, connfd);
     assert(io != NULL);
     hio_set_peeraddr(io, &peeraddr.sa, sockaddr_len(&peeraddr));
-    hconnect(loop, connfd, connect_cb);
     return io;
 }
 
-// @server: socket -> bind -> hrecvfrom
+hio_t* hloop_create_tcp_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb) {
+    int listenfd = Listen(port, host);
+    if (listenfd < 0) {
+        return NULL;
+    }
+    hio_t* io = haccept(loop, listenfd, accept_cb);
+    if (io == NULL) {
+        closesocket(listenfd);
+    }
+    return io;
+}
+
+hio_t* hloop_create_tcp_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb) {
+    hio_t* io = hio_create(loop, host, port, SOCK_STREAM);
+    if (io == NULL) return NULL;
+    hconnect(loop, io->fd, connect_cb);
+    return io;
+}
+
 hio_t* hloop_create_udp_server(hloop_t* loop, const char* host, int port) {
     int bindfd = Bind(port, host, SOCK_DGRAM);
     if (bindfd < 0) {
@@ -920,24 +929,59 @@ hio_t* hloop_create_udp_server(hloop_t* loop, const char* host, int port) {
     return hio_get(loop, bindfd);
 }
 
-// @client: Resolver -> socket -> hio_get -> hio_set_peeraddr
 hio_t* hloop_create_udp_client(hloop_t* loop, const char* host, int port) {
-    sockaddr_u peeraddr;
-    memset(&peeraddr, 0, sizeof(peeraddr));
-    int ret = sockaddr_set_ipport(&peeraddr, host, port);
-    if (ret != 0) {
-        //printf("unknown host: %s\n", host);
-        return NULL;
+    return hio_create(loop, host, port, SOCK_DGRAM);
+}
+
+// upstream
+void hio_read_upstream(hio_t* io) {
+    hio_t* upstream_io = io->upstream_io;
+    if (upstream_io) {
+        hio_read(io);
+        hio_read(upstream_io);
     }
+}
 
-    int sockfd = socket(peeraddr.sa.sa_family, SOCK_DGRAM, 0);
-    if (sockfd < 0) {
-        perror("socket");
-        return NULL;
+void hio_write_upstream(hio_t* io, void* buf, int bytes) {
+    hio_t* upstream_io = io->upstream_io;
+    if (upstream_io) {
+        hio_write(upstream_io, buf, bytes);
     }
+}
 
-    hio_t* io = hio_get(loop, sockfd);
-    assert(io != NULL);
-    hio_set_peeraddr(io, &peeraddr.sa, sockaddr_len(&peeraddr));
-    return io;
+void hio_close_upstream(hio_t* io) {
+    hio_t* upstream_io = io->upstream_io;
+    if (upstream_io) {
+        hio_close(upstream_io);
+    }
+}
+
+void hio_setup_upstream(hio_t* io1, hio_t* io2) {
+    io1->upstream_io = io2;
+    io2->upstream_io = io1;
+    hio_setcb_read(io1, hio_write_upstream);
+    hio_setcb_read(io2, hio_write_upstream);
+}
+
+hio_t* hio_get_upstream(hio_t* io) {
+    return io->upstream_io;
+}
+
+hio_t* hio_setup_tcp_upstream(hio_t* io, const char* host, int port, int ssl) {
+    hio_t* upstream_io = hio_create(io->loop, host, port, SOCK_STREAM);
+    if (upstream_io == NULL) return NULL;
+    if (ssl) hio_enable_ssl(upstream_io);
+    hio_setup_upstream(io, upstream_io);
+    hio_setcb_close(io, hio_close_upstream);
+    hio_setcb_close(upstream_io, hio_close_upstream);
+    hconnect(io->loop, upstream_io->fd, hio_read_upstream);
+    return upstream_io;
+}
+
+hio_t* hio_setup_udp_upstream(hio_t* io, const char* host, int port) {
+    hio_t* upstream_io = hio_create(io->loop, host, port, SOCK_DGRAM);
+    if (upstream_io == NULL) return NULL;
+    hio_setup_upstream(io, upstream_io);
+    hio_read_upstream(io);
+    return upstream_io;
 }

+ 36 - 5
event/hloop.h

@@ -291,21 +291,52 @@ HV_EXPORT hio_t* hrecvfrom (hloop_t* loop, int sockfd, void* buf, size_t len, hr
 // hio_get -> hio_setcb_write -> hio_write
 HV_EXPORT hio_t* hsendto   (hloop_t* loop, int sockfd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
 
-//----------------- top-level apis---------------------------------------------
+//-----------------top-level apis---------------------------------------------
+// Resolver -> socket -> hio_get
+HV_EXPORT hio_t* hio_create(hloop_t* loop, const char* host, int port, int type DEFAULT(SOCK_STREAM));
 // @tcp_server: socket -> bind -> listen -> haccept
-// @see examples/tcp.c
+// @see examples/tcp_echo_server.c
 HV_EXPORT hio_t* hloop_create_tcp_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb);
-// @tcp_client: resolver -> socket -> hio_get -> hio_set_peeraddr -> hconnect
+// @tcp_client: hio_create(loop, host, port, SOCK_STREAM) -> hconnect
 // @see examples/nc.c
 HV_EXPORT hio_t* hloop_create_tcp_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb);
 
 // @udp_server: socket -> bind -> hio_get
-// @see examples/udp.c
+// @see examples/udp_echo_server.c
 HV_EXPORT hio_t* hloop_create_udp_server (hloop_t* loop, const char* host, int port);
-// @udp_client: resolver -> socket -> hio_get -> hio_set_peeraddr
+// @udp_client: hio_create(loop, host, port, SOCK_DGRAM)
 // @see examples/nc.c
 HV_EXPORT hio_t* hloop_create_udp_client (hloop_t* loop, const char* host, int port);
 
+//-----------------upstream---------------------------------------------
+// hio_read(io)
+// hio_read(io->upstream_io)
+HV_EXPORT void   hio_read_upstream(hio_t* io);
+// hio_write(io->upstream_io, buf, bytes)
+HV_EXPORT void   hio_write_upstream(hio_t* io, void* buf, int bytes);
+// hio_close(io->upstream_io)
+HV_EXPORT void   hio_close_upstream(hio_t* io);
+
+// io1->upstream_io = io2;
+// io2->upstream_io = io1;
+// hio_setcb_read(io1, hio_write_upstream);
+// hio_setcb_read(io2, hio_write_upstream);
+HV_EXPORT void   hio_setup_upstream(hio_t* io1, hio_t* io2);
+
+// @return io->upstream_io
+HV_EXPORT hio_t* hio_get_upstream(hio_t* io);
+
+// @tcp_upstream: hio_create -> hio_setup_upstream -> hio_setcb_close(hio_close_upstream) -> hconnect -> on_connect -> hio_read_upstream
+// @return upstream_io
+// @see examples/tcp_proxy_server
+HV_EXPORT hio_t* hio_setup_tcp_upstream(hio_t* io, const char* host, int port, int ssl DEFAULT(0));
+#define hio_setup_ssl_upstream(io, host, port) hio_setup_tcp_upstream(io, host, port, 1)
+
+// @udp_upstream: hio_create -> hio_setup_upstream -> hio_read_upstream
+// @return upstream_io
+// @see examples/udp_proxy_server
+HV_EXPORT hio_t* hio_setup_udp_upstream(hio_t* io, const char* host, int port);
+
 END_EXTERN_C
 
 #endif // HV_LOOP_H_

+ 8 - 4
examples/CMakeLists.txt

@@ -4,10 +4,11 @@ list(APPEND EXAMPLES
     htimer_test
     nc
     nmap
-    udp_echo_server
     tcp_echo_server
     tcp_chat_server
     tcp_proxy_server
+    udp_echo_server
+    udp_proxy_server
 )
 
 include_directories(.. ../base ../utils ../event ../evpp)
@@ -28,9 +29,6 @@ add_executable(nmap nmap.cpp)
 target_compile_definitions(nmap PRIVATE -DPRINT_DEBUG)
 target_link_libraries(nmap hv)
 
-add_executable(udp_echo_server udp_echo_server.c)
-target_link_libraries(udp_echo_server hv)
-
 add_executable(tcp_echo_server tcp_echo_server.c)
 target_link_libraries(tcp_echo_server hv)
 
@@ -40,6 +38,12 @@ target_link_libraries(tcp_chat_server hv)
 add_executable(tcp_proxy_server tcp_proxy_server.c)
 target_link_libraries(tcp_proxy_server hv)
 
+add_executable(udp_echo_server udp_echo_server.c)
+target_link_libraries(udp_echo_server hv)
+
+add_executable(udp_proxy_server udp_proxy_server.c)
+target_link_libraries(udp_proxy_server hv)
+
 if(WITH_HTTP)
     include_directories(../http)
 if(WITH_HTTP_SERVER)

+ 15 - 71
examples/tcp_proxy_server.c

@@ -1,12 +1,14 @@
 /*
  * tcp proxy server
  *
- * @build:        make examples
- * @http_server:  bin/httpd -d
- * @proxy_server: bin/tcp_proxy_server 1234 127.0.0.1:8080
- *                bin/tcp_proxy_server 1234 www.baidu.com
- * @client:       bin/curl -v 127.0.0.1:1234
- *                bin/nc 127.0.0.1 1234
+ * @build:        make clean && make examples WITH_OPENSSL=yes
+ * @http_server:  bin/httpd -s restart -d
+ * @proxy_server: bin/tcp_proxy_server 8888 127.0.0.1:8080
+ *                bin/tcp_proxy_server 8888 127.0.0.1:8443
+ *                bin/tcp_proxy_server 8888 www.baidu.com
+ *                bin/tcp_proxy_server 8888 www.baidu.com:443
+ * @client:       bin/curl -v 127.0.0.1:8888
+ *                bin/nc 127.0.0.1 8888
  *                > GET / HTTP/1.1
  *                > Connection: close
  *                > [Enter]
@@ -18,82 +20,24 @@
 #include "hloop.h"
 #include "hsocket.h"
 
-// hloop_create_tcp_server
-// on_accept(connio) => proxyio = hloop_create_tcp_client
-// on_proxy_connect(proxyio) => hio_read(connio) hio_read(proxyio)
-// on_recv(connio) => hio_write(proxyio)
-// on_proxy_recv(proxyio) => hio_write(connio)
-// on_close(connio) => hio_close(proxyio)
-// on_proxy_close(proxyio) => hio_close(connio)
-
 static char proxy_host[64] = "127.0.0.1";
-static int proxy_port = 80;
-
-static void on_proxy_close(hio_t* proxyio) {
-    hio_t* connio = (hio_t*)hevent_userdata(proxyio);
-    if (connio) {
-        hevent_set_userdata(proxyio, NULL);
-        hio_close(connio);
-    }
-}
-
-static void on_proxy_recv(hio_t* proxyio, void* buf, int readbytes) {
-    hio_t* connio = (hio_t*)hevent_userdata(proxyio);
-    assert(connio != NULL);
-    hio_write(connio, buf, readbytes);
-}
-
-static void on_proxy_connect(hio_t* proxyio) {
-    hio_t* connio = (hio_t*)hevent_userdata(proxyio);
-    assert(connio != NULL);
-    hio_read(connio);
-
-    hio_setcb_close(proxyio, on_proxy_close);
-    hio_setcb_read(proxyio, on_proxy_recv);
-    hio_read(proxyio);
-}
-
-static void on_close(hio_t* io) {
-    printf("on_close fd=%d error=%d\n", hio_fd(io), hio_error(io));
-    hio_t* proxyio = (hio_t*)hevent_userdata(io);
-    if (proxyio) {
-        hevent_set_userdata(io, NULL);
-        hio_close(proxyio);
-    }
-}
-
-static void on_recv(hio_t* io, void* buf, int readbytes) {
-    printf("on_recv fd=%d readbytes=%d\n", hio_fd(io), readbytes);
-    char localaddrstr[SOCKADDR_STRLEN] = {0};
-    char peeraddrstr[SOCKADDR_STRLEN] = {0};
-    printf("[%s] <=> [%s]\n",
-            SOCKADDR_STR(hio_localaddr(io), localaddrstr),
-            SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
-    printf("< %.*s", readbytes, (char*)buf);
+static int  proxy_port = 80;
+static int  proxy_ssl = 0;
 
-    hio_t* proxyio = (hio_t*)hevent_userdata(io);
-    assert(proxyio != NULL);
-    hio_write(proxyio, buf, readbytes);
-}
+// hloop_create_tcp_server -> on_accept -> hio_setup_tcp_upstream
 
 static void on_accept(hio_t* io) {
+    /*
     printf("on_accept connfd=%d\n", hio_fd(io));
     char localaddrstr[SOCKADDR_STRLEN] = {0};
     char peeraddrstr[SOCKADDR_STRLEN] = {0};
     printf("accept connfd=%d [%s] <= [%s]\n", hio_fd(io),
             SOCKADDR_STR(hio_localaddr(io), localaddrstr),
             SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
+    */
 
-    hio_t* proxyio = hloop_create_tcp_client(hevent_loop(io), proxy_host, proxy_port, on_proxy_connect);
-    if (proxyio == NULL) {
-        hio_close(io);
-        return;
-    }
-
-    hio_setcb_read(io, on_recv);
-    hio_setcb_close(io, on_close);
-    hevent_set_userdata(io, proxyio);
-    hevent_set_userdata(proxyio, io);
+    if (proxy_port % 1000 == 443) proxy_ssl = 1;
+    hio_setup_tcp_upstream(io, proxy_host, proxy_port, proxy_ssl);
 }
 
 int main(int argc, char** argv) {

+ 50 - 0
examples/udp_proxy_server.c

@@ -0,0 +1,50 @@
+/*
+ * udp proxy server
+ *
+ * @build:        make examples
+ * @udp_server:   bin/udp_echo_server 1234
+ * @proxy_server: bin/udp_proxy_server 2222 127.0.0.1:1234
+ * @client:       bin/nc -u 127.0.0.1 2222
+ *                > hello
+ *                < hello
+ */
+
+#include "hloop.h"
+
+static char proxy_host[64] = "127.0.0.1";
+static int proxy_port = 1234;
+
+// hloop_create_udp_server -> hio_setup_udp_upstream
+
+int main(int argc, char** argv) {
+    if (argc < 3) {
+        printf("Usage: %s port proxy_host:proxy_port\n", argv[0]);
+        return -10;
+    }
+    int port = atoi(argv[1]);
+    char* pos = strchr(argv[2], ':');
+    if (pos) {
+        int len = pos - argv[2];
+        if (len > 0) {
+            memcpy(proxy_host, argv[2], len);
+            proxy_host[len] = '\0';
+        }
+        proxy_port = atoi(pos + 1);
+    } else {
+        strncpy(proxy_host, argv[2], sizeof(proxy_host));
+    }
+    printf("proxy: [%s:%d]\n", proxy_host, proxy_port);
+
+    hloop_t* loop = hloop_new(0);
+    hio_t* io = hloop_create_udp_server(loop, "0.0.0.0", port);
+    if (io == NULL) {
+        return -20;
+    }
+    hio_t* upstream_io = hio_setup_udp_upstream(io, proxy_host, proxy_port);
+    if (upstream_io == NULL) {
+        return -30;
+    }
+    hloop_run(loop);
+    hloop_free(&loop);
+    return 0;
+}

+ 2 - 1
readme_cn.md

@@ -9,7 +9,7 @@
 
 - 跨平台(Linux, Windows, Mac, Solaris)
 - 高性能事件循环(网络IO事件、定时器事件、空闲事件)
-- TCP/UDP服务端/客户端
+- TCP/UDP服务端/客户端/代理
 - SSL/TLS加密通信(WITH_OPENSSL or WITH_MBEDTLS)
 - HTTP服务端/客户端(https http1/x http2 grpc)
 - HTTP文件服务、目录服务、API服务(支持RESTful)
@@ -169,6 +169,7 @@ wrk -c 100 -t 4 -d 10s http://127.0.0.1:8080/
 - TCP聊天服务:  [examples/tcp_chat_server.c](examples/tcp_chat_server.c)
 - TCP代理服务:  [examples/tcp_proxy_server.c](examples/tcp_proxy_server.c)
 - UDP回显服务:  [examples/udp_echo_server.c](examples/udp_echo_server.c)
+- UDP代理服务:  [examples/udp_proxy_server.c](examples/udp_proxy_server.c)
 - TCP/UDP客户端: [examples/nc.c](examples/nc.c)
 
 ### c++版本