@ -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----- |
@ -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----- |
@ -1 +0,0 @@ | |||
等新版socket稳定了再来封装该模块吧!!!! |
@ -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. |
@ -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]}}. | |||
@ -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). | |||
@ -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}}. | |||
@ -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}. | |||
@ -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!">>]). | |||