ssl_server.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,376 行 · 第 1/3 页
ERL
1,376 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%%%% Purpose : SSL server%%%% TODO%%%% XXX The ip option in listen is not general enough. It is assumed%% to be a tuple, which is not always the case.-module(ssl_server).-behaviour(gen_server).%% External exports -export([start_link/0]). -export([transport_accept/2, transport_accept/3, ssl_accept/2, ssl_accept/3, ciphers/0, connect/5, connect/6, connection_info/1, close/1, listen/3, listen/4, peercert/1, peername/1, proxy_join/2, seed/1, setnodelay/2, sockname/1, version/0]).-export([start_link_prim/0]).-export([ssl_accept_prim/4, transport_accept_prim/4, connect_prim/7, close_prim/2, listen_prim/5, proxy_join_prim/3, peername_prim/2, setnodelay_prim/3, sockname_prim/2]).-export([dump/0, dump/1]).-export([enable_debug/0, disable_debug/0, set_debug/1]).-export([enable_debugmsg/0, disable_debugmsg/0, set_debugmsg/1]).%% gen_server callbacks-export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]).-include("ssl_int.hrl").-record(st, { port = [], % port() of port program progpid = [], % OS pid of port program debug = false, % debug printout flag cons = [], % All brokers except pending accepts paccepts = [], % Pending accept brokers proxylsport = [], % proxy listen socket port intref = 0, % internal reference counter compvsn = "", % ssl compile library version libvsn = "", % ssl library version ciphers = [] % available ciphers }).%% In all functions below IP is a four tuple, e.g. {192, 236, 52, 7}. %% Port, Fd and ListenFd are integers; Flags is a string of characters.%%%% The prefixes F and L mean foreign and local, respectively. %% Example: FIP (IP address for foreign end).%%%% start_link() -> {ok, Pid} | {error, Reason}%%start_link() -> gen_server:start_link({local, ssl_server}, ssl_server, [], []).start_link_prim() -> gen_server:start_link({local, ssl_server_prim}, ssl_server, [], []).%%%% transport_accept(ListenFd, Flags) -> {ok, Fd, ProxyLLPort} |%% {error, Reason}%%transport_accept(ListenFd, Flags) -> transport_accept(ListenFd, Flags, infinity).transport_accept(ListenFd, Flags, Timeout) -> transport_accept_prim(ssl_server,ListenFd, Flags, Timeout).transport_accept_prim(ServerName, ListenFd, Flags, Timeout) -> Req = {transport_accept, self(), ListenFd, Flags}, gen_server:call(ServerName, Req, Timeout).%%%% ssl_accept(ListenFd, Flags) -> {ok, Fd, ProxyLLPort} |%% {error, Reason}%%ssl_accept(ListenFd, Flags) -> ssl_accept(ListenFd, Flags, infinity).ssl_accept(ListenFd, Flags, Timeout) -> ssl_accept_prim(ssl_server, ListenFd, Flags, Timeout).ssl_accept_prim(ServerName, Fd, Flags, Timeout) -> Req = {ssl_accept, Fd, Flags}, gen_server:call(ServerName, Req, Timeout).%%%% ciphers() -> {ok, Ciphers} %%ciphers() -> gen_server:call(ssl_server, ciphers, infinity).%%%% close(Fd) -> ok%%close(Fd) -> close_prim(ssl_server, Fd).close_prim(ServerName, Fd) -> gen_server:call(ServerName, {close, self(), Fd}, infinity), ok.%%%% connect(LIP, LPort, FIP, FPort, Flags) -> {ok, Fd, ProxyLFPort} |%% {error, Reason}%%connect(LIP, LPort, FIP, FPort, Flags) -> connect(LIP, LPort, FIP, FPort, Flags, infinity).connect(LIP, LPort, FIP, FPort, Flags, Timeout) -> connect_prim(ssl_server, LIP, LPort, FIP, FPort, Flags, Timeout).connect_prim(ServerName, LIP, LPort, FIP, FPort, Flags, Timeout) -> Req = {connect, self(), LIP, LPort, FIP, FPort, Flags}, gen_server:call(ServerName, Req, Timeout).%%%% connection_info(Fd) -> {ok, {Protocol, Cipher}} | {error, Reason}%%connection_info(Fd) -> Req = {connection_info, self(), Fd}, gen_server:call(ssl_server, Req, infinity). %%%% listen(IP, LPort, Flags), %% listen(IP, LPort, Flags, BackLog) -> {ok, ListenFd, LPort0} | %% {error, Reason}%%listen(IP, LPort, Flags) -> listen(IP, LPort, Flags, ?DEF_BACKLOG).listen(IP, LPort, Flags, BackLog) -> listen_prim(ssl_server, IP, LPort, Flags, BackLog).listen_prim(ServerName, IP, LPort, Flags, BackLog) -> Req = {listen, self(), IP, LPort, Flags, BackLog}, gen_server:call(ServerName, Req, infinity).%%%% peercert(Fd) -> {ok, Cert} | {error, Reason}%%peercert(Fd) -> Req = {peercert, self(), Fd}, gen_server:call(ssl_server, Req, infinity).%%%% peername(Fd) -> {ok, {Address, Port}} | {error, Reason}%%peername(Fd) -> peername_prim(ssl_server, Fd).peername_prim(ServerName, Fd) -> Req = {peername, self(), Fd}, gen_server:call(ServerName, Req, infinity).%%%% proxy_join(Fd, LPort) -> ok | {error, Reason}%%proxy_join(Fd, LPort) -> proxy_join_prim(ssl_server, Fd, LPort).proxy_join_prim(ServerName, Fd, LPort) -> Req = {proxy_join, self(), Fd, LPort}, gen_server:call(ServerName, Req, infinity).%%%% seed(Data)%%seed(Data) -> Req = {seed, Data}, gen_server:call(ssl_server, Req, infinity). %%%% set_nodelay(Fd, Boolean)%%setnodelay(Fd, Boolean) -> setnodelay_prim(ssl_server, Fd, Boolean).setnodelay_prim(ServerName, Fd, Boolean) -> Req = {setnodelay, self(), Fd, Boolean}, gen_server:call(ServerName, Req, infinity). %%%% sockname(Fd) -> {ok, {Address, Port}} | {error, Reason}%%sockname(Fd) -> sockname_prim(ssl_server, Fd).sockname_prim(ServerName, Fd) -> Req = {sockname, self(), Fd}, gen_server:call(ServerName, Req, infinity).%%%% version() -> {ok, {CompVsn, LibVsn}} %%version() -> gen_server:call(ssl_server, version, infinity).enable_debug() -> set_debug(true).disable_debug() -> set_debug(false).set_debug(Bool) -> set_debug(Bool, infinity).set_debug(Bool, Timeout) when is_boolean(Bool) -> Req = {set_debug, Bool, self()}, gen_server:call(ssl_server, Req, Timeout). enable_debugmsg() -> set_debugmsg(true).disable_debugmsg() -> set_debugmsg(false).set_debugmsg(Bool) -> set_debugmsg(Bool, infinity).set_debugmsg(Bool, Timeout) when is_boolean(Bool) -> Req = {set_debugmsg, Bool, self()}, gen_server:call(ssl_server, Req, Timeout).dump() -> dump(infinity).dump(Timeout) -> Req = {dump, self()}, gen_server:call(ssl_server, Req, Timeout).%%%% init%%init([]) -> Debug = case application:get_env(ssl, edebug) of {ok, true} -> true; _ -> case application:get_env(ssl, debug) of {ok, true} -> true; _ -> case os:getenv("ERL_SSL_DEBUG") of false -> false; _ -> true end end end, ProgDir = case init:get_argument(ssl_portprogram_dir) of {ok, [[D]]} -> D; _ -> find_priv_bin() end, {Program, Flags} = mk_cmd_line("ssl_esock"), Cmd = filename:join(ProgDir, Program) ++ " " ++ Flags, debug1(Debug, " start, Cmd = ~s~n", [Cmd]), case (catch open_port({spawn, Cmd}, [binary, {packet, 4}])) of Port when port(Port) -> process_flag(trap_exit, true), receive {Port, {data, Bin}} -> {ProxyLLPort, ProgPid, CompVsn, LibVsn, Ciphers} = decode_msg(Bin, [int16, int32, string, string, string]), debug1(Debug, "port program pid = ~w~n", [ProgPid]), {ok, #st{port = Port, proxylsport = ProxyLLPort, progpid = ProgPid, debug = Debug, compvsn = CompVsn, libvsn = LibVsn, ciphers = Ciphers}}; {'EXIT', Port, Reason} -> {stop, Reason} end; {'EXIT', Reason} -> {stop, Reason} end.%%%% transport_accept%%handle_call({transport_accept, Broker, ListenFd, Flags}, From, St) -> debug(St, "transport_accept: broker = ~w, listenfd = ~w~n", [Broker, ListenFd]), case get_by_fd(ListenFd, St#st.cons) of {ok, {ListenFd, _, _}} -> send_cmd(St#st.port, ?TRANSPORT_ACCEPT, [int32(ListenFd), Flags, 0]), PAccepts = add({ListenFd, Broker, From}, St#st.paccepts), %% %% We reply when we get TRANSPORT_ACCEPT_REP or ASYNC_ACCEPT_ERR %% {noreply, St#st{paccepts = PAccepts}}; _Other -> {reply, {error, ebadf}, St} end;%%%% ssl_accept%%handle_call({ssl_accept, Fd, Flags}, From, St) -> case replace_from_by_fd(Fd, St#st.cons, From) of {ok, _, Cons} = _Rep -> send_cmd(St#st.port, ?SSL_ACCEPT, [int32(Fd), Flags, 0]), %% We reply when we get SSL_ACCEPT_REP or ASYNC_ACCEPT_ERR {noreply, St#st{cons = Cons}}; _Other -> {reply, {error, ebadf}, St} end;%%%% version%%handle_call(ciphers, From, St) -> debug(St, "ciphers: from = ~w~n", [From]), {reply, {ok, St#st.ciphers}, St};%%%% connect%%handle_call({connect, Broker, LIP, LPort, FIP, FPort, Flags}, From, St) -> debug(St, "connect: broker = ~w, ip = ~w, " "sport = ~w~n", [Broker, FIP, FPort]), Port = St#st.port, LIPStr = ip_to_string(LIP), FIPStr = ip_to_string(FIP), IntRef = new_intref(St), send_cmd(Port, ?CONNECT, [int32(IntRef), int16(LPort), LIPStr, 0, int16(FPort), FIPStr, 0, Flags, 0]), Cons = add({{intref, IntRef}, Broker, From}, St#st.cons), %% We reply when we have got CONNECT_SYNC_ERR, or CONNECT_WAIT %% and CONNECT_REP, or CONNECT_ERR. {noreply, St#st{cons = Cons, intref = IntRef}};%%%% connection_info%%handle_call({connection_info, Broker, Fd}, From, St) -> debug(St, "connection_info: broker = ~w, fd = ~w~n", [Broker, Fd]), case replace_from_by_fd(Fd, St#st.cons, From) of {ok, _, Cons} -> send_cmd(St#st.port, ?GETCONNINFO, [int32(Fd)]), %% We reply when we get GETCONNINFO_REP or GETCONNINFO_ERR. {noreply, St#st{cons = Cons}}; _Other -> {reply, {error, ebadf}, St} end;%%%% close%%handle_call({close, Broker, Fd}, _From, St) -> debug(St, "close: broker = ~w, fd = ~w~n", [Broker, Fd]), #st{port = Port, cons = Cons0, paccepts = PAccepts0} = St, case delete_by_fd(Fd, Cons0) of %% Must match Broker pid; fd may be reused already. {ok, {Fd, Broker, _}, Cons} -> send_cmd(Port, ?CLOSE, int32(Fd)), %% If Fd is a listen socket fd, there might be pending %% accepts for that fd. case delete_all_by_fd(Fd, PAccepts0) of {ok, DelAccepts, RemAccepts} -> %% Reply {error, closed} to all pending accepts lists:foreach(fun({_, _, AccFrom}) -> gen_server:reply(AccFrom, {error, closed}) end, DelAccepts), {reply, ok, St#st{cons = Cons, paccepts = RemAccepts}}; _ -> {reply, ok, St#st{cons = Cons}} end; _ -> {reply, ok, St} end;%%%% listen%%handle_call({listen, Broker, IP, LPort, Flags, BackLog}, From, St) -> debug(St, "listen: broker = ~w, IP = ~w, " "sport = ~w~n", [Broker, IP, LPort]), Port = St#st.port, IPStr = ip_to_string(IP), IntRef = new_intref(St), send_cmd(Port, ?LISTEN, [int32(IntRef), int16(LPort), IPStr, 0, int16(BackLog), Flags, 0]), Cons = add({{intref, IntRef}, Broker, From}, St#st.cons), %% We reply when we have got LISTEN_REP. {noreply, St#st{cons = Cons, intref = IntRef}};%%%% peercert%%handle_call({peercert, Broker, Fd}, From, St) -> debug(St, "peercert: broker = ~w, fd = ~w~n", [Broker, Fd]), case replace_from_by_fd(Fd, St#st.cons, From) of {ok, _, Cons} -> send_cmd(St#st.port, ?GETPEERCERT, [int32(Fd)]), %% We reply when we get GETPEERCERT_REP or GETPEERCERT_ERR. {noreply, St#st{cons = Cons}}; _Other -> {reply, {error, ebadf}, St} end;%%%% peername%%handle_call({peername, Broker, Fd}, From, St) -> debug(St, "peername: broker = ~w, fd = ~w~n", [Broker, Fd]), case replace_from_by_fd(Fd, St#st.cons, From) of {ok, _, Cons} -> send_cmd(St#st.port, ?GETPEERNAME, [int32(Fd)]), %% We reply when we get GETPEERNAME_REP or GETPEERNAME_ERR. {noreply, St#st{cons = Cons}}; _Other -> {reply, {error, ebadf}, St} end;%%%% proxy join%%handle_call({proxy_join, Broker, Fd, LPort}, From, St) -> debug(St, "proxy_join: broker = ~w, fd = ~w, " "sport = ~w~n", [Broker, Fd, LPort]), case replace_from_by_fd(Fd, St#st.cons, From) of {ok, _, Cons} -> send_cmd(St#st.port, ?PROXY_JOIN, [int32(Fd), int16(LPort)]), %% We reply when we get PROXY_JOIN_REP, or PROXY_JOIN_ERR.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?