From 25198a94092112724094a077cbacb1df739e5116 Mon Sep 17 00:00:00 2001 From: SisMaker <1713699517@qq.com> Date: Tue, 11 Jan 2022 15:05:46 +0800 Subject: [PATCH] =?UTF-8?q?ft:=20Ssl=E7=9B=B8=E5=85=B3=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/eNet.hrl | 18 +++-- priv/demo.crt | 17 +++++ priv/demo.key | 15 ++++ src/eNet.erl | 8 +- src/misc/ntCom.erl | 4 + src/ssl/doToSsl.md | 1 - src/ssl/ntSslAcceptor.erl | 144 +++++++++++++++++++++++++++++++++++ src/ssl/ntSslAcceptorSup.erl | 29 +++++++ src/ssl/ntSslListener.erl | 143 ++++++++++++++++++++++++++++++++++ src/ssl/ntSslMgrSup.erl | 57 ++++++++++++++ src/test/utSslANSrv.erl | 82 ++++++++++++++++++++ src/test/utSslCli.erl | 40 ++++++++++ src/test/utTcpAFSrv.erl | 39 +++++----- src/test/utTcpCli.erl | 2 +- 14 files changed, 569 insertions(+), 30 deletions(-) create mode 100644 priv/demo.crt create mode 100644 priv/demo.key delete mode 100644 src/ssl/doToSsl.md create mode 100644 src/ssl/ntSslAcceptor.erl create mode 100644 src/ssl/ntSslAcceptorSup.erl create mode 100644 src/ssl/ntSslListener.erl create mode 100644 src/ssl/ntSslMgrSup.erl create mode 100644 src/test/utSslANSrv.erl create mode 100644 src/test/utSslCli.erl diff --git a/include/eNet.hrl b/include/eNet.hrl index 3484889..2609744 100644 --- a/include/eNet.hrl +++ b/include/eNet.hrl @@ -2,9 +2,10 @@ -define(nlSslMgrSup, nlSslMgrSup). -define(nlUdpMgrSup, nlUdpMgrSup). +%% gen_tcp ready maybe to set sock options +%% %% ssl ready and then need do ntSslAcceptor:handshake/3 and maybe to set other options -define(mSockReady, mSockReady). - -define(TCP_DEFAULT_OPTIONS, [ binary , {packet, 4} @@ -14,7 +15,8 @@ , {delay_send, true} , {send_timeout, 15000} , {keepalive, true} - , {exit_on_close, true}]). + , {exit_on_close, true} +]). -define(ACCEPTOR_POOL, 16). @@ -24,11 +26,13 @@ -define(PROXY_RECV_TIMEOUT, 5000). -type listenOpt() :: -{aptCnt, non_neg_integer()} | -{conMod, atom()} | -{tcpOpts, [gen_tcp:listen_option()]} | -{sslOpts, [ssl:ssl_option()]} | -{udpOpts, [gen_udp:option()]}. + {aptCnt, non_neg_integer()} | + {conMod, atom()} | + {tcpOpts, [gen_tcp:listen_option()]} | + {sslOpts, [ssl:ssl_option()]} | + {udpOpts, [gen_udp:option()]}. + +-export_type([listenOpt/0]). %% 令牌桶相关定义 -record(tokenBucket, { diff --git a/priv/demo.crt b/priv/demo.crt new file mode 100644 index 0000000..0018446 --- /dev/null +++ b/priv/demo.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICuTCCAiICCQC8+3PPaqATfDANBgkqhkiG9w0BAQUFADCBoDELMAkGA1UEBhMC +Q0gxETAPBgNVBAgTCFpoZUppYW5nMREwDwYDVQQHEwhIYW5nWmhvdTEUMBIGA1UE +ChMLWGlhb0xpIFRlY2gxHzAdBgNVBAsTFkluZm9ybWF0aW9uIFRlY2hub2xvZ3kx +EzARBgNVBAMTCnQuZW1xdHQuaW8xHzAdBgkqhkiG9w0BCQEWEGZlbmcgYXQgZW1x +dHQuaW8wHhcNMTUwMjI1MTc0NjQwWhcNMTYwMjI1MTc0NjQwWjCBoDELMAkGA1UE +BhMCQ0gxETAPBgNVBAgTCFpoZUppYW5nMREwDwYDVQQHEwhIYW5nWmhvdTEUMBIG +A1UEChMLWGlhb0xpIFRlY2gxHzAdBgNVBAsTFkluZm9ybWF0aW9uIFRlY2hub2xv +Z3kxEzARBgNVBAMTCnQuZW1xdHQuaW8xHzAdBgkqhkiG9w0BCQEWEGZlbmcgYXQg +ZW1xdHQuaW8wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALAtN2OHsvltOk+9 +AtlwMtKuaWW2WpV/S0lRRG9x9k8pyd5PJeeYAr2jVsoWnZInb1CoEOHFcwxZLjv3 +gEvz+X+//W02YyI9hnvCJUpT/+6P0gJEbmTmqL078M6vbtwtiF1YC7mdo0nGAZuK +qedpIoEZbVJavf4S0vXWTsb3s5unAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAgUR3 +z4uDUsAl+xUorPMBIOS/ncHHVk1XucVv9Wi4chzzZ+4/Y77/fFqP6oxhQ59C9Q8i +iT5wjaE4R1eCge18lPSw3yb1tsTe5B3WkRTzziPq/Q/AsC+DifkkE1YW67leuJV/ +vz74sEi0dudmOVoe6peYxjEH8xXoIUqhnwXt/4Q= +-----END CERTIFICATE----- diff --git a/priv/demo.key b/priv/demo.key new file mode 100644 index 0000000..5d5786f --- /dev/null +++ b/priv/demo.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCwLTdjh7L5bTpPvQLZcDLSrmlltlqVf0tJUURvcfZPKcneTyXn +mAK9o1bKFp2SJ29QqBDhxXMMWS4794BL8/l/v/1tNmMiPYZ7wiVKU//uj9ICRG5k +5qi9O/DOr27cLYhdWAu5naNJxgGbiqnnaSKBGW1SWr3+EtL11k7G97ObpwIDAQAB +AoGBAKU1cbiLG0GdtU3rME3ZUj+RQNMZ4u5IVcBmTie4FcN8q4ombKQ2P3O4RX3z +IUZaZp+bS2F8uHt+8cVYPl57Zp5fwbIlv6jWgGpvXLsX8JBQl2OTw38B+hVwJvAM +h0mBzprUOs3KGZyF5cyA4osrZ4QvCZhwId9fAjwLGBF9i1yBAkEA4jWAF1sWQiwF +vY476m+0ihpRwGKjldKHWFZmvoB/AnNV/rXO+HRl3MB5wmO+Dqg3gJZrjGBgDeaV +g9hoQjK6ZwJBAMdg57iKLd8uUb7c4pR8fDdDbeeI5X7WDf2k9emT3BMPJPQ3EiSf +CStn1hRfp31U9CXEnw94rKHhrdMFrYjdzMECQCcWD3f5qTLt4GAMf5XWj199hLq1 +UIbGxdQhuccY9Nk7jJRiXczYb/Fg4KkSCvkFX/G8DAFJdc9xFEyfzAQEN+kCQH3a +nMrvZn9gBLffRKOIZPyZctHZp0xGIHTA4X39GMlrIN+Lt8coIKimlgssSlSiAK+q +iuFAQnC5PXlcNyuTHsECQAMNMY6jXikgSUZfVXitAFX3g9+IbjT9eJ92f60QneW8 +mxWQoqP3fqCSbTEysb7NojEEwppSZtaNgnBb5R4E+mU= +-----END RSA PRIVATE KEY----- diff --git a/src/eNet.erl b/src/eNet.erl index 78af749..41071c2 100644 --- a/src/eNet.erl +++ b/src/eNet.erl @@ -35,15 +35,15 @@ openTcp(ListenName, Port, ListenOpts) -> %% add a Ssl listener -spec openSsl(ListenName :: atom(), Port :: inet:port_number(), ListenOpts :: [listenOpt()]) -> {ok, pid()} | {error, term()}. openSsl(ListenName, Port, ListenOpts) -> - TcpMgrSupSpec = #{ + SslMgrSupSpec = #{ id => ListenName, - start => {ntTcpMgrSup, start_link, [Port, ListenOpts]}, + start => {ntSslMgrSup, start_link, [Port, ListenOpts]}, restart => permanent, shutdown => infinity, type => supervisor, - modules => [ntTcpMgrSup] + modules => [ntSslMgrSup] }, - supervisor:start_child(eNet_sup, TcpMgrSupSpec). + supervisor:start_child(eNet_sup, SslMgrSupSpec). %% add a Udp listener -spec openUdp(UdpName :: atom(), Port :: inet:port_number(), ListenOpts :: [listenOpt()]) -> {ok, pid()} | {error, term()}. diff --git a/src/misc/ntCom.erl b/src/misc/ntCom.erl index b0b7c62..9a8be98 100644 --- a/src/misc/ntCom.erl +++ b/src/misc/ntCom.erl @@ -101,12 +101,16 @@ serverName(PoolName, Index) -> asName(tcp, PrName) -> binary_to_atom(<<(atom_to_binary(PrName))/binary, "TAs">>); +asName(ssl, PrName) -> + binary_to_atom(<<(atom_to_binary(PrName))/binary, "SAs">>); asName(udp, PrName) -> binary_to_atom(<<(atom_to_binary(PrName))/binary, "UOs">>). lsName(tcp, PrName) -> binary_to_atom(<<(atom_to_binary(PrName))/binary, "TLs">>); +lsName(ssl, PrName) -> + binary_to_atom(<<(atom_to_binary(PrName))/binary, "SLs">>); lsName(udp, PrName) -> binary_to_atom(<<(atom_to_binary(PrName))/binary, "URs">>). diff --git a/src/ssl/doToSsl.md b/src/ssl/doToSsl.md deleted file mode 100644 index 4e34581..0000000 --- a/src/ssl/doToSsl.md +++ /dev/null @@ -1 +0,0 @@ -等新版socket稳定了再来封装该模块吧!!!! \ No newline at end of file diff --git a/src/ssl/ntSslAcceptor.erl b/src/ssl/ntSslAcceptor.erl new file mode 100644 index 0000000..0211864 --- /dev/null +++ b/src/ssl/ntSslAcceptor.erl @@ -0,0 +1,144 @@ +-module(ntSslAcceptor). + +-include("eNet.hrl"). +-include("ntCom.hrl"). + +-compile(inline). +-compile({inline_size, 128}). + +-export([ + start_link/5 + + , handshake/3 + + , init/1 + , handleMsg/2 + + , init_it/2 + , system_code_change/4 + , system_continue/3 + , system_get_state/1 + , system_terminate/4 +]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genActor start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec start_link(list(), timeout(), socket(), module(), [proc_lib:spawn_option()]) -> {ok, pid()}. +start_link(SslOpts, HandshakeTimeout, LSock, ConMod, SpawnOpts) -> + proc_lib:start_link(?MODULE, init_it, [self(), {SslOpts, HandshakeTimeout, LSock, ConMod}], infinity, SpawnOpts). + +init_it(Parent, Args) -> + process_flag(trap_exit, true), + modInit(Parent, Args). + +-spec system_code_change(term(), module(), undefined | term(), term()) -> {ok, term()}. +system_code_change(State, _Module, _OldVsn, _Extra) -> + {ok, State}. + +-spec system_continue(pid(), [], {module(), atom(), pid(), term()}) -> ok. +system_continue(_Parent, _Debug, {Parent, State}) -> + loop(Parent, State). + +-spec system_get_state(term()) -> {ok, term()}. +system_get_state(State) -> + {ok, State}. + +-spec system_terminate(term(), pid(), [], term()) -> none(). +system_terminate(Reason, _Parent, _Debug, _State) -> + exit(Reason). + +modInit(Parent, Args) -> + case init(Args) of + {ok, State} -> + proc_lib:init_ack(Parent, {ok, self()}), + loop(Parent, State); + {stop, Reason} -> + proc_lib:init_ack(Parent, {error, Reason}), + exit(Reason) + end. + +loop(Parent, State) -> + receive + {system, From, Request} -> + sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {Parent, State}); + {'EXIT', Parent, Reason} -> + exit(Reason); + Msg -> + case handleMsg(Msg, State) of + {ok, NewState} -> + loop(Parent, NewState); + {stop, Reason} -> + exit(Reason) + end + end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genActor end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-record(state, { + lSock + , sslOpts + , handshake_timeout + , ref + , conMod + , sockMod +}). + +-spec init(Args :: term()) -> ok. +init({SslOpts, HandshakeTimeout, LSock, ConMod}) -> + case prim_inet:async_accept(LSock, -1) of + {ok, Ref} -> + {ok, SockMod} = inet_db:lookup_socket(LSock), + {ok, #state{lSock = LSock, sslOpts = SslOpts, handshake_timeout = HandshakeTimeout, ref = Ref, conMod = ConMod, sockMod = SockMod}}; + {error, Reason} -> + ?ntErr("init prim_inet:async_accept error ~p~n", [Reason]), + {stop, Reason} + end. + +handleMsg({inet_async, LSock, Ref, Msg}, #state{lSock = LSock, sslOpts = SslOpts, handshake_timeout = HandshakeTimeout, ref = Ref, conMod = ConMod, sockMod = SockMod} = State) -> + case Msg of + {ok, Sock} -> + %% make it look like gen_tcp:accept + inet_db:register_socket(Sock, SockMod), + try ConMod:newConn(Sock) of + {ok, Pid} -> + gen_tcp:controlling_process(Sock, Pid), + Pid ! {?mSockReady, Sock, SslOpts, HandshakeTimeout}, + newAsyncAccept(LSock, State); + {close, Reason} -> + ?ntErr("handleMsg ConMod:newAcceptor return close ~p~n", [Reason]), + catch port_close(Sock), + newAsyncAccept(LSock, State); + _Ret -> + ?ntErr("ConMod:newAcceptor return error ~p~n", [_Ret]), + {stop, error_ret} + catch + E:R:S -> + ?ntErr("CliMod:newConnect crash: ~p:~p~n~p~n ~n ", [E, R, S]), + newAsyncAccept(LSock, State) + end; + {error, closed} -> + % ?ntErr("error, closed listen sock error ~p~n", [closed]), + {stop, normal}; + {error, Reason} -> + ?ntErr("listen sock error ~p~n", [Reason]), + {stop, {lsock, Reason}} + end; +handleMsg(_Msg, State) -> + ?ntErr("~p receive unexpected ~p msg: ~p", [?MODULE, self(), _Msg]), + {ok, State}. + +newAsyncAccept(LSock, State) -> + case prim_inet:async_accept(LSock, -1) of + {ok, Ref} -> + {ok, State#state{ref = Ref}}; + {error, Reason} -> + ?ntErr("~p prim_inet:async_accept error ~p~n", [?MODULE, Reason]), + {stop, Reason} + end. + +handshake(Sock, SslOpts, Timeout) -> + case ssl:handshake(Sock, SslOpts, Timeout) of + {ok, _SslSock} = Ret -> + Ret; + {ok, SslSock, _Ext} -> %% OTP 21.0 + {ok, SslSock}; + {error, _} = Err -> Err + end. diff --git a/src/ssl/ntSslAcceptorSup.erl b/src/ssl/ntSslAcceptorSup.erl new file mode 100644 index 0000000..79e373c --- /dev/null +++ b/src/ssl/ntSslAcceptorSup.erl @@ -0,0 +1,29 @@ +-module(ntSslAcceptorSup). + +-behaviour(supervisor). + +-export([ + start_link/3 +]). + +-export([ + init/1 +]). + +-spec(start_link(SupName :: atom(), SslOpts :: list(), HandshakeTimeout :: timeout()) -> {ok, pid()}). +start_link(SupName, SslOpts, HandshakeTimeout) -> + supervisor:start_link({local, SupName}, ?MODULE, {SslOpts, HandshakeTimeout}). + +init({SslOpts, HandshakeTimeout}) -> + SupFlags = #{strategy => simple_one_for_one, intensity => 100, period => 3600}, + + Acceptor = #{ + id => ntSslAcceptor, + start => {ntSslAcceptor, start_link, [SslOpts, HandshakeTimeout]}, + restart => transient, + shutdown => 3000, + type => worker, + modules => [ntSslAcceptor] + }, + {ok, {SupFlags, [Acceptor]}}. + diff --git a/src/ssl/ntSslListener.erl b/src/ssl/ntSslListener.erl new file mode 100644 index 0000000..dfb62ae --- /dev/null +++ b/src/ssl/ntSslListener.erl @@ -0,0 +1,143 @@ +-module(ntSslListener). + +-include("eNet.hrl"). +-include("ntCom.hrl"). + +-compile(inline). +-compile({inline_size, 128}). + +-export([ + start_link/4 + , getOpts/1 + , getListenPort/1 + + , init_it/3 + , system_code_change/4 + , system_continue/3 + , system_get_state/1 + , system_terminate/4 +]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genActor start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec(start_link(atom(), atom(), inet:port_number(), [listenOpt()]) -> {ok, pid()} | ignore | {error, term()}). +start_link(ListenName, AptSupName, Port, ListenOpts) -> + proc_lib:start_link(?MODULE, init_it, [ListenName, self(), {AptSupName, Port, ListenOpts}], infinity, []). + +init_it(Name, Parent, Args) -> + case safeRegister(Name) of + true -> + process_flag(trap_exit, true), + modInit(Parent, Args); + {false, Pid} -> + proc_lib:init_ack(Parent, {error, {already_started, Pid}}) + end. + +-spec system_code_change(term(), module(), undefined | term(), term()) -> {ok, term()}. +system_code_change(State, _Module, _OldVsn, _Extra) -> + {ok, State}. + +-spec system_continue(pid(), [], {module(), atom(), pid(), term()}) -> ok. +system_continue(_Parent, _Debug, {Parent, State}) -> + loop(Parent, State). + +-spec system_get_state(term()) -> {ok, term()}. +system_get_state(State) -> + {ok, State}. + +-spec system_terminate(term(), pid(), [], term()) -> none(). +system_terminate(Reason, _Parent, _Debug, _State) -> + exit(Reason). + +safeRegister(Name) -> + try register(Name, self()) of + true -> true + catch + _:_ -> {false, whereis(Name)} + end. + +modInit(Parent, Args) -> + case init(Args) of + {ok, State} -> + proc_lib:init_ack(Parent, {ok, self()}), + loop(Parent, State); + {stop, Reason} -> + proc_lib:init_ack(Parent, {error, Reason}), + exit(Reason) + end. + +loop(Parent, State) -> + receive + {system, From, Request} -> + sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {Parent, State}); + {'EXIT', Parent, Reason} -> + terminate(Reason, State); + Msg -> + case handleMsg(Msg, State) of + {ok, NewState} -> + loop(Parent, NewState); + {stop, Reason} -> + terminate(Reason, State), + exit(Reason) + end + end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genActor end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-record(state, { + listenAddr :: inet:ip_address() + , listenPort :: inet:port_number() + , lSock :: inet:socket() + , opts :: [listenOpt()] +}). + +-define(DefTcpOpts, [{nodelay, true}, {reuseaddr, true}, {send_timeout, 30000}, {send_timeout_close, true}]). + +init({AptSupName, Port, ListenOpts}) -> + process_flag(trap_exit, true), + TcpOpts = ?getLValue(tcpOpts, ListenOpts, []), + LastTcpOpts = ntCom:mergeOpts(?DefTcpOpts, TcpOpts), + %% Don't active the socket... + case gen_tcp:listen(Port, lists:keystore(active, 1, LastTcpOpts, {active, false})) of + {ok, LSock} -> + AptCnt = ?getLValue(aptCnt, ListenOpts, ?ACCEPTOR_POOL), + ConMod = ?getLValue(conMod, ListenOpts, undefined), + startAcceptor(AptCnt, LSock, AptSupName, ConMod), + {ok, {LAddr, LPort}} = inet:sockname(LSock), + % ?ntInfo("success to listen on ~p ~n", [Port]), + {ok, #state{listenAddr = LAddr, listenPort = LPort, lSock = LSock, opts = [{acceptors, AptCnt}, {tcpOpts, LastTcpOpts}]}}; + {error, Reason} -> + ?ntErr("failed to listen on ~p - ~p (~s) ~n", [Port, Reason, inet:format_error(Reason)]), + {stop, Reason} + end. + +handleMsg({'$gen_call', From, miOpts}, #state{opts = Opts} = State) -> + gen_server:reply(From, Opts), + {ok, State}; + +handleMsg({'$gen_call', From, miListenPort}, #state{listenPort = LPort} = State) -> + gen_server:reply(From, LPort), + {ok, State}; + +handleMsg(_Msg, State) -> + ?ntErr("~p unexpected info: ~p ~n", [?MODULE, _Msg]), + {noreply, State}. + +terminate(_Reason, #state{lSock = LSock, listenAddr = Addr, listenPort = Port}) -> + ?ntInfo("stopped on ~s:~p ~n", [inet:ntoa(Addr), Port]), + %% 关闭这个监听LSock 监听进程收到tcp_close 然后终止acctptor进程 + catch port_close(LSock), + ok. + +startAcceptor(0, _LSock, _AptSupName, _ConMod) -> + ok; +startAcceptor(N, LSock, AptSupName, ConMod) -> + supervisor:start_child(AptSupName, [LSock, ConMod, []]), + startAcceptor(N - 1, LSock, AptSupName, ConMod). + +-spec getOpts(pid()) -> [listenOpt()]. +getOpts(Listener) -> + gen_server:call(Listener, miOpts). + +-spec getListenPort(pid()) -> inet:port_number(). +getListenPort(Listener) -> + gen_server:call(Listener, miListenPort). + diff --git a/src/ssl/ntSslMgrSup.erl b/src/ssl/ntSslMgrSup.erl new file mode 100644 index 0000000..dccf92d --- /dev/null +++ b/src/ssl/ntSslMgrSup.erl @@ -0,0 +1,57 @@ +-module(ntSslMgrSup). + +-behaviour(supervisor). + +-include("eNet.hrl"). +-include("ntCom.hrl"). + +-export([ + start_link/3 +]). + +-export([ + init/1 +]). + +-spec(start_link(SupName :: atom(), Port :: inet:port_number(), ListenOpts :: [listenOpt()]) -> {ok, pid()} | {error, term()}). +start_link(SupName, Port, ListenOpts) -> + supervisor:start_link({local, SupName}, ?MODULE, {SupName, Port, ListenOpts}). + +init({SupName, Port, ListenOpts}) -> + SupFlag = #{strategy => one_for_one, intensity => 100, period => 3600}, + + AptSupName = ntCom:asName(ssl, SupName), + ListenName = ntCom:lsName(ssl, SupName), + + SslOpts = ?getLValue(sslOpts, ListenOpts, []), + {HandshakeTimeout, LastSslOpts} = + case lists:keytake(handshake_timeout, 1, SslOpts) of + {value, {handshake_timeout, Timeout}, TemSslOpts} -> + {Timeout, TemSslOpts}; + false -> + {?SSL_HANDSHAKE_TIMEOUT, SslOpts} + end, + + ChildSpecs = [ + #{ + id => AptSupName, + start => {ntSslAcceptorSup, start_link, [AptSupName, LastSslOpts, HandshakeTimeout]}, + restart => permanent, + shutdown => infinity, + type => supervisor, + modules => [ntSslAcceptorSup] + }, + #{ + id => ListenName, + start => {ntSslListener, start_link, [ListenName, AptSupName, Port, ListenOpts]}, + restart => permanent, + shutdown => 3000, + type => worker, + modules => [ntSslListener] + }], + {ok, {SupFlag, ChildSpecs}}. + + + + + diff --git a/src/test/utSslANSrv.erl b/src/test/utSslANSrv.erl new file mode 100644 index 0000000..9476266 --- /dev/null +++ b/src/test/utSslANSrv.erl @@ -0,0 +1,82 @@ +-module(utSslANSrv). %% ssl active N server + +-behaviour(gen_server). + +-include("eNet.hrl"). +-include("ntCom.hrl"). + +-export([newConn/1]). + +-export([start/2, start_link/1]). + +%% gen_server Function Exports +-export([init/1 + , handle_call/3 + , handle_cast/2 + , handle_info/2 + , terminate/2 + , code_change/3 +]). + +-record(state, {socket}). + +start(Name, Port) -> + PrivDir = code:priv_dir(eNet), + TcpOpts = [binary, {reuseaddr, true}], + SslOpts = [ + {certfile, filename:join(PrivDir, "demo.crt")}, + {keyfile, filename:join(PrivDir, "demo.key")} + ], + Opts = [{tcpOpts, TcpOpts}, {sslOpts, SslOpts}, {conMod, ?MODULE}], + eNet:openSsl(Name, Port, Opts). + +start_link(Sock) -> + {ok, proc_lib:spawn_link(?MODULE, init, Sock)}. + +newConn(Sock) -> + start_link(Sock). + +init(_Sock) -> + gen_server:enter_loop(?MODULE, [], #state{}). + +handle_call(_Request, _From, State) -> + io:format("handle_call for______ ~p~n", [_Request]), + {reply, ignore, State}. + +handle_cast(_Msg, State) -> + io:format("handle_cast for______ ~p~n", [_Msg]), + {noreply, State}. + +handle_info({ssl, Socket, Data}, State = #state{socket = _Sock}) -> + io:format("packet:~p Data from ~s~n", [inet:getopts(Socket, [packet]), Data]), + prim_inet:send(Socket, Data), + {noreply, State}; + +handle_info({ssl_error, _Socket, Reason}, State) -> + io:format("ssl_error for ~p~n", [Reason]), + {stop, {shutdown, Reason}, State}; +handle_info({ssl_closed, _Socket}, State) -> + io:format("ssl_closed"), + {noreply, State}; + +handle_info({ssl_passive, SslSock}, State) -> + inet:setopts(SslSock, [{active, 100}]), + {noreply, State}; +handle_info({?mSockReady, Sock, SslOpts, HandshakeTimeout}, State) -> + case ntSslAcceptor:handshake(Sock, SslOpts, HandshakeTimeout) of + {ok, SslSock} -> + {noreply, State#state{socket = SslSock}}; + _Err -> + io:format("handshake error ~p~n", [_Err]), + {stop, State} + end; +handle_info(_Info, State) -> + io:format("handle_info for______ ~p~n", [_Info]), + {noreply, State}. + +terminate(_Reason, #state{socket = Sock}) -> + catch port_close(Sock). + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + diff --git a/src/test/utSslCli.erl b/src/test/utSslCli.erl new file mode 100644 index 0000000..d6ddd1c --- /dev/null +++ b/src/test/utSslCli.erl @@ -0,0 +1,40 @@ +-module(utSslCli). + +-export([start/4, send/2, connect/4, loop/2]). + +-define(TCP_OPTIONS, [binary, {packet, 0}, {active, true}]). + +start(0, _Num, _Host, _Port) -> + ok; +start(Cnt, Num, Host, Port) -> + spawn(?MODULE, connect, [Num, self(), Host, Port]), + start(Cnt - 1, Num, Host, Num). + +connect(Num, Parent, Host, Port) -> + case ssl:connect(Host, Port, ?TCP_OPTIONS, 6000) of + {ok, Sock} -> + Parent ! {connected, Sock}, + loop(Num, Sock); + {error, Reason} -> + io:format("Client ~p connect error: ~p~n", [Num, Reason]) + end. + +loop(Num, Sock) -> + % Timeout = 5000 + rand:uniform(5000), + receive + {ssl, Sock, Data} -> + io:format("Client ~w received: ~s~n", [Num, Data]), + loop(Num, Sock); + {ssl_closed, Sock} -> + io:format("Client ~w socket closed~n", [Num]); + {ssl_error, Sock, Reason} -> + io:format("Client ~w socket error: ~p~n", [Num, Reason]); + Other -> + io:format("Client ~w unexpected: ~p", [Num, Other]) + after 0 -> + send(Num, Sock), loop(Num, Sock) + end. + +send(N, Sock) -> + ssl:send(Sock, [integer_to_list(N), ":", <<"Hello, eSockd!">>]). + diff --git a/src/test/utTcpAFSrv.erl b/src/test/utTcpAFSrv.erl index a8cdd13..fff83a2 100644 --- a/src/test/utTcpAFSrv.erl +++ b/src/test/utTcpAFSrv.erl @@ -4,7 +4,7 @@ %% start -export([newConn/1]). --export([start_link/2]). +-export([start/2, start_link/1]). %% gen_server Function Exports -export([init/1 @@ -17,37 +17,42 @@ -record(state, {transport, socket}). -start_link(Transport, Sock) -> - {ok, proc_lib:spawn_link(?MODULE, init, [[Transport, Sock]])}. +start(Name, Port) -> + TcpOpts = [binary, {reuseaddr, true}], + Opts = [{tcpOpts, TcpOpts}, {conMod, ?MODULE}], + eNet:openTcp(Name, Port, Opts). + +start_link(Sock) -> + {ok, proc_lib:spawn_link(?MODULE, init, Sock)}. newConn(Sock) -> - start_link(prim_inet, Sock). + start_link(Sock). -init([Transport, Sock]) -> +init(_Sock) -> gen_server:enter_loop(?MODULE, [], #state{}). handle_call(_Request, _From, State) -> io:format("handle_call for______ ~p~n", [_Request]), - {reply, ignore, State}. + {reply, ignore, State}. handle_cast(_Msg, State) -> io:format("handle_cast for______ ~p~n", [_Msg]), {noreply, State}. -handle_info({inet_async, Sock, _Ref, {ok, Data}}, State = #state{transport = Transport, socket = _Sock}) -> - {ok, Peername} = inet:peername(Sock), - io:format("packet:~p Data from ~p: ~s~n", [inet:getopts(Sock, [packet]), Peername, Data]), - prim_inet:send(Sock, Data), - prim_inet:async_recv(Sock, 0, -1), - {noreply, State}; +handle_info({inet_async, Sock, _Ref, {ok, Data}}, State = #state{socket = _Sock}) -> + {ok, Peername} = inet:peername(Sock), + io:format("packet:~p Data from ~p: ~s~n", [inet:getopts(Sock, [packet]), Peername, Data]), + prim_inet:send(Sock, Data), + prim_inet:async_recv(Sock, 0, -1), + {noreply, State}; handle_info({inet_async, _Sock, _Ref, {error, Reason}}, State) -> - io:format("Shutdown for ~p~n", [Reason]), - shutdown(Reason, State); + io:format("Shutdown for ~p~n", [Reason]), + shutdown(Reason, State); -handle_info({inet_reply, _Sock ,ok}, State) -> +handle_info({inet_reply, _Sock, ok}, State) -> io:format("inet_reply for______ ~p~n", [ok]), - {noreply, State}; + {noreply, State}; handle_info({inet_reply, _Sock, {error, Reason}}, State) -> io:format("Shutdown for ~p~n", [Reason]), @@ -62,7 +67,7 @@ handle_info(_Info, State) -> io:format("handle_info for______ ~p~n", [_Info]), {noreply, State}. -terminate(_Reason, #state{transport = Transport, socket = Sock}) -> +terminate(_Reason, #state{socket = Sock}) -> catch port_close(Sock). code_change(_OldVsn, State, _Extra) -> diff --git a/src/test/utTcpCli.erl b/src/test/utTcpCli.erl index daa1809..810e7e3 100644 --- a/src/test/utTcpCli.erl +++ b/src/test/utTcpCli.erl @@ -23,7 +23,7 @@ loop(Num, Sock) -> % Timeout = 5000 + rand:uniform(5000), receive {tcp, Sock, Data} -> - % io:format("Client ~w received: ~s~n", [Num, Data]), + io:format("Client ~w received: ~s~n", [Num, Data]), loop(Num, Sock); {tcp_closed, Sock} -> io:format("Client ~w socket closed~n", [Num]);