Browse Source

WITH_GNUTLS

ithewei 4 years ago
parent
commit
1ad306b07c
30 changed files with 627 additions and 259 deletions
  1. 1 1
      BUILD.md
  2. 9 3
      CMakeLists.txt
  3. 28 28
      Makefile
  4. 5 0
      Makefile.in
  5. 5 3
      Makefile.vars
  6. 1 1
      README-CN.md
  7. 1 1
      README.md
  8. 1 0
      TREE.md
  9. 0 1
      base/README.md
  10. 8 5
      cmake/vars.cmake
  11. 1 0
      config.ini
  12. 2 1
      config.mk
  13. 4 0
      configure
  14. 1 1
      evpp/TcpClient.h
  15. 1 1
      evpp/TcpServer.h
  16. 1 1
      examples/CMakeLists.txt
  17. 2 0
      examples/httpd/httpd.cpp
  18. 3 0
      hconfig.h
  19. 4 0
      hconfig.h.in
  20. 1 0
      http/server/HttpServer.cpp
  21. 0 1
      hv.h
  22. 3 1
      scripts/shini.sh
  23. 50 0
      ssl/appletls.c
  24. 190 0
      ssl/gnutls.c
  25. 10 0
      ssl/hssl.c
  26. 29 5
      ssl/hssl.h
  27. 11 205
      ssl/mbedtls.c
  28. 50 0
      ssl/nossl.c
  29. 155 0
      ssl/openssl.c
  30. 50 0
      ssl/wintls.c

+ 1 - 1
BUILD.md

@@ -93,7 +93,7 @@ make libhv
 ### compile WITH_OPENSSL
 Enable SSL in libhv is so easy, just only two apis:
 ```
-// init ssl_ctx, see base/hssl.h
+// init ssl_ctx, see ssl/hssl.h
 hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param);
 
 // enable ssl, see event/hloop.h

+ 9 - 3
CMakeLists.txt

@@ -25,6 +25,7 @@ option(WITH_CURL "with curl library" OFF)
 option(WITH_NGHTTP2 "with nghttp2 library" OFF)
 
 option(WITH_OPENSSL "with openssl library" OFF)
+option(WITH_GNUTLS  "with gnutls library"  OFF)
 option(WITH_MBEDTLS "with mbedtls library" OFF)
 
 set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
@@ -105,6 +106,11 @@ if(WITH_OPENSSL)
     set(LIBS ${LIBS} ssl crypto)
 endif()
 
+if(WITH_GNUTLS)
+    add_definitions(-DWITH_GNUTLS)
+    set(LIBS ${LIBS} gnutls)
+endif()
+
 if(WITH_MBEDTLS)
     add_definitions(-DWITH_MBEDTLS)
     set(LIBS ${LIBS} mbedtls mbedx509 mbedcrypto)
@@ -131,10 +137,10 @@ if(ANDROID)
 endif()
 
 # see Makefile
-set(ALL_SRCDIRS . base util event protocol cpputil evpp http http/client http/server)
-set(LIBHV_SRCDIRS . base util event)
+set(ALL_SRCDIRS . base event ssl util cpputil evpp protocol http http/client http/server)
+set(LIBHV_SRCDIRS . base ssl event util)
 set(LIBHV_HEADERS hv.h hconfig.h hexport.h)
-set(LIBHV_HEADERS ${LIBHV_HEADERS} ${BASE_HEADERS} ${UTIL_HEADERS} ${EVENT_HEADERS})
+set(LIBHV_HEADERS ${LIBHV_HEADERS} ${BASE_HEADERS} ${SSL_HEADERS} ${EVENT_HEADERS} ${CPPUTIL_HEADERS})
 
 if(WITH_PROTOCOL)
     set(LIBHV_HEADERS ${LIBHV_HEADERS} ${PROTOCOL_HEADERS})

+ 28 - 28
Makefile

@@ -2,11 +2,11 @@ include config.mk
 include Makefile.vars
 
 MAKEF=$(MAKE) -f Makefile.in
-ALL_SRCDIRS=. base util event protocol cpputil evpp http http/client http/server
+ALL_SRCDIRS=. base ssl event util cpputil evpp protocol http http/client http/server
 
-LIBHV_SRCDIRS = . base util event
+LIBHV_SRCDIRS = . base ssl event util
 LIBHV_HEADERS = hv.h hconfig.h hexport.h
-LIBHV_HEADERS += $(BASE_HEADERS) $(UTIL_HEADERS) $(EVENT_HEADERS)
+LIBHV_HEADERS += $(BASE_HEADERS) $(SSL_HEADERS) $(EVENT_HEADERS) $(UTIL_HEADERS)
 
 ifeq ($(WITH_PROTOCOL), yes)
 LIBHV_HEADERS += $(PROTOCOL_HEADERS)
@@ -71,57 +71,57 @@ hmain_test: prepare
 	$(MAKEF) TARGET=$@ SRCDIRS=". base cpputil" SRCS="examples/hmain_test.cpp"
 
 htimer_test: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/htimer_test.c"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event" SRCS="examples/htimer_test.c"
 
 hloop_test: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/hloop_test.c"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event" SRCS="examples/hloop_test.c"
 
 tcp_echo_server: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/tcp_echo_server.c"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event" SRCS="examples/tcp_echo_server.c"
 
 tcp_chat_server: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/tcp_chat_server.c"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event" SRCS="examples/tcp_chat_server.c"
 
 tcp_proxy_server: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/tcp_proxy_server.c"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event" SRCS="examples/tcp_proxy_server.c"
 
 udp_echo_server: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/udp_echo_server.c"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event" SRCS="examples/udp_echo_server.c"
 
 udp_proxy_server: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/udp_proxy_server.c"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event" SRCS="examples/udp_proxy_server.c"
 
 nc: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event" SRCS="examples/nc.c"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event" SRCS="examples/nc.c"
 
 nmap: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event cpputil examples/nmap" DEFINES="PRINT_DEBUG"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event cpputil examples/nmap" DEFINES="PRINT_DEBUG"
 
 httpd: prepare
 	$(RM) examples/httpd/*.o
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event util cpputil evpp http http/client http/server examples/httpd"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event util cpputil evpp http http/client http/server examples/httpd"
 
 consul: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event util cpputil evpp http http/client examples/consul" DEFINES="PRINT_DEBUG"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event util cpputil evpp http http/client examples/consul" DEFINES="PRINT_DEBUG"
 
 curl: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event util cpputil evpp http http/client" SRCS="examples/curl.cpp"
-	# $(MAKEF) TARGET=$@ SRCDIRS=". base event util cpputil evpp http http/client" SRCS="examples/curl.cpp" WITH_CURL=yes
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event util cpputil evpp http http/client" SRCS="examples/curl.cpp"
+	# $(MAKEF) TARGET=$@ SRCDIRS=". base ssl event util cpputil evpp http http/client" SRCS="examples/curl.cpp" WITH_CURL=yes
 
 wget: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event util cpputil evpp http http/client" SRCS="examples/wget.cpp"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event util cpputil evpp http http/client" SRCS="examples/wget.cpp"
 
 http_server_test: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event util cpputil evpp http http/server" SRCS="examples/http_server_test.cpp"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event util cpputil evpp http http/server" SRCS="examples/http_server_test.cpp"
 
 http_client_test: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event util cpputil evpp http http/client" SRCS="examples/http_client_test.cpp"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event util cpputil evpp http http/client" SRCS="examples/http_client_test.cpp"
 
 websocket_server_test: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event util cpputil evpp http http/server" SRCS="examples/websocket_server_test.cpp"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event util cpputil evpp http http/server" SRCS="examples/websocket_server_test.cpp"
 
 websocket_client_test: prepare
-	$(MAKEF) TARGET=$@ SRCDIRS=". base event util cpputil evpp http http/client" SRCS="examples/websocket_client_test.cpp"
+	$(MAKEF) TARGET=$@ SRCDIRS=". base ssl event util cpputil evpp http http/client" SRCS="examples/websocket_client_test.cpp"
 
 unittest: prepare
 	$(CC)  -g -Wall -O0 -std=c99   -I. -Ibase            -o bin/mkdir_p           unittest/mkdir_test.c         base/hbase.c
@@ -146,13 +146,13 @@ unittest: prepare
 	$(CC)  -g -Wall -O0 -std=c99   -I. -Ibase -Iprotocol -Iutil -o bin/sendmail   unittest/sendmail_test.c      protocol/smtp.c base/hsocket.c util/base64.c
 
 evpp: prepare libhv
-	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Ievent -Icpputil -Ievpp -o bin/EventLoop_test           evpp/EventLoop_test.cpp           -Llib -lhv -pthread
-	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Ievent -Icpputil -Ievpp -o bin/EventLoopThread_test     evpp/EventLoopThread_test.cpp     -Llib -lhv -pthread
-	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Ievent -Icpputil -Ievpp -o bin/EventLoopThreadPool_test evpp/EventLoopThreadPool_test.cpp -Llib -lhv -pthread
-	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Ievent -Icpputil -Ievpp -o bin/TcpServer_test           evpp/TcpServer_test.cpp           -Llib -lhv -pthread
-	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Ievent -Icpputil -Ievpp -o bin/TcpClient_test           evpp/TcpClient_test.cpp           -Llib -lhv -pthread
-	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Ievent -Icpputil -Ievpp -o bin/UdpServer_test           evpp/UdpServer_test.cpp           -Llib -lhv -pthread
-	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Ievent -Icpputil -Ievpp -o bin/UdpClient_test           evpp/UdpClient_test.cpp           -Llib -lhv -pthread
+	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/EventLoop_test           evpp/EventLoop_test.cpp           -Llib -lhv -pthread
+	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/EventLoopThread_test     evpp/EventLoopThread_test.cpp     -Llib -lhv -pthread
+	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/EventLoopThreadPool_test evpp/EventLoopThreadPool_test.cpp -Llib -lhv -pthread
+	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/TcpServer_test           evpp/TcpServer_test.cpp           -Llib -lhv -pthread
+	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/TcpClient_test           evpp/TcpClient_test.cpp           -Llib -lhv -pthread
+	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/UdpServer_test           evpp/UdpServer_test.cpp           -Llib -lhv -pthread
+	$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/UdpClient_test           evpp/UdpClient_test.cpp           -Llib -lhv -pthread
 
 # UNIX only
 webbench: prepare

+ 5 - 0
Makefile.in

@@ -167,11 +167,16 @@ ifeq ($(WITH_OPENSSL), yes)
 	CPPFLAGS += -DWITH_OPENSSL
 	LDFLAGS += -lssl -lcrypto
 else
+ifeq ($(WITH_GNUTLS), yes)
+	CPPFLAGS += -DWITH_GNUTLS
+	LDFLAGS += -lgnutls
+else
 ifeq ($(WITH_MBEDTLS), yes)
 	CPPFLAGS += -DWITH_MBEDTLS
 	LDFLAGS += -lmbedtls -lmbedx509 -lmbedcrypto
 endif
 endif
+endif
 
 LDFLAGS += $(addprefix -L, $(LIBDIRS))
 LDFLAGS += $(addprefix -l, $(LIBS))

+ 5 - 3
Makefile.vars

@@ -25,13 +25,15 @@ BASE_HEADERS =  base/hplatform.h\
 				base/hbuf.h\
 				base/hendian.h\
 
-UTIL_HEADERS =  util/base64.h\
-				util/md5.h\
-				util/sha1.h\
+SSL_HEADERS =   ssl/hssl.h
 
 EVENT_HEADERS = event/hloop.h\
 				event/nlog.h\
 
+UTIL_HEADERS =  util/base64.h\
+				util/md5.h\
+				util/sha1.h\
+
 CPPUTIL_HEADERS = cpputil/hmap.h\
 				cpputil/hstring.h\
 				cpputil/hfile.h\

+ 1 - 1
README-CN.md

@@ -24,7 +24,7 @@
 - 跨平台(Linux, Windows, MacOS, Solaris)
 - 高性能事件循环(网络IO事件、定时器事件、空闲事件、自定义事件)
 - TCP/UDP服务端/客户端/代理
-- SSL/TLS加密通信(可选WITH_OPENSSL or WITH_MBEDTLS)
+- SSL/TLS加密通信(可选WITH_OPENSSL、WITH_GNUTLS、WITH_MBEDTLS)
 - HTTP服务端/客户端(支持https http1/x http2 grpc)
 - HTTP支持静态文件服务、目录服务、同步/异步API处理函数
 - HTTP支持RESTful风格、URI路由、keep-alive长连接、chunked分块等特性

+ 1 - 1
README.md

@@ -26,7 +26,7 @@ but simpler api and richer protocols.
 - Cross-platform (Linux, Windows, MacOS, Solaris)
 - EventLoop (IO, timer, idle, custom)
 - TCP/UDP client/server/proxy
-- SSL/TLS support: (via WITH_OPENSSL or WITH_MBEDTLS)
+- SSL/TLS support: (via WITH_OPENSSL or WITH_GNUTLS or WITH_MBEDTLS)
 - HTTP client/server (support https http1/x http2 grpc)
 - HTTP static file service, indexof service, sync/async API handler
 - HTTP supports RESTful, URI router, keep-alive, chunked, etc.

+ 1 - 0
TREE.md

@@ -28,6 +28,7 @@
 ├── misc        杂项
 ├── protocol    包含icmp、dns、ftp、smtp等协议的实现
 ├── scripts     shell脚本存放目录
+├── ssl         SSL/TLS加密通信
 ├── unittest    单元测试代码
 └── util        libhv工具函数,如base64、md5、sha1
 

+ 0 - 1
base/README.md

@@ -16,7 +16,6 @@
 ├── hplatform.h     平台相关宏
 ├── hproc.h         进程
 ├── hsocket.h       套接字
-├── hssl.h          SSL/TLS
 ├── hsysinfo.h      系统信息
 ├── hthread.h       线程
 ├── htime.h         时间

+ 8 - 5
cmake/vars.cmake

@@ -14,16 +14,13 @@ set(BASE_HEADERS
     base/hthread.h
     base/hmutex.h
     base/hsocket.h
-    base/hssl.h
     base/hlog.h
     base/hbuf.h
     base/hendian.h
 )
 
-set(UTIL_HEADERS
-    util/base64.h
-    util/md5.h
-    util/sha1.h
+set(SSL_HEADERS
+    ssl/hssl.h
 )
 
 set(EVENT_HEADERS
@@ -31,6 +28,12 @@ set(EVENT_HEADERS
     event/nlog.h
 )
 
+set(UTIL_HEADERS
+    util/base64.h
+    util/md5.h
+    util/sha1.h
+)
+
 set(CPPUTIL_HEADERS
     cpputil/hmap.h
     cpputil/hstring.h

+ 1 - 0
config.ini

@@ -31,4 +31,5 @@ WITH_CURL=no
 WITH_NGHTTP2=no
 # for SSL/TLS
 WITH_OPENSSL=no
+WITH_GNUTLS=no
 WITH_MBEDTLS=no

+ 2 - 1
config.mk

@@ -14,5 +14,6 @@ USE_MULTIMAP=no
 WITH_CURL=no
 WITH_NGHTTP2=no
 WITH_OPENSSL=no
+WITH_GNUTLS=no
 WITH_MBEDTLS=no
-CONFIG_DATE=20210430
+CONFIG_DATE=20210817

+ 4 - 0
configure

@@ -33,6 +33,7 @@ dependencies:
   --with-curl           compile with curl?              (DEFAULT: $WITH_CURL)
   --with-nghttp2        compile with nghttp2?           (DEFAULT: $WITH_NGHTTP2)
   --with-openssl        compile with openssl?           (DEFAULT: $WITH_OPENSSL)
+  --with-gnutls         compile with gnutls?            (DEFAULT: $WITH_GNUTLS)
   --with-mbedtls        compile with mbedtls?           (DEFAULT: $WITH_MBEDTLS)
 
 END
@@ -244,6 +245,9 @@ function=sem_timedwait && header=semaphore.h && check_function
 
 # Checks for options
 source config.mk 2>/dev/null
+option=WITH_OPENSSL && check_option
+option=WITH_GNUTLS && check_option
+option=WITH_MBEDTLS && check_option
 option=ENABLE_UDS && check_option
 option=USE_MULTIMAP && check_option
 

+ 1 - 1
evpp/TcpClient.h

@@ -160,7 +160,7 @@ public:
             memset(&param, 0, sizeof(param));
             param.crt_file = cert_file;
             param.key_file = key_file;
-            param.endpoint = 1;
+            param.endpoint = HSSL_CLIENT;
             return hssl_ctx_init(&param) == NULL ? -1 : 0;
         }
         return 0;

+ 1 - 1
evpp/TcpServer.h

@@ -62,7 +62,7 @@ public:
             memset(&param, 0, sizeof(param));
             param.crt_file = cert_file;
             param.key_file = key_file;
-            param.endpoint = 0;
+            param.endpoint = HSSL_SERVER;
             return hssl_ctx_init(&param) == NULL ? -1 : 0;
         }
         return 0;

+ 1 - 1
examples/CMakeLists.txt

@@ -9,7 +9,7 @@ list(APPEND EXAMPLES
     udp_proxy_server
 )
 
-include_directories(.. ../base ../util ../event)
+include_directories(.. ../base ../ssl ../event ../util)
 
 add_executable(hloop_test hloop_test.c)
 target_link_libraries(hloop_test hv)

+ 2 - 0
examples/httpd/httpd.cpp

@@ -1,4 +1,5 @@
 #include "hv.h"
+#include "hssl.h"
 #include "hmain.h"
 #include "iniparser.h"
 
@@ -152,6 +153,7 @@ int parse_confile(const char* confile) {
         std::string crt_file = ini.GetValue("ssl_certificate");
         std::string key_file = ini.GetValue("ssl_privatekey");
         std::string ca_file = ini.GetValue("ssl_ca_certificate");
+        hlogi("SSL backend is %s", hssl_backend());
         hssl_ctx_init_param_t param;
         memset(&param, 0, sizeof(param));
         param.crt_file = crt_file.c_str();

+ 3 - 0
hconfig.h

@@ -65,6 +65,9 @@
 #define HAVE_SEM_TIMEDWAIT 0
 #endif
 
+/* #undef WITH_OPENSSL */
+/* #undef WITH_GNUTLS */
+/* #undef WITH_MBEDTLS */
 /* #undef ENABLE_UDS */
 /* #undef USE_MULTIMAP */
 

+ 4 - 0
hconfig.h.in

@@ -65,6 +65,10 @@
 #define HAVE_SEM_TIMEDWAIT @HAVE_SEM_TIMEDWAIT@
 #endif
 
+#cmakedefine WITH_OPENSSL   1
+#cmakedefine WITH_GNUTLS    1
+#cmakedefine WITH_MBEDTLS   1
+
 #cmakedefine ENABLE_UDS     1
 #cmakedefine USE_MULTIMAP   1
 

+ 1 - 0
http/server/HttpServer.cpp

@@ -1,6 +1,7 @@
 #include "HttpServer.h"
 
 #include "hv.h"
+#include "hssl.h"
 #include "hmain.h"
 
 #include "httpdef.h"

+ 0 - 1
hv.h

@@ -24,7 +24,6 @@
 #include "hthread.h"
 #include "hmutex.h"
 #include "hsocket.h"
-#include "hssl.h"
 
 #include "hlog.h"
 #include "hbuf.h"

+ 3 - 1
scripts/shini.sh

@@ -295,7 +295,9 @@ shini_write()
 # default usage
 __shini_parsed()
 {
-    eval $2=$3
+    if [[ $2 != *\$* ]] && [[ $3 != *\$* ]]; then
+        eval $2=$3
+    fi
 }
 
 __shini_parse_error()

+ 50 - 0
ssl/appletls.c

@@ -0,0 +1,50 @@
+#include "hssl.h"
+
+#ifdef WITH_APPLETLS
+
+const char* hssl_backend() {
+    return "appletls";
+}
+
+hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
+    fprintf(stderr, "Please recompile WITH_SSL.\n");
+    return NULL;
+}
+
+void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx) {
+}
+
+hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
+    return (void*)(intptr_t)fd;
+}
+
+void hssl_free(hssl_t ssl) {
+}
+
+int hssl_accept(hssl_t ssl) {
+    return 0;
+}
+
+int hssl_connect(hssl_t ssl) {
+    return 0;
+}
+
+int hssl_read(hssl_t ssl, void* buf, int len) {
+    int fd = (intptr_t)ssl;
+    return read(fd, buf, len);
+}
+
+int hssl_write(hssl_t ssl, const void* buf, int len) {
+    int fd = (intptr_t)ssl;
+    return write(fd, buf, len);
+}
+
+int hssl_close(hssl_t ssl) {
+    return 0;
+}
+
+int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
+    return 0;
+}
+
+#endif // WITH_APPLETLS

+ 190 - 0
ssl/gnutls.c

@@ -0,0 +1,190 @@
+#include "hssl.h"
+
+#ifdef WITH_GNUTLS
+
+#include "gnutls/gnutls.h"
+
+const char* hssl_backend() {
+    return "gnutls";
+}
+
+typedef gnutls_certificate_credentials_t gnutls_ctx_t;
+
+hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
+    static int s_initialized = 0;
+    if (s_initialized == 0) {
+        gnutls_global_init();
+        s_initialized = 1;
+    }
+
+    gnutls_ctx_t ctx;
+    const char* crt_file = NULL;
+    const char* key_file = NULL;
+    const char* ca_file = NULL;
+
+    int ret = gnutls_certificate_allocate_credentials(&ctx);
+    if (ret != GNUTLS_E_SUCCESS) {
+        return NULL;
+    }
+
+    if (param) {
+        if (param->crt_file && *param->crt_file) {
+            crt_file = param->crt_file;
+        }
+        if (param->key_file && *param->key_file) {
+            key_file = param->key_file;
+        }
+        if (param->ca_file && *param->ca_file) {
+            ca_file = param->ca_file;
+        }
+
+        if (ca_file) {
+            ret = gnutls_certificate_set_x509_trust_file(ctx, ca_file, GNUTLS_X509_FMT_PEM);
+            if (ret < 0) {
+                fprintf(stderr, "ssl ca_file failed!\n");
+                goto error;
+            }
+        }
+
+        if (crt_file && key_file) {
+            ret = gnutls_certificate_set_x509_key_file(ctx, crt_file, key_file, GNUTLS_X509_FMT_PEM);
+            if (ret != GNUTLS_E_SUCCESS) {
+                fprintf(stderr, "ssl crt_file/key_file error!\n");
+                goto error;
+            }
+        }
+
+        if (param->verify_peer && !ca_file) {
+            gnutls_certificate_set_x509_system_trust(ctx);
+        }
+    }
+
+    g_ssl_ctx = ctx;
+    return ctx;
+error:
+    gnutls_certificate_free_credentials(ctx);
+    return NULL;
+}
+
+void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx) {
+    if (!ssl_ctx) return;
+    if (g_ssl_ctx == ssl_ctx) {
+        g_ssl_ctx = NULL;
+    }
+    gnutls_ctx_t ctx = (gnutls_ctx_t)ssl_ctx;
+    gnutls_certificate_free_credentials(ctx);
+}
+
+typedef struct gnutls_s {
+    gnutls_session_t session;
+    gnutls_ctx_t     ctx;
+    int              fd;
+} gnutls_t;
+
+hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
+    gnutls_t* gnutls = (gnutls_t*)malloc(sizeof(gnutls_t));
+    if (gnutls == NULL) return NULL;
+    gnutls->session = NULL;
+    gnutls->ctx = (gnutls_ctx_t)ssl_ctx;
+    gnutls->fd = fd;
+    return (hssl_t)gnutls;
+}
+
+static int hssl_init(hssl_t ssl, int endpoint) {
+    if (ssl == NULL) return HSSL_ERROR;
+    gnutls_t* gnutls = (gnutls_t*)ssl;
+    if (gnutls->session == NULL) {
+        gnutls_init(&gnutls->session, endpoint);
+        gnutls_priority_set_direct(gnutls->session, "NORMAL", NULL);
+        gnutls_credentials_set(gnutls->session, GNUTLS_CRD_CERTIFICATE, gnutls->ctx);
+        gnutls_transport_set_ptr(gnutls->session, (gnutls_transport_ptr_t)(ptrdiff_t)gnutls->fd);
+    }
+    return HSSL_OK;
+}
+
+void hssl_free(hssl_t ssl) {
+    if (ssl == NULL) return;
+    gnutls_t* gnutls = (gnutls_t*)ssl;
+    if (gnutls->session) {
+        gnutls_deinit(gnutls->session);
+        gnutls->session = NULL;
+    }
+    free(gnutls);
+}
+
+static int hssl_handshake(hssl_t ssl) {
+    if (ssl == NULL) return HSSL_ERROR;
+    gnutls_t* gnutls = (gnutls_t*)ssl;
+    if (gnutls->session == NULL) return HSSL_ERROR;
+    int ret = 0;
+    while (1) {
+        ret = gnutls_handshake(gnutls->session);
+        if (ret == GNUTLS_E_SUCCESS) {
+            return HSSL_OK;
+        }
+        else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
+            return gnutls_record_get_direction(gnutls->session) == 0 ? HSSL_WANT_READ : HSSL_WANT_WRITE;
+        }
+        else if (gnutls_error_is_fatal(ret)) {
+            // fprintf(stderr, "gnutls_handshake failed: %s\n", gnutls_strerror(ret));
+            return HSSL_ERROR;
+        }
+    }
+    return HSSL_OK;
+}
+
+int hssl_accept(hssl_t ssl) {
+    if (ssl == NULL) return HSSL_ERROR;
+    gnutls_t* gnutls = (gnutls_t*)ssl;
+    if (gnutls->session == NULL) {
+        hssl_init(ssl, GNUTLS_SERVER);
+    }
+    return hssl_handshake(ssl);
+}
+
+int hssl_connect(hssl_t ssl) {
+    if (ssl == NULL) return HSSL_ERROR;
+    gnutls_t* gnutls = (gnutls_t*)ssl;
+    if (gnutls->session == NULL) {
+        hssl_init(ssl, GNUTLS_CLIENT);
+    }
+    return hssl_handshake(ssl);
+}
+
+int hssl_read(hssl_t ssl, void* buf, int len) {
+    if (ssl == NULL) return HSSL_ERROR;
+    gnutls_t* gnutls = (gnutls_t*)ssl;
+    if (gnutls->session == NULL) return HSSL_ERROR;
+    int ret = 0;
+    while ((ret = gnutls_record_recv(gnutls->session, buf, len)) == GNUTLS_E_INTERRUPTED);
+    return ret;
+}
+
+int hssl_write(hssl_t ssl, const void* buf, int len) {
+    if (ssl == NULL) return HSSL_ERROR;
+    gnutls_t* gnutls = (gnutls_t*)ssl;
+    if (gnutls->session == NULL) return HSSL_ERROR;
+    int ret = 0;
+    while ((ret = gnutls_record_send(gnutls->session, buf, len)) == GNUTLS_E_INTERRUPTED);
+    return ret;
+}
+
+int hssl_close(hssl_t ssl) {
+    if (ssl == NULL) return HSSL_ERROR;
+    gnutls_t* gnutls = (gnutls_t*)ssl;
+    if (gnutls->session == NULL) return HSSL_ERROR;
+    gnutls_bye(gnutls->session, GNUTLS_SHUT_RDWR);
+    return HSSL_OK;
+}
+
+int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
+    if (ssl == NULL) return HSSL_ERROR;
+    gnutls_t* gnutls = (gnutls_t*)ssl;
+    if (gnutls->session == NULL) {
+        hssl_init(ssl, GNUTLS_SERVER);
+    }
+    gnutls_server_name_set(gnutls->session, GNUTLS_NAME_DNS, hostname, strlen(hostname));
+    return 0;
+}
+
+#endif // WITH_GNUTLS

+ 10 - 0
ssl/hssl.c

@@ -0,0 +1,10 @@
+#include "hssl.h"
+
+hssl_ctx_t g_ssl_ctx = NULL;
+
+hssl_ctx_t hssl_ctx_instance() {
+    if (g_ssl_ctx == NULL) {
+        g_ssl_ctx = hssl_ctx_init(NULL);
+    }
+    return g_ssl_ctx;
+}

+ 29 - 5
base/hssl.h → ssl/hssl.h

@@ -3,11 +3,30 @@
 
 #include "hexport.h"
 
-typedef void* hssl_ctx_t; ///> SSL_CTX
-typedef void* hssl_t; ///> SSL
+#include "hplatform.h"
+#if !defined(WITH_OPENSSL) &&   \
+    !defined(WITH_GNUTLS)  &&   \
+    !defined(WITH_MBEDTLS)
+#if OS_WIN
+#define WITH_WINTLS
+#elif defined(OS_DARWIN)
+#define WITH_APPLETLS
+#else
+#define HV_WITHOUT_SSL
+#endif
+#endif
+
+typedef void* hssl_ctx_t;   ///> SSL_CTX
+typedef void* hssl_t;       ///> SSL
+
+enum {
+    HSSL_SERVER = 0,
+    HSSL_CLIENT = 1,
+};
 
 enum {
     HSSL_OK = 0,
+    HSSL_ERROR = -1,
     HSSL_WANT_READ = -2,
     HSSL_WANT_WRITE = -3,
 };
@@ -18,7 +37,7 @@ typedef struct {
     const char* ca_file;
     const char* ca_path;
     short       verify_peer;
-    short       endpoint; // 0: server 1: client
+    short       endpoint; // HSSL_SERVER / HSSL_CLIENT
 } hssl_ctx_init_param_t;
 
 BEGIN_EXTERN_C
@@ -27,16 +46,19 @@ BEGIN_EXTERN_C
 const char* hssl_backend() {
 #ifdef WITH_OPENSSL
     return "openssl";
+#elif defined(WITH_GNUTLS)
+    return "gnutls";
 #elif defined(WITH_MBEDTLS)
     return "mbedtls";
 #else
-    return "null";
+    return "nossl";
 #endif
 }
 */
 HV_EXPORT const char* hssl_backend();
-#define HV_WITH_SSL (strcmp(hssl_backend(), "null") != 0)
+#define HV_WITH_SSL (strcmp(hssl_backend(), "nossl") != 0)
 
+HV_EXPORT extern hssl_ctx_t g_ssl_ctx;
 HV_EXPORT hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param);
 HV_EXPORT void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx);
 HV_EXPORT hssl_ctx_t hssl_ctx_instance();
@@ -50,6 +72,8 @@ HV_EXPORT int hssl_read(hssl_t ssl, void* buf, int len);
 HV_EXPORT int hssl_write(hssl_t ssl, const void* buf, int len);
 HV_EXPORT int hssl_close(hssl_t ssl);
 
+HV_EXPORT int hssl_set_sni_hostname(hssl_t ssl, const char* hostname);
+
 END_EXTERN_C
 
 #endif // HV_SSL_H_

+ 11 - 205
base/hssl.c → ssl/mbedtls.c

@@ -1,170 +1,6 @@
 #include "hssl.h"
 
-#include "hplatform.h"
-
-static hssl_ctx_t s_ssl_ctx = NULL;
-
-const char* hssl_backend() {
-#ifdef WITH_OPENSSL
-    return "openssl";
-#elif defined(WITH_MBEDTLS)
-    return "mbedtls";
-#else
-    return "null";
-#endif
-}
-
-hssl_ctx_t hssl_ctx_instance() {
-    if (s_ssl_ctx == NULL) {
-        s_ssl_ctx = hssl_ctx_init(NULL);
-    }
-    return s_ssl_ctx;
-}
-
-#ifdef WITH_OPENSSL
-
-#include "openssl/ssl.h"
-#include "openssl/err.h"
-#ifdef _MSC_VER
-//#pragma comment(lib, "libssl.a")
-//#pragma comment(lib, "libcrypto.a")
-#endif
-
-hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
-    static int s_initialized = 0;
-    if (s_initialized == 0) {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-        SSL_library_init();
-        SSL_load_error_strings();
-#else
-        OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, NULL);
-#endif
-        s_initialized = 1;
-    }
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-    SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
-#else
-    SSL_CTX* ctx = SSL_CTX_new(TLS_method());
-#endif
-    if (ctx == NULL) return NULL;
-    int mode = SSL_VERIFY_NONE;
-    const char* ca_file = NULL;
-    const char* ca_path = NULL;
-    if (param) {
-        if (param->ca_file && *param->ca_file) {
-            ca_file = param->ca_file;
-        }
-        if (param->ca_path && *param->ca_path) {
-            ca_path = param->ca_path;
-        }
-        if (ca_file || ca_path) {
-            if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) {
-                fprintf(stderr, "ssl ca_file/ca_path failed!\n");
-                goto error;
-            }
-        }
-
-        if (param->crt_file && *param->crt_file) {
-            if (!SSL_CTX_use_certificate_file(ctx, param->crt_file, SSL_FILETYPE_PEM)) {
-                fprintf(stderr, "ssl crt_file error!\n");
-                goto error;
-            }
-        }
-
-        if (param->key_file && *param->key_file) {
-            if (!SSL_CTX_use_PrivateKey_file(ctx, param->key_file, SSL_FILETYPE_PEM)) {
-                fprintf(stderr, "ssl key_file error!\n");
-                goto error;
-            }
-            if (!SSL_CTX_check_private_key(ctx)) {
-                fprintf(stderr, "ssl key_file check failed!\n");
-                goto error;
-            }
-        }
-
-        if (param->verify_peer) {
-            mode = SSL_VERIFY_PEER;
-        }
-    }
-    if (mode == SSL_VERIFY_PEER && !ca_file && !ca_path) {
-        SSL_CTX_set_default_verify_paths(ctx);
-    }
-    SSL_CTX_set_verify(ctx, mode, NULL);
-    s_ssl_ctx = ctx;
-    return ctx;
-error:
-    SSL_CTX_free(ctx);
-    return NULL;
-}
-
-void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx) {
-    if (ssl_ctx) {
-        if (ssl_ctx == s_ssl_ctx) {
-            s_ssl_ctx = NULL;
-        }
-        SSL_CTX_free((SSL_CTX*)ssl_ctx);
-        ssl_ctx = NULL;
-    }
-}
-
-hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
-    SSL* ssl = SSL_new((SSL_CTX*)ssl_ctx);
-    if (ssl == NULL) return NULL;
-    SSL_set_fd(ssl, fd);
-    return ssl;
-}
-
-void hssl_free(hssl_t ssl) {
-    if (ssl) {
-        SSL_free((SSL*)ssl);
-        ssl = NULL;
-    }
-}
-
-int hssl_accept(hssl_t ssl) {
-    int ret = SSL_accept((SSL*)ssl);
-    if (ret == 1) return 0;
-
-    int err = SSL_get_error((SSL*)ssl, ret);
-    if (err == SSL_ERROR_WANT_READ) {
-        return HSSL_WANT_READ;
-    }
-    else if (err == SSL_ERROR_WANT_WRITE) {
-        return HSSL_WANT_WRITE;
-    }
-    return err;
-}
-
-int hssl_connect(hssl_t ssl) {
-    int ret = SSL_connect((SSL*)ssl);
-    if (ret == 1) return 0;
-
-    int err = SSL_get_error((SSL*)ssl, ret);
-    if (err == SSL_ERROR_WANT_READ) {
-        return HSSL_WANT_READ;
-    }
-    else if (err == SSL_ERROR_WANT_WRITE) {
-        return HSSL_WANT_WRITE;
-    }
-    return err;
-}
-
-int hssl_read(hssl_t ssl, void* buf, int len) {
-    return SSL_read((SSL*)ssl, buf, len);
-}
-
-int hssl_write(hssl_t ssl, const void* buf, int len) {
-    return SSL_write((SSL*)ssl, buf, len);
-}
-
-int hssl_close(hssl_t ssl) {
-    SSL_shutdown((SSL*)ssl);
-    return 0;
-}
-
-#elif defined(WITH_MBEDTLS)
-
+#ifdef WITH_MBEDTLS
 
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
@@ -185,6 +21,10 @@ int hssl_close(hssl_t ssl) {
 //#pragma comment(lib, "libmbedcrypto.a")
 #endif
 
+const char* hssl_backend() {
+    return "mbedtls";
+}
+
 struct mbedtls_ctx {
     mbedtls_entropy_context     entropy;
     mbedtls_ctr_drbg_context    ctr_drbg;
@@ -229,7 +69,7 @@ hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
         if (param->verify_peer) {
             mode = MBEDTLS_SSL_VERIFY_REQUIRED;
         }
-        if (param->endpoint == 0) {
+        if (param->endpoint == HSSL_SERVER) {
             endpoint = MBEDTLS_SSL_IS_SERVER;
         }
     }
@@ -254,7 +94,7 @@ hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
         }
     }
 
-    s_ssl_ctx = ctx;
+    g_ssl_ctx = ctx;
     return ctx;
 error:
     free(ctx);
@@ -263,8 +103,8 @@ error:
 
 void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx) {
     if (!ssl_ctx) return;
-    if (ssl_ctx == s_ssl_ctx) {
-        s_ssl_ctx = NULL;
+    if (g_ssl_ctx == ssl_ctx) {
+        g_ssl_ctx = NULL;
     }
     struct mbedtls_ctx *mctx = (struct mbedtls_ctx *)ssl_ctx;
     mbedtls_x509_crt_free(&mctx->cert);
@@ -342,42 +182,8 @@ int hssl_close(hssl_t ssl) {
     return 0;
 }
 
-#else
-
-hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
-    fprintf(stderr, "Please recompile WITH_SSL.\n");
-    return NULL;
-}
-
-void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx) {
-}
-
-hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
-    return (void*)(intptr_t)fd;
-}
-
-void hssl_free(hssl_t ssl) {
-}
-
-int hssl_accept(hssl_t ssl) {
-    return 0;
-}
-
-int hssl_connect(hssl_t ssl) {
+int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
     return 0;
 }
 
-int hssl_read(hssl_t ssl, void* buf, int len) {
-    int fd = (intptr_t)ssl;
-    return read(fd, buf, len);
-}
-
-int hssl_write(hssl_t ssl, const void* buf, int len) {
-    int fd = (intptr_t)ssl;
-    return write(fd, buf, len);
-}
-
-int hssl_close(hssl_t ssl) {
-    return 0;
-}
-#endif
+#endif // WITH_MBEDTLS

+ 50 - 0
ssl/nossl.c

@@ -0,0 +1,50 @@
+#include "hssl.h"
+
+#ifdef HV_WITHOUT_SSL
+
+const char* hssl_backend() {
+    return "nossl";
+}
+
+hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
+    fprintf(stderr, "Please recompile WITH_SSL.\n");
+    return NULL;
+}
+
+void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx) {
+}
+
+hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
+    return (void*)(intptr_t)fd;
+}
+
+void hssl_free(hssl_t ssl) {
+}
+
+int hssl_accept(hssl_t ssl) {
+    return 0;
+}
+
+int hssl_connect(hssl_t ssl) {
+    return 0;
+}
+
+int hssl_read(hssl_t ssl, void* buf, int len) {
+    int fd = (intptr_t)ssl;
+    return read(fd, buf, len);
+}
+
+int hssl_write(hssl_t ssl, const void* buf, int len) {
+    int fd = (intptr_t)ssl;
+    return write(fd, buf, len);
+}
+
+int hssl_close(hssl_t ssl) {
+    return 0;
+}
+
+int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
+    return 0;
+}
+
+#endif // HV_WITHOUT_SSL

+ 155 - 0
ssl/openssl.c

@@ -0,0 +1,155 @@
+#include "hssl.h"
+
+#ifdef WITH_OPENSSL
+
+#include "openssl/ssl.h"
+#include "openssl/err.h"
+#ifdef _MSC_VER
+//#pragma comment(lib, "libssl.a")
+//#pragma comment(lib, "libcrypto.a")
+#endif
+
+const char* hssl_backend() {
+    return "openssl";
+}
+
+hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
+    static int s_initialized = 0;
+    if (s_initialized == 0) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+        SSL_library_init();
+        SSL_load_error_strings();
+#else
+        OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, NULL);
+#endif
+        s_initialized = 1;
+    }
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+    SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
+#else
+    SSL_CTX* ctx = SSL_CTX_new(TLS_method());
+#endif
+    if (ctx == NULL) return NULL;
+    int mode = SSL_VERIFY_NONE;
+    const char* ca_file = NULL;
+    const char* ca_path = NULL;
+    if (param) {
+        if (param->ca_file && *param->ca_file) {
+            ca_file = param->ca_file;
+        }
+        if (param->ca_path && *param->ca_path) {
+            ca_path = param->ca_path;
+        }
+        if (ca_file || ca_path) {
+            if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) {
+                fprintf(stderr, "ssl ca_file/ca_path failed!\n");
+                goto error;
+            }
+        }
+
+        if (param->crt_file && *param->crt_file) {
+            if (!SSL_CTX_use_certificate_file(ctx, param->crt_file, SSL_FILETYPE_PEM)) {
+                fprintf(stderr, "ssl crt_file error!\n");
+                goto error;
+            }
+        }
+
+        if (param->key_file && *param->key_file) {
+            if (!SSL_CTX_use_PrivateKey_file(ctx, param->key_file, SSL_FILETYPE_PEM)) {
+                fprintf(stderr, "ssl key_file error!\n");
+                goto error;
+            }
+            if (!SSL_CTX_check_private_key(ctx)) {
+                fprintf(stderr, "ssl key_file check failed!\n");
+                goto error;
+            }
+        }
+
+        if (param->verify_peer) {
+            mode = SSL_VERIFY_PEER;
+        }
+    }
+    if (mode == SSL_VERIFY_PEER && !ca_file && !ca_path) {
+        SSL_CTX_set_default_verify_paths(ctx);
+    }
+    SSL_CTX_set_verify(ctx, mode, NULL);
+
+    g_ssl_ctx = ctx;
+    return ctx;
+error:
+    SSL_CTX_free(ctx);
+    return NULL;
+}
+
+void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx) {
+    if (!ssl_ctx) return;
+    if (g_ssl_ctx == ssl_ctx) {
+        g_ssl_ctx = NULL;
+    }
+    SSL_CTX_free((SSL_CTX*)ssl_ctx);
+}
+
+hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
+    SSL* ssl = SSL_new((SSL_CTX*)ssl_ctx);
+    if (ssl == NULL) return NULL;
+    SSL_set_fd(ssl, fd);
+    return ssl;
+}
+
+void hssl_free(hssl_t ssl) {
+    if (ssl) {
+        SSL_free((SSL*)ssl);
+        ssl = NULL;
+    }
+}
+
+int hssl_accept(hssl_t ssl) {
+    int ret = SSL_accept((SSL*)ssl);
+    if (ret == 1) return 0;
+
+    int err = SSL_get_error((SSL*)ssl, ret);
+    if (err == SSL_ERROR_WANT_READ) {
+        return HSSL_WANT_READ;
+    }
+    else if (err == SSL_ERROR_WANT_WRITE) {
+        return HSSL_WANT_WRITE;
+    }
+    return err;
+}
+
+int hssl_connect(hssl_t ssl) {
+    int ret = SSL_connect((SSL*)ssl);
+    if (ret == 1) return 0;
+
+    int err = SSL_get_error((SSL*)ssl, ret);
+    if (err == SSL_ERROR_WANT_READ) {
+        return HSSL_WANT_READ;
+    }
+    else if (err == SSL_ERROR_WANT_WRITE) {
+        return HSSL_WANT_WRITE;
+    }
+    return err;
+}
+
+int hssl_read(hssl_t ssl, void* buf, int len) {
+    return SSL_read((SSL*)ssl, buf, len);
+}
+
+int hssl_write(hssl_t ssl, const void* buf, int len) {
+    return SSL_write((SSL*)ssl, buf, len);
+}
+
+int hssl_close(hssl_t ssl) {
+    SSL_shutdown((SSL*)ssl);
+    return 0;
+}
+
+int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+    SSL_set_tlsext_host_name((SSL*)ssl, hostname);
+#endif
+    return 0;
+}
+
+#endif // WITH_OPENSSL

+ 50 - 0
ssl/wintls.c

@@ -0,0 +1,50 @@
+#include "hssl.h"
+
+#ifdef WITH_WINTLS
+
+const char* hssl_backend() {
+    return "wintls";
+}
+
+hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
+    fprintf(stderr, "Please recompile WITH_SSL.\n");
+    return NULL;
+}
+
+void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx) {
+}
+
+hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
+    return (void*)(intptr_t)fd;
+}
+
+void hssl_free(hssl_t ssl) {
+}
+
+int hssl_accept(hssl_t ssl) {
+    return 0;
+}
+
+int hssl_connect(hssl_t ssl) {
+    return 0;
+}
+
+int hssl_read(hssl_t ssl, void* buf, int len) {
+    int fd = (intptr_t)ssl;
+    return read(fd, buf, len);
+}
+
+int hssl_write(hssl_t ssl, const void* buf, int len) {
+    int fd = (intptr_t)ssl;
+    return write(fd, buf, len);
+}
+
+int hssl_close(hssl_t ssl) {
+    return 0;
+}
+
+int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
+    return 0;
+}
+
+#endif // WITH_WINTLS