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 + -
显示快捷键?