%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
%%
%% 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 online 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.
%%
%% %CopyrightEnd%
%%
%%
%% Purpose: Primitive interface to SSL, without broker process (used by
%% SSL distribution).
-module(ssl_prim).
-export([listen/2, connect/3, accept/1, close/1, send/2, send/3, recv/2, recv/3,
getll/1, getstat/2, setopts/2, controlling_process/2, peername/1,
sockname/1, getif/1]).
-include("ssl_int.hrl").
-include("ssl_broker_int.hrl").
%-define(filter(Call), filter((catch Call))).
-define(filter(Call), filter(Call)).
listen(Port, Opts) ->
St = newstate(listener),
?filter(ssl_broker:listen_prim(ssl_server_prim, self(), Port, nonactive(Opts), St)).
connect(Address, Port, Opts) ->
St = newstate(connector),
?filter(ssl_broker:connect_prim(ssl_server_prim, inet_tcp, self(), Address,
Port, nonactive(Opts), infinity, St)).
accept(#st{} = ListenSt0) ->
case transport_accept(ListenSt0) of
{ok, ListenSt1} ->
ssl_accept(ListenSt0, ListenSt1);
Error ->
Error
end.
transport_accept(#st{opts = ListenOpts, thissock = ListenSocket}) ->
NewSt = newstate(acceptor),
ListenFd = ListenSocket#sslsocket.fd,
?filter(ssl_broker:transport_accept_prim(ssl_server_prim, ListenFd,
ListenOpts, infinity, NewSt)).
ssl_accept(#st{opts = LOpts}, ListenSt1) ->
?filter(ssl_broker:ssl_accept_prim(ssl_server_prim, gen_tcp, self(),
LOpts, infinity, ListenSt1)).
close(#st{fd = Fd}) when is_integer(Fd) ->
ssl_server:close_prim(ssl_server_prim, Fd),
ok;
close(_) ->
ok.
send(St, Data) ->
send(St, Data, []).
send(#st{proxysock = Proxysock, status = open}, Data, Opts) ->
case inet_tcp:send(Proxysock, Data, Opts) of
ok ->
ok;
{error, _} ->
{error, closed}
end;
send(#st{}, _Data, _Opts) ->
{error, closed}.
recv(St, Length) ->
recv(St, Length, infinity).
recv(#st{proxysock = Proxysock, status = open}, Length, Tmo) ->
inet_tcp:recv(Proxysock, Length, Tmo);
recv(#st{}, _Length, _Tmo) ->
{error, closed}.
getll(#st{proxysock = Proxysock, status = open}) ->
inet:getll(Proxysock);
getll(#st{}) ->
{error, closed}.
getstat(#st{proxysock = Proxysock, status = open}, Opts) ->
inet:getstat(Proxysock, Opts);
getstat(#st{}, _Opts) ->
{error, closed}.
setopts(#st{proxysock = Proxysock, status = open}, Opts) ->
case remove_supported(Opts) of
[] ->
inet:setopts(Proxysock, Opts);
_ ->
{error, enotsup}
end;
setopts(#st{}, _Opts) ->
{error, closed}.
controlling_process(#st{proxysock = Proxysock, status = open}, Pid)
when is_pid(Pid) ->
inet_tcp:controlling_process(Proxysock, Pid);
controlling_process(#st{}, Pid) when is_pid(Pid) ->
{error, closed}.
peername(#st{fd = Fd, status = open}) ->
case ssl_server:peername_prim(ssl_server_prim, Fd) of
{ok, {Address, Port}} ->
{ok, At} = inet_parse:ipv4_address(Address),
{ok, {At, Port}};
Error ->
Error
end;
peername(#st{}) ->
{error, closed}.
sockname(#st{fd = Fd, status = open}) ->
case ssl_server:sockname_prim(ssl_server_prim, Fd) of
{ok, {Address, Port}} ->
{ok, At} = inet_parse:ipv4_address(Address),
{ok, {At, Port}};
Error ->
Error
end;
sockname(#st{}) ->
{error, closed}.
getif(#st{proxysock = Proxysock, status = open}) ->
inet:getif(Proxysock);
getif(#st{}) ->
{error, closed}.
remove_supported([{active, _}|T]) ->
remove_supported(T);
remove_supported([{packet,_}|T]) ->
remove_supported(T);
remove_supported([{deliver,_}|T]) ->
remove_supported(T);
remove_supported([H|T]) ->
[H | remove_supported(T)];
remove_supported([]) ->
[].
filter(Result) ->
case Result of
{ok, _Sock,St} ->
{ok, St};
{error, Reason, _St} ->
{error,Reason}
end.
nonactive([{active,_}|T]) ->
nonactive(T);
nonactive([H|T]) ->
[H | nonactive(T)];
nonactive([]) ->
[{active, false}].
newstate(Type) ->
#st{brokertype = Type, server = whereis(ssl_server_prim),
client = undefined, collector = undefined, debug = false}.