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