ssl_broker.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,206 行 · 第 1/3 页

ERL
1,206
字号
%% ``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 broker-module(ssl_broker).-behaviour(gen_server).%% This module implements brokers for ssl. A broker is either a connector, %% an acceptor, or a listener. All brokers are children to ssl_broker_sup,%% to which they are linked. Each broker is also linked to ssl_server, and%% to its client.%%%% The purpose of the broker is to set up SSL connections through calls to%% ssl_server and gen_tcp. All control information goes to the server,%% while all data is exchanged directly between gen_tcp and the port program%% of the ssl_server.%%%% A broker is created by a call to start_broker/3 (do *not* use start_link/4%% - it is for ssl_broker_sup to call that one), and then call listen/3, %% accept/4, or connect/5. %%%% The following table shows all functions dependency on status, active %% mode etc.%%%% Permitted status transitions: %%%%		nil	->	open %%		open	->	closing | closed (termination)%%		closing	->	closed (termination)%%%% We are rather sloppy about nil, and consider open/closing == !closed,%% open/closing/closed === any  etc.%%%%%%	function/	 valid			mode		new%%	message		 status					state%%								%%	calls							%%	-----							%%	recv		 open			passive		ditto%%	send		 open			any		ditto%%	transport_accept nil			any		open%%      ssl_accept       nil                    any             open%%	connect		 nil			any		open%%	listen		 nil			any		open%%	peername	 open/closing		any		ditto%%	setopts		 open/closing		any		ditto%%	getopts		 open/closing		any		ditto%%	sockname	 open/closing		any		ditto%%	peercert	 open/closing		any		ditto%%	inhibit		 any			any		ditto%%	release		 any			any		ditto%%	close		 any			any		closed (1)%%%%	info							%%	----							%%	tcp		 open			active		ditto%%	tcp_closed	 open | closing		active		closing%%	tcp_error	 open | closing		active		closing%%%%	(1) We just terminate.%%%% TODO%%%% XXX Timeouts are not checked (integer or infinity).%%%% XXX The collector thing is not gen_server compliant.%%%% NOTE: There are three different "modes": (a) passive or active mode,%% specified as {active, bool()}, and (b) list or binary mode, specified %% as {mode, list | binary}, and (c) encrypted or clear mode%%-include("ssl_int.hrl").%% External exports -export([start_broker/1, start_broker/2, start_link/3,	 transport_accept/3, ssl_accept/2,	 close/1, connect/5, connection_info/1, controlling_process/2,	 listen/3, recv/3, send/2, getopts/2, getopts/3, setopts/2,	 sockname/1, peername/1, peercert/1]).-export([listen_prim/5, connect_prim/8,	 transport_accept_prim/5, ssl_accept_prim/6]).%% Internal exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2,	 code_change/3, terminate/2, collector_init/1]).-include("ssl_broker_int.hrl").%% start_broker(Type) -> {ok, Pid} | {error, Reason}%% start_broker(Type, GenOpts) -> {ok, Pid} | {error, Reason}%%            Type = accept | connect | listen%%            GenOpts = /standard gen_server options/%%%% This is the function to be called from the interface module ssl.erl.%% Links to the caller.%%start_broker(Type) ->    start_broker(Type, []).start_broker(Type, GenOpts) ->    case lists:member(Type, [listener, acceptor, connector]) of	true ->	    case supervisor:start_child(ssl_broker_sup, 					[self(), Type, GenOpts]) of		{ok, Pid} ->		    link(Pid),		    {ok, Pid};		{error, Reason} ->		    {error, Reason}	    end;	false  ->	    {error, ebrokertype}    end.%% start_link(Client, Type, GenOpts) -> {ok, Pid} | {error, Reason}%%	      %%	Type = accept | connect | listen%%	GenOpts = /standard gen_server options/%%%% This function is called by ssl_broker_sup and must *not* be called%% from an interface module (ssl.erl).start_link(Client, Type, GenOpts) ->    gen_server:start_link(?MODULE, [Client, Type], GenOpts).%% accept(Pid, ListenSocket, Timeout) -> {ok, Socket} | %% 						  {error, Reason}%%  %% Types:   Pid = pid() of acceptor%%          ListenSocket = Socket = sslsocket()%% 	    Timeout = integer() | infinity%%%% accept(Pid, ListenSocket, Timeout) %%   when is_pid(Pid), is_record(ListenSocket, sslsocket) ->%%     Req = {accept, self(), ListenSocket, Timeout},%%     gen_server:call(Pid, Req, infinity).%% transport_accept(Pid, ListenSocket, Timeout) -> {ok, Socket} | %% 						   {error, Reason}%%  %% Types:   Pid = pid() of acceptor%%          ListenSocket = Socket = sslsocket()%% 	    Timeout = integer() | infinity%%transport_accept(Pid, ListenSocket, Timeout)   when is_pid(Pid), is_record(ListenSocket, sslsocket) ->     Req = {transport_accept, self(), ListenSocket, Timeout},     gen_server:call(Pid, Req, infinity).%% ssl_accept(Pid, Socket, Timeout) -> {ok, Socket} | %%				       {error, Reason}%%%% Types:   Pid = pid() of acceptor%%          ListenSocket = Socket = sslsocket()%% 	    Timeout = integer() | infinity%%ssl_accept(Socket, Timeout)   when is_record(Socket, sslsocket) ->    Req = {ssl_accept, self(), Socket, Timeout},    gen_server:call(Socket#sslsocket.pid, Req, infinity).%% close(Socket) -> ok | {error, Reason}%%  %% Types:   Socket = sslsocket() | pid()%%close(Socket) when is_record(Socket, sslsocket) ->    close(Socket#sslsocket.pid);close(Pid) when is_pid(Pid) ->    gen_server:call(Pid, {close, self()}, infinity).%% connect(Pid, Address, Port, Opts, Timeout) -> {ok, Socket} | %%						    {error, Reason}%%  %% Types:   Pid = pid() of connector%%          Address  = string() | {byte(), byte(), byte(), byte()}%%          Port = int()%%          Opts = options()%% 	    Timeout = integer() | infinity%%          Socket = sslsocket()%%connect(Pid, Address, Port, Opts, Timeout) when is_pid(Pid), is_list(Opts) ->    case are_connect_opts(Opts) of	true ->	    Req = {connect, self(), Address, Port, Opts, Timeout},	    gen_server:call(Pid, Req, infinity);	false  ->	    {error, eoptions}    end.%%%% connection_info(Socket) -> {ok, {Protocol, Cipher} | {error, Reason}%%connection_info(Socket) when is_record(Socket, sslsocket) ->    Req = {connection_info, self()},    gen_server:call(Socket#sslsocket.pid, Req, infinity).%% controlling_process(Socket, NewOwner) -> ok | {error, Reason}controlling_process(Socket, NewOwner)   when is_record(Socket, sslsocket), is_pid(NewOwner) ->    Pid = Socket#sslsocket.pid,     case gen_server:call(Pid, {inhibit_msgs, self()}, infinity) of	ok ->	    transfer_messages(Pid, NewOwner),	    gen_server:call(Pid, {release_msgs, self(), NewOwner}, infinity);	Error ->	    Error    end.%% listen(Pid, Port, Opts) -> {ok, ListenSocket} | {error, Reason}%%  %% Types:   Pid = pid() of listener%%          Port = int()%%          Opts = options()%%          ListenSocket = sslsocket()%%listen(Pid, Port, Opts) when is_pid(Pid) ->    case are_listen_opts(Opts) of	true ->	    Req = {listen, self(), Port, Opts}, 	    gen_server:call(Pid, Req, infinity);	false  ->	    {error, eoptions}    end.%%%% peername(Socket) -> {ok, {Address, Port}} | {error, Reason}%%peername(Socket) when is_record(Socket, sslsocket) ->    Req = {peername, self()},    gen_server:call(Socket#sslsocket.pid, Req, infinity).%% recv(Socket, Length, Timeout) -> {ok, Data} | {error, Reason}%%%% Types:   Socket = sslsocket()%%          Length = Timeout = integer()%%          Data = bytes() | binary()%%recv(Socket, Length, Timeout) when is_record(Socket, sslsocket) ->    Req = {recv, self(), Length, Timeout},     gen_server:call(Socket#sslsocket.pid, Req, infinity).%% send(Socket, Data) -> ok | {error, Reason}%%  %% Types:   Socket = sslsocket()%%send(Socket, Data) when is_record(Socket, sslsocket) ->    gen_server:call(Socket#sslsocket.pid, {send, self(), Data}, infinity).%% getopts(Socket, OptTags) -> {ok, Opts} | {error, einval}%%  %% Types:	Pid = pid() of broker%%  		Timeout = integer() >= 0 | infinity%%		OptTags = option_tags()%%		Opts = options()%%getopts(Socket, OptTags) ->    getopts(Socket, OptTags, infinity).getopts(Socket, OptTags, Timeout) when is_record(Socket, sslsocket), 				       is_list(OptTags) ->    Req = {getopts, self(), OptTags},     gen_server:call(Socket#sslsocket.pid, Req, Timeout).%%%% setopts(Socket, Opts) -> ok | {error, Reason}%%setopts(Socket, Opts) when is_record(Socket, sslsocket) ->    Req = {setopts, self(), Opts},    gen_server:call(Socket#sslsocket.pid, Req, infinity).%%%% sockname(Socket) -> {ok, {Address, Port}} | {error, Reason}%%sockname(Socket) when is_record(Socket, sslsocket) ->    Req = {sockname, self()},    gen_server:call(Socket#sslsocket.pid, Req, infinity).%%%% peercert(Socket) -> {ok, Cert} | {error, Reason}%%peercert(Socket) when is_record(Socket, sslsocket) ->    Req = {peercert, self()},    gen_server:call(Socket#sslsocket.pid, Req, infinity).%%%%  INIT%%%% init%%init([Client, Type]) ->    process_flag(trap_exit, true),    link(Client),    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,    Server = whereis(ssl_server),    if 	pid(Server) ->	    link(Server),	    debug1(Debug, Type, "in start, client = ~w", [Client]),	    {ok, #st{brokertype = Type, server = Server, client = Client,		     collector = Client, debug = Debug}};		   true  ->			  {stop, no_ssl_server}		  end.%%%% HANDLE CALL%%%% recv - passive mode%%handle_call({recv, Client, Length, Timeout}, _From, St)   when St#st.active == false ->    debug(St, "recv: client = ~w~n", [Client]),    if 	St#st.status =/= open -> 	    {reply, {error, closed}, St};	true ->	    case gen_tcp:recv(St#st.proxysock, Length, Timeout) of		{ok, Data} ->		    {reply, {ok, Data}, St};		{error, timeout} ->		    {reply, {error, timeout}, St};		{error, Reason} ->		    {reply, {error, Reason}, St#st{status = closing}}	    end    end;%% send%% handle_call({send, Client, Data}, _From, St) ->    debug(St, "send: client = ~w~n", [Client]),    if 	St#st.status =/= open -> 	    {reply, {error, closed}, St};	true ->	    case gen_tcp:send(St#st.proxysock, Data) of		ok ->		    {reply, ok, St};		{error, _Reason} ->		    {reply, {error, closed}, St#st{status = closing}}	    end    end;%% transport_accept %% %% Client = pid of client %% ListenSocket = sslsocket()%%handle_call({transport_accept, Client, ListenSocket, Timeout}, _From, St) ->    debug(St, "transport_accept: client = ~w, listensocket = ~w~n", 	  [Client, ListenSocket]),    case getopts(ListenSocket, tcp_listen_opt_tags(), ?DEF_TIMEOUT) of 	{ok, LOpts} ->	    case transport_accept_prim(		   ssl_server, ListenSocket#sslsocket.fd, LOpts, Timeout, St) of		{ok, ThisSocket, NSt} ->

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?