@ -1,47 +0,0 @@ | |||
-ifndef(eNet_H). | |||
-define(eNet_H, true). | |||
%% gen_tcp ready maybe to set sock options | |||
%% ssl ready and then need do ntSslAcceptor:handshake/3 and maybe to set other options | |||
%% ppt ready and then need do ntPptAcceptor:pptAndHS/5 and maybe to set other options | |||
-define(mSockReady, mSockReady). | |||
-define(DefTpOpts, [ | |||
binary | |||
, {packet, 4} | |||
, {active, false} | |||
, {reuseaddr, true} | |||
, {nodelay, false} | |||
, {delay_send, true} | |||
, {send_timeout, 15000} | |||
, {keepalive, true} | |||
, {exit_on_close, true} | |||
, {back_log, 1024} | |||
]). | |||
-define(AptCnt, 16). | |||
-define(DefSslHSTet, 15000). | |||
-define(DefProxyPtTet, 5000). | |||
-export_type([listenOpt/0]). | |||
-type listenOpt() :: | |||
{aptCnt, non_neg_integer()} | | |||
{conMod, atom()} | | |||
{conArgs, atom()} | | |||
{tcpOpts, [gen_tcp:listen_option()]} | | |||
{sslOpts, [ssl:ssl_option()]} | | |||
{sslHSTet, timeout()} | | |||
{udpOpts, [gen_udp:option()]} | | |||
{proxyPt, boolean()} | | |||
{proxyPtTet, timeout()}. | |||
%% 令牌桶相关定义 | |||
-record(tBucket, { | |||
rate :: pos_integer() %% 速率 | |||
, tokens :: non_neg_integer() %% 剩余tokens数量 | |||
, lastTime :: pos_integer() %% 最后一次更新访问时间单位毫秒 | |||
, bucketSize :: pos_integer() %% 桶大小 可以容纳的令牌数量 | |||
}). | |||
-endif. |
@ -1,5 +0,0 @@ | |||
-define(ntErr(Format, Args), error_logger:error_msg(Format, Args)). | |||
-define(ntWarn(Format, Args), error_logger:warning_msg(Format, Args)). | |||
-define(ntInfo(Format, Args), error_logger:info_msg(Format, Args)). | |||
-define(getLValue(Key, List, Default), wsCom:getListValue(Key, List, Default)). |
@ -1,37 +0,0 @@ | |||
-ifndef(ntProxyPt_H). | |||
-define(ntProxyPt_H, true). | |||
%%-------------------------------------------------------------------- | |||
%% Proxy-Protocol Socket Wrapper | |||
%%-------------------------------------------------------------------- | |||
-type(pp2_additional_ssl_field() :: {pp2_ssl_client, boolean()} | |||
| {pp2_ssl_client_cert_conn, boolean()} | |||
| {pp2_ssl_client_cert_sess, boolean()} | |||
| {pp2_ssl_verify, success | failed} | |||
| {pp2_ssl_version, binary()} % US-ASCII string | |||
| {pp2_ssl_cn, binary()} % UTF8-encoded string | |||
| {pp2_ssl_cipher, binary()} % US-ASCII string | |||
| {pp2_ssl_sig_alg, binary()} % US-ASCII string | |||
| {pp2_ssl_key_alg, binary()} % US-ASCII string | |||
). | |||
-type(pp2_additional_field() :: | |||
{pp2_alpn, binary()} % byte sequence | |||
| {pp2_authority, binary()} % UTF8-encoded string | |||
| {pp2_crc32c, integer()} % 32-bit number | |||
| {pp2_netns, binary()} % US-ASCII string | |||
| {pp2_ssl, list(pp2_additional_ssl_field())} | |||
). | |||
-record(proxy_socket, { | |||
inet = inet4 :: inet4 | inet6 | 'unix' | 'unspec', | |||
src_addr = {0, 0, 0, 0} :: inet:ip_address() | undefined, | |||
dst_addr = {0, 0, 0, 0} :: inet:ip_address() | undefined, | |||
src_port = 0 :: inet:port_number() | undefined, | |||
dst_port = 0 :: inet:port_number() | undefined, | |||
%% Proxy protocol v2 addtional fields | |||
pp2_additional_info = [] :: list(pp2_additional_field()) | |||
}). | |||
-endif. |
@ -1,168 +0,0 @@ | |||
-module(wsPptAcceptor). | |||
-include("eNet.hrl"). | |||
-include("ntCom.hrl"). | |||
-include("ntProxyPt.hrl"). | |||
-compile(inline). | |||
-compile({inline_size, 128}). | |||
-export([ | |||
start_link/8 | |||
, pptAndHS/5 | |||
, 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(), boolean(), timeout(), inet:socket(), module(), term(), [proc_lib:spawn_option()]) -> {ok, pid()}. | |||
start_link(SslOpts, SslHSTet, ProxyPt, ProxyPtTet, LSock, ConMod, ConArgs, SpawnOpts) -> | |||
proc_lib:start_link(?MODULE, init_it, [self(), {SslOpts, SslHSTet, ProxyPt, ProxyPtTet, LSock, ConMod, ConArgs}], 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 | |||
, sslHSTet | |||
, proxyPt | |||
, proxyPtTet | |||
, ref | |||
, conMod | |||
, conArgs | |||
, sockMod | |||
}). | |||
-spec init(Args :: term()) -> ok. | |||
init({SslOpts, SslHSTet, ProxyPt, ProxyPtTet, LSock, ConMod, ConArgs}) -> | |||
case prim_inet:async_accept(LSock, -1) of | |||
{ok, Ref} -> | |||
{ok, SockMod} = inet_db:lookup_socket(LSock), | |||
{ok, #state{lSock = LSock, sslOpts = SslOpts, sslHSTet = SslHSTet, proxyPt = ProxyPt, proxyPtTet = ProxyPtTet, ref = Ref, conMod = ConMod, conArgs = ConArgs, 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, sslHSTet = SslHSTet, proxyPt = ProxyPt, proxyPtTet = ProxyPtTet, ref = Ref, conMod = ConMod, conArgs = ConArgs, 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, ConArgs) of | |||
{ok, Pid} -> | |||
gen_tcp:controlling_process(Sock, Pid), | |||
Pid ! {?mSockReady, Sock, SslOpts, SslHSTet, ProxyPt, ProxyPtTet}, | |||
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. | |||
pptAndHS(OSock, SslOpts, SslHSTet, ProxyPt, ProxyPtTet) -> | |||
PptRet = | |||
case ProxyPt of | |||
true -> | |||
ws_proxy_protocol:recv(OSock, ProxyPtTet); | |||
_ -> | |||
{ok, OSock, #proxy_socket{}} | |||
end, | |||
case PptRet of | |||
{ok, TemSock, ProxySock} -> | |||
case SslOpts /= undefined of | |||
true -> | |||
case ssl:handshake(TemSock, SslOpts, SslHSTet) of | |||
{ok, SslSock} -> | |||
{ok, SslSock, ProxySock}; | |||
{ok, SslSock, _Ext} -> %% OTP 21.0 | |||
{ok, SslSock, ProxySock}; | |||
{error, _} = Err -> Err | |||
end; | |||
_ -> | |||
PptRet | |||
end; | |||
_ -> | |||
PptRet | |||
end. | |||
@ -1,29 +0,0 @@ | |||
-module(wsPptAcceptorSup). | |||
-behaviour(supervisor). | |||
-export([ | |||
start_link/5 | |||
]). | |||
-export([ | |||
init/1 | |||
]). | |||
-spec(start_link(SupName :: atom(), SslOpts :: list(), SslHSTet :: timeout(), ProxyPt :: boolean(), ProxyPtTet :: timeout()) -> {ok, pid()}). | |||
start_link(SupName, SslOpts, SslHSTet, ProxyPt, ProxyPtTet) -> | |||
supervisor:start_link({local, SupName}, ?MODULE, {SslOpts, SslHSTet, ProxyPt, ProxyPtTet}). | |||
init({SslOpts, SslHSTet, ProxyPt, ProxyPtTet}) -> | |||
SupFlags = #{strategy => simple_one_for_one, intensity => 100, period => 3600}, | |||
Acceptor = #{ | |||
id => wsPptAcceptor, | |||
start => {wsPptAcceptor, start_link, [SslOpts, SslHSTet, ProxyPt, ProxyPtTet]}, | |||
restart => transient, | |||
shutdown => 3000, | |||
type => worker, | |||
modules => [wsPptAcceptor] | |||
}, | |||
{ok, {SupFlags, [Acceptor]}}. | |||
@ -1,143 +0,0 @@ | |||
-module(wsPptListener). | |||
-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}) -> | |||
TcpOpts = ?getLValue(tcpOpts, ListenOpts, []), | |||
LastTcpOpts = wsCom: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, ?AptCnt), | |||
ConMod = ?getLValue(conMod, ListenOpts, undefined), | |||
ConArgs = ?getLValue(conArgs, ListenOpts, undefined), | |||
startAcceptor(AptCnt, LSock, AptSupName, ConMod, ConArgs), | |||
{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, _ConArgs) -> | |||
ok; | |||
startAcceptor(N, LSock, AptSupName, ConMod, ConArgs) -> | |||
supervisor:start_child(AptSupName, [LSock, ConMod, ConArgs, []]), | |||
startAcceptor(N - 1, LSock, AptSupName, ConMod, ConArgs). | |||
-spec getOpts(pid()) -> [listenOpt()]. | |||
getOpts(Listener) -> | |||
gen_server:call(Listener, miOpts). | |||
-spec getListenPort(pid()) -> inet:port_number(). | |||
getListenPort(Listener) -> | |||
gen_server:call(Listener, miListenPort). | |||
@ -1,53 +0,0 @@ | |||
-module(wsPptMgrSup). | |||
-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 = wsCom:asName(ssl, SupName), | |||
ListenName = wsCom:lsName(ssl, SupName), | |||
SslOpts = ?getLValue(sslOpts, ListenOpts, undefined), | |||
SslHSTet = ?getLValue(sslHSTet, ListenOpts, ?DefSslHSTet), | |||
ProxyPt = ?getLValue(proxyPt, ListenOpts, false), | |||
ProxyPtTet = ?getLValue(proxyPtTet, ListenOpts, ?DefProxyPtTet), | |||
ChildSpecs = [ | |||
#{ | |||
id => AptSupName, | |||
start => {wsPptAcceptorSup, start_link, [AptSupName, SslOpts, SslHSTet, ProxyPt, ProxyPtTet]}, | |||
restart => permanent, | |||
shutdown => infinity, | |||
type => supervisor, | |||
modules => [wsPptAcceptorSup] | |||
}, | |||
#{ | |||
id => ListenName, | |||
start => {wsPptListener, start_link, [ListenName, AptSupName, Port, ListenOpts]}, | |||
restart => permanent, | |||
shutdown => 3000, | |||
type => worker, | |||
modules => [wsPptListener] | |||
}], | |||
{ok, {SupFlag, ChildSpecs}}. | |||
@ -1,197 +0,0 @@ | |||
%%-------------------------------------------------------------------- | |||
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. | |||
%% | |||
%% Licensed under the Apache License, Version 2.0 (the "License"); | |||
%% you may not use this file except in compliance with the License. | |||
%% You may obtain a copy of the License at | |||
%% | |||
%% http://www.apache.org/licenses/LICENSE-2.0 | |||
%% | |||
%% Unless required by applicable law or agreed to in writing, software | |||
%% distributed under the License is distributed on an "AS IS" BASIS, | |||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
%% See the License for the specific language governing permissions and | |||
%% limitations under the License. | |||
%%-------------------------------------------------------------------- | |||
%% @doc [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) | |||
-module(ws_proxy_protocol). | |||
-include("ntProxyPt.hrl"). | |||
-export([recv/2]). | |||
-ifdef(TEST). | |||
-export([parse_v1/3, parse_v2/5, parse_pp2_tlv/2, parse_pp2_ssl/1]). | |||
-endif. | |||
%% Protocol Command | |||
-define(LOCAL, 16#0). | |||
-define(PROXY, 16#1). | |||
%% Address families | |||
-define(UNSPEC, 16#0). | |||
-define(INET, 16#1). | |||
-define(INET6, 16#2). | |||
-define(UNIX, 16#3). | |||
-define(STREAM, 16#1). | |||
-define(DGRAM, 16#2). | |||
-define(SPACE, 16#20). | |||
-define(TIMEOUT, 5000). | |||
%% Proxy Protocol Additional Fields | |||
-define(PP2_TYPE_ALPN, 16#01). | |||
-define(PP2_TYPE_AUTHORITY, 16#02). | |||
-define(PP2_TYPE_CRC32C, 16#03). | |||
-define(PP2_TYPE_NOOP, 16#04). | |||
-define(PP2_TYPE_SSL, 16#20). | |||
-define(PP2_SUBTYPE_SSL_VERSION, 16#21). | |||
-define(PP2_SUBTYPE_SSL_CN, 16#22). | |||
-define(PP2_SUBTYPE_SSL_CIPHER, 16#23). | |||
-define(PP2_SUBTYPE_SSL_SIG_ALG, 16#24). | |||
-define(PP2_SUBTYPE_SSL_KEY_ALG, 16#25). | |||
-define(PP2_TYPE_NETNS, 16#30). | |||
%% Protocol signature: | |||
%% 16#0D,16#0A,16#00,16#0D,16#0A,16#51,16#55,16#49,16#54,16#0A | |||
-define(SIG, "\r\n\0\r\nQUIT\n"). | |||
-spec(recv(inet:socket(), timeout()) -> {ok, inet:socket(), #proxy_socket{}} | {error, term()}). | |||
recv(Sock, Timeout) -> | |||
{ok, OriginOpts} = inet:getopts(Sock, [mode, active, packet]), | |||
ok = inet:setopts(Sock, [binary, {active, once}, {packet, line}]), | |||
receive | |||
%% V1 TCP | |||
{_, Sock, <<"PROXY TCP", Proto, ?SPACE, ProxyInfo/binary>>} -> | |||
inet:setopts(Sock, OriginOpts), | |||
parse_v1(Sock, ProxyInfo, #proxy_socket{inet = inet_family(Proto)}); | |||
%% V1 Unknown | |||
{_, _Sock, <<"PROXY UNKNOWN", _ProxyInfo/binary>>} -> | |||
inet:setopts(Sock, OriginOpts), | |||
{ok, Sock, #proxy_socket{}}; | |||
%% V2 TCP | |||
{_, _Sock, <<"\r\n">>} -> | |||
inet:setopts(Sock, [{active, false}, {packet, raw}]), | |||
{ok, Header} = gen_tcp:recv(Sock, 14, 1000), | |||
<<?SIG, 2:4, Cmd:4, AF:4, Trans:4, Len:16>> = Header, | |||
case gen_tcp:recv(Sock, Len, 1000) of | |||
{ok, ProxyInfo} -> | |||
inet:setopts(Sock, OriginOpts), | |||
parse_v2(Cmd, Trans, ProxyInfo, #proxy_socket{inet = inet_family(AF)}, Sock); | |||
{error, Reason} -> | |||
{error, {recv_proxy_info_error, Reason}} | |||
end; | |||
{tcp_error, _Sock, Reason} -> | |||
{error, {recv_proxy_info_error, Reason}}; | |||
{tcp_closed, _Sock} -> | |||
{error, {recv_proxy_info_error, tcp_closed}}; | |||
{_, _Sock, ProxyInfo} -> | |||
{error, {invalid_proxy_info, ProxyInfo}} | |||
after | |||
Timeout -> | |||
{error, proxy_proto_timeout} | |||
end. | |||
parse_v1(Sock, ProxyInfo, ProxySock) -> | |||
[SrcAddrBin, DstAddrBin, SrcPortBin, DstPortBin] = binary:split(ProxyInfo, [<<" ">>, <<"\r\n">>], [global, trim]), | |||
{ok, SrcAddr} = inet:parse_address(binary_to_list(SrcAddrBin)), | |||
{ok, DstAddr} = inet:parse_address(binary_to_list(DstAddrBin)), | |||
SrcPort = list_to_integer(binary_to_list(SrcPortBin)), | |||
DstPort = list_to_integer(binary_to_list(DstPortBin)), | |||
{ok, Sock, ProxySock#proxy_socket{src_addr = SrcAddr, dst_addr = DstAddr, src_port = SrcPort, dst_port = DstPort}}. | |||
parse_v2(?LOCAL, _Trans, _ProxyInfo, ProxySocket, Sock) -> | |||
{ok, Sock, ProxySocket}; | |||
parse_v2(?PROXY, ?STREAM, ProxyInfo, ProxySock = #proxy_socket{inet = inet4}, Sock) -> | |||
<<A:8, B:8, C:8, D:8, W:8, X:8, Y:8, Z:8, SrcPort:16, DstPort:16, AdditionalBytes/binary>> = ProxyInfo, | |||
parse_pp2_additional(AdditionalBytes, ProxySock#proxy_socket{src_addr = {A, B, C, D}, src_port = SrcPort, dst_addr = {W, X, Y, Z}, dst_port = DstPort}, Sock); | |||
parse_v2(?PROXY, ?STREAM, ProxyInfo, ProxySock = #proxy_socket{inet = inet6}, Sock) -> | |||
<<A:16, B:16, C:16, D:16, E:16, F:16, G:16, H:16, R:16, S:16, T:16, U:16, V:16, W:16, X:16, Y:16, SrcPort:16, DstPort:16, AdditionalBytes/binary>> = ProxyInfo, | |||
parse_pp2_additional(AdditionalBytes, ProxySock#proxy_socket{src_addr = {A, B, C, D, E, F, G, H}, src_port = SrcPort, dst_addr = {R, S, T, U, V, W, X, Y}, dst_port = DstPort}, Sock); | |||
parse_v2(_, _, _, _, _) -> | |||
{error, unsupported_proto_v2}. | |||
parse_pp2_additional(<<>>, ProxySock, Sock) -> | |||
{ok, Sock, ProxySock}; | |||
parse_pp2_additional(Bytes, ProxySock, Sock) when is_binary(Bytes) -> | |||
IgnoreGuard = fun(?PP2_TYPE_NOOP) -> false; (_Type) -> true end, | |||
AdditionalInfo = parse_pp2_tlv(fun pp2_additional_field/1, Bytes, IgnoreGuard), | |||
{ok, Sock, ProxySock#proxy_socket{pp2_additional_info = AdditionalInfo}}. | |||
parse_pp2_tlv(Fun, Bytes) -> | |||
parse_pp2_tlv(Fun, Bytes, fun(_Any) -> true end). | |||
parse_pp2_tlv(Fun, Bytes, Guard) -> | |||
[Fun({Type, Val}) || <<Type:8, Len:16, Val:Len/binary>> <= Bytes, Guard(Type)]. | |||
pp2_additional_field({?PP2_TYPE_ALPN, PP2_ALPN}) -> | |||
{pp2_alpn, PP2_ALPN}; | |||
pp2_additional_field({?PP2_TYPE_AUTHORITY, PP2_AUTHORITY}) -> | |||
{pp2_authority, PP2_AUTHORITY}; | |||
pp2_additional_field({?PP2_TYPE_CRC32C, PP2_CRC32C}) -> | |||
{pp2_crc32c, PP2_CRC32C}; | |||
pp2_additional_field({?PP2_TYPE_NETNS, PP2_NETNS}) -> | |||
{pp2_netns, PP2_NETNS}; | |||
pp2_additional_field({?PP2_TYPE_SSL, PP2_SSL}) -> | |||
{pp2_ssl, parse_pp2_ssl(PP2_SSL)}; | |||
pp2_additional_field({Field, Value}) -> | |||
{{pp2_raw, Field}, Value}. | |||
parse_pp2_ssl(<<_Unused:5, PP2_CLIENT_CERT_SESS:1, PP2_CLIENT_CERT_CONN:1, PP2_CLIENT_SSL:1, | |||
PP2_SSL_VERIFY:32, SubFields/bitstring>>) -> | |||
[ | |||
%% The PP2_CLIENT_SSL flag indicates that the client connected over SSL/TLS. When | |||
%% this field is present, the US-ASCII string representation of the TLS version is | |||
%% appended at the end of the field in the TLV format using the type PP2_SUBTYPE_SSL_VERSION. | |||
{pp2_ssl_client, bool(PP2_CLIENT_SSL)}, | |||
%% PP2_CLIENT_CERT_CONN indicates that the client provided a certificate over the | |||
%% current connection. | |||
{pp2_ssl_client_cert_conn, bool(PP2_CLIENT_CERT_CONN)}, | |||
%% PP2_CLIENT_CERT_SESS indicates that the client provided a | |||
%% certificate at least once over the TLS session this connection belongs to. | |||
{pp2_ssl_client_cert_sess, bool(PP2_CLIENT_CERT_SESS)}, | |||
%% The <verify> field will be zero if the client presented a certificate | |||
%% and it was successfully verified, and non-zero otherwise. | |||
{pp2_ssl_verify, ssl_certificate_verified(PP2_SSL_VERIFY)} | |||
| parse_pp2_tlv(fun pp2_additional_ssl_field/1, SubFields) | |||
]. | |||
pp2_additional_ssl_field({?PP2_SUBTYPE_SSL_VERSION, PP2_SSL_VERSION}) -> | |||
{pp2_ssl_version, PP2_SSL_VERSION}; | |||
%% In all cases, the string representation (in UTF8) of the Common Name field | |||
%% (OID: 2.5.4.3) of the client certificate's Distinguished Name, is appended | |||
%% using the TLV format and the type PP2_SUBTYPE_SSL_CN. E.g. "example.com". | |||
pp2_additional_ssl_field({?PP2_SUBTYPE_SSL_CN, PP2_SSL_CN}) -> | |||
{pp2_ssl_cn, PP2_SSL_CN}; | |||
pp2_additional_ssl_field({?PP2_SUBTYPE_SSL_CIPHER, PP2_SSL_CIPHER}) -> | |||
{pp2_ssl_cipher, PP2_SSL_CIPHER}; | |||
pp2_additional_ssl_field({?PP2_SUBTYPE_SSL_SIG_ALG, PP2_SSL_SIG_ALG}) -> | |||
{pp2_ssl_sig_alg, PP2_SSL_SIG_ALG}; | |||
pp2_additional_ssl_field({?PP2_SUBTYPE_SSL_KEY_ALG, PP2_SSL_KEY_ALG}) -> | |||
{pp2_ssl_key_alg, PP2_SSL_KEY_ALG}; | |||
pp2_additional_ssl_field({Field, Val}) -> | |||
{{pp2_ssl_raw, Field}, Val}. | |||
ssl_certificate_verified(0) -> success; | |||
ssl_certificate_verified(_) -> failed. | |||
%% V1 | |||
inet_family($4) -> inet4; | |||
inet_family($6) -> inet6; | |||
%% V2 | |||
inet_family(?UNSPEC) -> unspec; | |||
inet_family(?INET) -> inet4; | |||
inet_family(?INET6) -> inet6; | |||
inet_family(?UNIX) -> unix. | |||
bool(1) -> true; | |||
bool(_) -> false. | |||
@ -1,145 +0,0 @@ | |||
-module(wsSslAcceptor). | |||
-include("eNet.hrl"). | |||
-include("ntCom.hrl"). | |||
-compile(inline). | |||
-compile({inline_size, 128}). | |||
-export([ | |||
start_link/6 | |||
, 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(), inet:socket(), module(), term(), [proc_lib:spawn_option()]) -> {ok, pid()}. | |||
start_link(SslOpts, HandshakeTimeout, LSock, ConMod, ConArgs, SpawnOpts) -> | |||
proc_lib:start_link(?MODULE, init_it, [self(), {SslOpts, HandshakeTimeout, LSock, ConMod, ConArgs}], 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 | |||
, sslHSTet | |||
, ref | |||
, conMod | |||
, conArgs | |||
, sockMod | |||
}). | |||
-spec init(Args :: term()) -> ok. | |||
init({SslOpts, SslHSTet, LSock, ConMod, ConArgs}) -> | |||
case prim_inet:async_accept(LSock, -1) of | |||
{ok, Ref} -> | |||
{ok, SockMod} = inet_db:lookup_socket(LSock), | |||
{ok, #state{lSock = LSock, sslOpts = SslOpts, sslHSTet = SslHSTet, ref = Ref, conMod = ConMod, conArgs = ConArgs, 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, sslHSTet = SslHSTet, ref = Ref, conMod = ConMod, conArgs = ConArgs, 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, ConArgs) of | |||
{ok, Pid} -> | |||
gen_tcp:controlling_process(Sock, Pid), | |||
Pid ! {?mSockReady, Sock, SslOpts, SslHSTet}, | |||
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. |
@ -1,29 +0,0 @@ | |||
-module(wsSslAcceptorSup). | |||
-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 => wsSslAcceptor, | |||
start => {wsSslAcceptor, start_link, [SslOpts, HandshakeTimeout]}, | |||
restart => transient, | |||
shutdown => 3000, | |||
type => worker, | |||
modules => [wsSslAcceptor] | |||
}, | |||
{ok, {SupFlags, [Acceptor]}}. | |||
@ -1,143 +0,0 @@ | |||
-module(wsSslListener). | |||
-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}) -> | |||
TcpOpts = ?getLValue(tcpOpts, ListenOpts, []), | |||
LastTcpOpts = wsCom: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, ?AptCnt), | |||
ConMod = ?getLValue(conMod, ListenOpts, undefined), | |||
ConArgs = ?getLValue(conArgs, ListenOpts, undefined), | |||
startAcceptor(AptCnt, LSock, AptSupName, ConMod, ConArgs), | |||
{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, _ConArgs) -> | |||
ok; | |||
startAcceptor(N, LSock, AptSupName, ConMod, ConArgs) -> | |||
supervisor:start_child(AptSupName, [LSock, ConMod, ConArgs, []]), | |||
startAcceptor(N - 1, LSock, AptSupName, ConMod, ConArgs). | |||
-spec getOpts(pid()) -> [listenOpt()]. | |||
getOpts(Listener) -> | |||
gen_server:call(Listener, miOpts). | |||
-spec getListenPort(pid()) -> inet:port_number(). | |||
getListenPort(Listener) -> | |||
gen_server:call(Listener, miListenPort). | |||
@ -1,51 +0,0 @@ | |||
-module(wsSslMgrSup). | |||
-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 = wsCom:asName(ssl, SupName), | |||
ListenName = wsCom:lsName(ssl, SupName), | |||
SslOpts = ?getLValue(sslOpts, ListenOpts, []), | |||
SslHSTet = ?getLValue(sslHSTet, ListenOpts, ?DefSslHSTet), | |||
ChildSpecs = [ | |||
#{ | |||
id => AptSupName, | |||
start => {wsSslAcceptorSup, start_link, [AptSupName, SslOpts, SslHSTet]}, | |||
restart => permanent, | |||
shutdown => infinity, | |||
type => supervisor, | |||
modules => [wsSslAcceptorSup] | |||
}, | |||
#{ | |||
id => ListenName, | |||
start => {wsSslListener, start_link, [ListenName, AptSupName, Port, ListenOpts]}, | |||
restart => permanent, | |||
shutdown => 3000, | |||
type => worker, | |||
modules => [wsSslListener] | |||
}], | |||
{ok, {SupFlag, ChildSpecs}}. | |||
@ -1,133 +0,0 @@ | |||
-module(wsTcpAcceptor). | |||
-include("eNet.hrl"). | |||
-include("ntCom.hrl"). | |||
-compile(inline). | |||
-compile({inline_size, 128}). | |||
-export([ | |||
start_link/4 | |||
, 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(inet:socket(), module(), term(), [proc_lib:spawn_option()]) -> {ok, pid()}. | |||
start_link(LSock, ConMod, ConArgs, SpawnOpts) -> | |||
proc_lib:start_link(?MODULE, init_it, [self(), {LSock, ConMod, ConArgs}], 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 | |||
, ref | |||
, conMod | |||
, conArgs | |||
, sockMod | |||
}). | |||
-spec init(Args :: term()) -> ok. | |||
init({LSock, ConMod, ConArgs}) -> | |||
case prim_inet:async_accept(LSock, -1) of | |||
{ok, Ref} -> | |||
{ok, SockMod} = inet_db:lookup_socket(LSock), | |||
{ok, #state{lSock = LSock, ref = Ref, conMod = ConMod, conArgs = ConArgs, 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, ref = Ref, conMod = ConMod, conArgs = ConArgs, 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, ConArgs) of | |||
{ok, Pid} -> | |||
gen_tcp:controlling_process(Sock, Pid), | |||
Pid ! {?mSockReady, Sock}, | |||
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. | |||
@ -1,29 +0,0 @@ | |||
-module(wsTcpAcceptorSup). | |||
-behaviour(supervisor). | |||
-export([ | |||
start_link/1 | |||
]). | |||
-export([ | |||
init/1 | |||
]). | |||
-spec(start_link(SupName :: atom()) -> {ok, pid()}). | |||
start_link(SupName) -> | |||
supervisor:start_link({local, SupName}, ?MODULE, undefined). | |||
init(_Args) -> | |||
SupFlags = #{strategy => simple_one_for_one, intensity => 100, period => 3600}, | |||
Acceptor = #{ | |||
id => wsTcpAcceptor, | |||
start => {wsTcpAcceptor, start_link, []}, | |||
restart => transient, | |||
shutdown => 3000, | |||
type => worker, | |||
modules => [wsTcpAcceptor] | |||
}, | |||
{ok, {SupFlags, [Acceptor]}}. | |||
@ -1,143 +0,0 @@ | |||
-module(wsTcpListener). | |||
-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}) -> | |||
TcpOpts = ?getLValue(tcpOpts, ListenOpts, []), | |||
LastTcpOpts = wsCom: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, ?AptCnt), | |||
ConMod = ?getLValue(conMod, ListenOpts, undefined), | |||
ConArgs = ?getLValue(conArgs, ListenOpts, undefined), | |||
startAcceptor(AptCnt, LSock, AptSupName, ConMod, ConArgs), | |||
{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, _ConArgs) -> | |||
ok; | |||
startAcceptor(N, LSock, AptSupName, ConMod, ConArgs) -> | |||
supervisor:start_child(AptSupName, [LSock, ConMod, ConArgs, []]), | |||
startAcceptor(N - 1, LSock, AptSupName, ConMod, ConArgs). | |||
-spec getOpts(pid()) -> [listenOpt()]. | |||
getOpts(Listener) -> | |||
gen_server:call(Listener, miOpts). | |||
-spec getListenPort(pid()) -> inet:port_number(). | |||
getListenPort(Listener) -> | |||
gen_server:call(Listener, miListenPort). | |||
@ -1,48 +0,0 @@ | |||
-module(wsTcpMgrSup). | |||
-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 = wsCom:asName(tcp, SupName), | |||
ListenName = wsCom:lsName(tcp, SupName), | |||
ChildSpecs = [ | |||
#{ | |||
id => AptSupName, | |||
start => {wsTcpAcceptorSup, start_link, [AptSupName]}, | |||
restart => permanent, | |||
shutdown => infinity, | |||
type => supervisor, | |||
modules => [wsTcpAcceptorSup] | |||
}, | |||
#{ | |||
id => ListenName, | |||
start => {wsTcpListener, start_link, [ListenName, AptSupName, Port, ListenOpts]}, | |||
restart => permanent, | |||
shutdown => 3000, | |||
type => worker, | |||
modules => [wsTcpListener] | |||
}], | |||
{ok, {SupFlag, ChildSpecs}}. | |||
@ -1,118 +0,0 @@ | |||
-module(wsCom). | |||
-compile([export_all, nowarn_export_all]). | |||
-spec mergeOpts(Defaults :: list(), Options :: list()) -> list(). | |||
mergeOpts(Defaults, Options) -> | |||
lists:foldl( | |||
fun({Opt, Val}, Acc) -> | |||
lists:keystore(Opt, 1, Acc, {Opt, Val}); | |||
(Opt, Acc) -> | |||
lists:usort([Opt | Acc]) | |||
end, | |||
Defaults, Options). | |||
mergeAddr({Addr, _Port}, SockOpts) -> | |||
lists:keystore(ip, 1, SockOpts, {ip, Addr}); | |||
mergeAddr(_Port, SockOpts) -> | |||
SockOpts. | |||
getPort({_Addr, Port}) -> Port; | |||
getPort(Port) -> Port. | |||
fixIpPort(IpOrStr, Port) -> | |||
if | |||
is_list(IpOrStr), is_integer(Port) -> | |||
{ok, IP} = inet:parse_address(v), | |||
{IP, Port}; | |||
is_tuple(IpOrStr), is_integer(Port) -> | |||
case isIpv4OrIpv6(IpOrStr) of | |||
true -> | |||
{IpOrStr, Port}; | |||
false -> | |||
error({invalid_ip, IpOrStr}) | |||
end; | |||
true -> | |||
error({invalid_ip_port, IpOrStr, Port}) | |||
end. | |||
parseAddr({Addr, Port}) when is_list(Addr), is_integer(Port) -> | |||
{ok, IPAddr} = inet:parse_address(Addr), | |||
{IPAddr, Port}; | |||
parseAddr({Addr, Port}) when is_tuple(Addr), is_integer(Port) -> | |||
case isIpv4OrIpv6(Addr) of | |||
true -> | |||
{Addr, Port}; | |||
false -> | |||
error(invalid_ipaddr) | |||
end; | |||
parseAddr(Port) -> | |||
Port. | |||
isIpv4OrIpv6({A, B, C, D}) -> | |||
A >= 0 andalso A =< 255 andalso | |||
B >= 0 andalso B =< 255 andalso | |||
C >= 0 andalso C =< 255 andalso | |||
D >= 0 andalso D =< 255; | |||
isIpv4OrIpv6({A, B, C, D, E, F, G, H}) -> | |||
A >= 0 andalso A =< 65535 andalso | |||
B >= 0 andalso B =< 65535 andalso | |||
C >= 0 andalso C =< 65535 andalso | |||
D >= 0 andalso D =< 65535 andalso | |||
E >= 0 andalso E =< 65535 andalso | |||
F >= 0 andalso F =< 65535 andalso | |||
G >= 0 andalso G =< 65535 andalso | |||
H >= 0 andalso H =< 65535; | |||
isIpv4OrIpv6(_) -> | |||
false. | |||
%% @doc Return true if the value is an ipv4 address | |||
isIpv4({A, B, C, D}) -> | |||
A >= 0 andalso A =< 255 andalso | |||
B >= 0 andalso B =< 255 andalso | |||
C >= 0 andalso C =< 255 andalso | |||
D >= 0 andalso D =< 255; | |||
isIpv4(_) -> | |||
false. | |||
%% @doc Return true if the value is an ipv6 address | |||
isIpv6({A, B, C, D, E, F, G, H}) -> | |||
A >= 0 andalso A =< 65535 andalso | |||
B >= 0 andalso B =< 65535 andalso | |||
C >= 0 andalso C =< 65535 andalso | |||
D >= 0 andalso D =< 65535 andalso | |||
E >= 0 andalso E =< 65535 andalso | |||
F >= 0 andalso F =< 65535 andalso | |||
G >= 0 andalso G =< 65535 andalso | |||
H >= 0 andalso H =< 65535; | |||
isIpv6(_) -> | |||
false. | |||
getListValue(Key, List, Default) -> | |||
case lists:keyfind(Key, 1, List) of | |||
false -> | |||
Default; | |||
{Key, Value} -> | |||
Value | |||
end. | |||
serverName(PoolName, Index) -> | |||
list_to_atom(atom_to_list(PoolName) ++ "_" ++ integer_to_list(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">>). | |||
@ -1,69 +0,0 @@ | |||
-module(wsNet). | |||
-include("eNet.hrl"). | |||
-export([ | |||
openTcp/3 | |||
, openSsl/3 | |||
, openUdp/3 | |||
, openPpt/3 | |||
, close/1 | |||
]). | |||
%% add a TCP listener | |||
-spec openTcp(ListenName :: atom(), Port :: inet:port_number(), ListenOpts :: [listenOpt()]) -> {ok, pid()} | {error, term()}. | |||
openTcp(ListenName, Port, ListenOpts) -> | |||
TcpMgrSupSpec = #{ | |||
id => ListenName, | |||
start => {wsTcpMgrSup, start_link, [ListenName, Port, ListenOpts]}, | |||
restart => permanent, | |||
shutdown => infinity, | |||
type => supervisor, | |||
modules => [wsTcpMgrSup] | |||
}, | |||
supervisor:start_child(eWSrv_sup, TcpMgrSupSpec). | |||
%% add a Ssl listener | |||
-spec openSsl(ListenName :: atom(), Port :: inet:port_number(), ListenOpts :: [listenOpt()]) -> {ok, pid()} | {error, term()}. | |||
openSsl(ListenName, Port, ListenOpts) -> | |||
SslMgrSupSpec = #{ | |||
id => ListenName, | |||
start => {wsntSslMgrSup, start_link, [ListenName, Port, ListenOpts]}, | |||
restart => permanent, | |||
shutdown => infinity, | |||
type => supervisor, | |||
modules => [wsSslMgrSup] | |||
}, | |||
supervisor:start_child(eWSrv_sup, SslMgrSupSpec). | |||
%% add a Udp listener | |||
-spec openUdp(UdpName :: atom(), Port :: inet:port_number(), ListenOpts :: [listenOpt()]) -> {ok, pid()} | {error, term()}. | |||
openUdp(UdpName, Port, ListenOpts) -> | |||
UdpSrvSpec = #{ | |||
id => UdpName, | |||
start => {wsUdpSrv, start_link, [UdpName, Port, ListenOpts]}, | |||
restart => permanent, | |||
shutdown => 5000, | |||
type => worker, | |||
modules => [wsUdpSrv] | |||
}, | |||
supervisor:start_child(eWSrv_sup, UdpSrvSpec). | |||
%% add a Proxy protocol listener | |||
-spec openPpt(ListenName :: atom(), Port :: inet:port_number(), ListenOpts :: [listenOpt()]) -> {ok, pid()} | {error, term()}. | |||
openPpt(ListenName, Port, ListenOpts) -> | |||
SslMgrSupSpec = #{ | |||
id => ListenName, | |||
start => {wsPptMgrSup, start_link, [ListenName, Port, ListenOpts]}, | |||
restart => permanent, | |||
shutdown => infinity, | |||
type => supervisor, | |||
modules => [wsPptMgrSup] | |||
}, | |||
supervisor:start_child(eWSrv_sup, SslMgrSupSpec). | |||
%% stop a listener | |||
-spec close(atom()) -> ignore | {ok, pid()} | {error, term()}. | |||
close(ListenName) -> | |||
supervisor:terminate_child(eWSrv_sup, ListenName), | |||
supervisor:delete_child(eWSrv_sup, ListenName). |
@ -1,28 +0,0 @@ | |||
-module(wsConSup). | |||
-behaviour(supervisor). | |||
-export([ | |||
start_link/2 | |||
]). | |||
-export([ | |||
init/1 | |||
]). | |||
-spec(start_link(SupName :: atom(), WsMod :: module()) -> {ok, pid()}). | |||
start_link(SupName, WsMod) -> | |||
supervisor:start_link({local, SupName}, ?MODULE, WsMod). | |||
init(WsMod) -> | |||
SupFlags = #{strategy => simple_one_for_one, intensity => 100, period => 3600}, | |||
WsHttpSpec = #{ | |||
id => wsHttp, | |||
start => {wsHttp, start_link, [WsMod]}, | |||
restart => transient, | |||
shutdown => 3000, | |||
type => worker, | |||
modules => [wsHttp] | |||
}, | |||
{ok, {SupFlags, [WsHttpSpec]}}. |