Skip to content

Commit

Permalink
Add possibility to use socket directly as tcp backend
Browse files Browse the repository at this point in the history
  • Loading branch information
dgud committed Nov 12, 2024
1 parent 5aa181f commit 8234a06
Show file tree
Hide file tree
Showing 12 changed files with 497 additions and 39 deletions.
1 change: 1 addition & 0 deletions lib/ssl/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ MODULES= \
tls_server_session_ticket_sup\
tls_server_sup\
tls_socket \
tls_socket_tcp \
tls_sup \
tls_v1

Expand Down
1 change: 1 addition & 0 deletions lib/ssl/src/ssl.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
tls_record,
tls_record_1_3,
tls_socket,
tls_socket_tcp,
tls_v1,
tls_connection_sup,
tls_gen_connection,
Expand Down
19 changes: 8 additions & 11 deletions lib/ssl/src/ssl.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2425,7 +2425,7 @@ handshake(Socket, SslOptions, Timeout)
ConnetionCb = connection_cb(SslOptions),
{ok, #config{transport_info = CbInfo, ssl = SslOpts, emulated = EmOpts}} =
handle_options(Transport, Socket, SslOptions, server, undefined),
ok = tls_socket:setopts(Transport, Socket, tls_socket:internal_inet_values()),
ok = tls_socket:setopts(Transport, Socket, tls_socket:internal_inet_values(Transport)),
{ok, Port} = tls_socket:port(Transport, Socket),
{ok, SessionIdHandle} = tls_socket:session_id_tracker(ssl_unknown_listener, SslOpts),
ssl_gen_statem:handshake(ConnetionCb, Port, Socket,
Expand Down Expand Up @@ -3219,12 +3219,14 @@ See `inet:getstat/2` for further details.
Options :: [inet:stat_option()],
OptionValues :: [{inet:stat_option(), integer()}].
%%--------------------------------------------------------------------

getstat(#sslsocket{socket_handle = {Listener, _},
listener_config = #config{transport_info = Info}},
listener_config = #config{transport_info = Info,
connection_cb = dtls_gen_connection}},
Options) when is_list(Options) ->
Transport = element(1, Info),
dtls_socket:getstat(Transport, Listener, Options);
getstat(#sslsocket{socket_handle = Listen,
getstat(#sslsocket{socket_handle = Listen,
listener_config = #config{transport_info = Info}},
Options) when is_list(Options) ->
Transport = element(1, Info),
Expand Down Expand Up @@ -3258,8 +3260,7 @@ To handle siutations where the peer has performed a shutdown on the
write side, option `{exit_on_close, false}` is useful.
""".
%%--------------------------------------------------------------------
shutdown(#sslsocket{listener_config = #config{connection_cb = dtls_gen_connection,
transport_info = Info}}, _) ->
shutdown(#sslsocket{listener_config = #config{transport_info = Info}}, _) ->
Transport = element(1, Info),
%% enotconn is what gen_tcp:shutdown on a listen socket will result with.
%% shutdown really is handling TCP functionality not present
Expand All @@ -3274,11 +3275,6 @@ shutdown(#sslsocket{listener_config = #config{connection_cb = dtls_gen_connectio
_ ->
{error, enotconn}
end;
shutdown(#sslsocket{socket_handle = Listen,
listener_config = #config{connection_cb = tls_gen_connection,
transport_info = Info}}, How) ->
Transport = element(1, Info),
Transport:shutdown(Listen, How);
shutdown(#sslsocket{connection_handler = Controller}, How) when is_pid(Controller) ->
ssl_gen_statem:shutdown(Controller, How).

Expand Down Expand Up @@ -4751,6 +4747,7 @@ set_opt_new(_, _, _, _, Opts) ->
%%%%

default_cb_info(tls) ->
%% tls_socket_tcp:cb_info();
{gen_tcp, tcp, tcp_closed, tcp_error, tcp_passive};
default_cb_info(dtls) ->
{gen_udp, udp, udp_closed, udp_error, udp_passive}.
Expand Down Expand Up @@ -4931,7 +4928,7 @@ tls_validate_version_gap(Versions) ->
Versions
end.

emulated_options(undefined, undefined, Protocol, Opts) ->
emulated_options(undefined, undefined, Protocol, Opts) ->
case Protocol of
tls ->
tls_socket:emulated_options(Opts);
Expand Down
11 changes: 11 additions & 0 deletions lib/ssl/src/ssl_gen_statem.erl
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,17 @@ handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_e
handle_normal_shutdown(Alert#alert{role = Role}, StateName, State),
{stop, {shutdown,normal}, State};

handle_info({ErrorTag, Socket, abort, Reason}, StateName, #state{static_env = #static_env{
role = Role,
socket = Socket,
error_tag = ErrorTag}
} = State) ->
?SSL_LOG(info, "Socket error", [{error_tag, ErrorTag}, {description, Reason}]),
Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, {transport_error, Reason}),
handle_normal_shutdown(Alert#alert{role = Role}, StateName, State),
{stop, {shutdown,normal}, State};


handle_info({'DOWN', MonitorRef, _, _, Reason}, _,
#state{connection_env = #connection_env{user_application = {MonitorRef, _Pid}},
ssl_options = #{erl_dist := true}}) ->
Expand Down
2 changes: 1 addition & 1 deletion lib/ssl/src/ssl_server_session_cache.erl
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,4 @@ monitor_listener(ssl_unknown_listener) ->
%% global process.
undefined;
monitor_listener(Listen) ->
inet:monitor(Listen).
tls_socket:monitor_socket(Listen).
3 changes: 2 additions & 1 deletion lib/ssl/src/tls_dtls_gen_connection.erl
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Trac
protocol_specific = #{sender => Sender,
active_n => ssl_config:get_internal_active_n(
maps:get(erl_dist, SSLOptions, false)),
active_n_toggle => true
active_n_toggle => true,
socket_active => 0
}
}.

Expand Down
39 changes: 28 additions & 11 deletions lib/ssl/src/tls_gen_connection.erl
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,22 @@ gen_info(Event, StateName, State) ->
StateName, State)
end.

%% raw data from socket, upack records
%% socket:socket() have data fetch and unpack records
handle_info({Protocol, Socket, Type, Handle}, StateName,
#state{static_env = #static_env{socket = Socket,
data_tag = Protocol,
transport_cb = Transport},
protocol_specific = #{socket_active := N}=PS}
= State0) ->
Data = Transport:data_available(Socket, Type, Handle, N > 0),
State1 = State0#state{protocol_specific = PS#{socket_active := N-1}},
case next_tls_record(Data, StateName, State1) of
{Record, State} ->
next_event(StateName, Record, State);
#alert{} = Alert ->
ssl_gen_statem:handle_own_alert(Alert, StateName, State0)
end;
%% raw data from (gen_tcp) socket, unpack records
handle_info({Protocol, _, Data}, StateName,
#state{static_env = #static_env{data_tag = Protocol}} = State0) ->
case next_tls_record(Data, StateName, State0) of
Expand All @@ -296,15 +311,15 @@ handle_info({PassiveTag, Socket}, StateName,
#state{static_env = #static_env{socket = Socket, passive_tag = PassiveTag} = StatEnv,
recv = #recv{from = From},
protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs},
protocol_specific = PS
protocol_specific = PS0
} = State0) ->
case (From =/= undefined) andalso (CTs == []) of
true ->
do_activate_socket(PS, StatEnv),
State = State0#state{protocol_specific = PS#{active_n_toggle => false}},
PS = do_activate_socket(PS0, StatEnv),
State = State0#state{protocol_specific = PS},
next_event(StateName, no_record, State);
false ->
State = State0#state{protocol_specific = PS#{active_n_toggle => true}},
State = State0#state{protocol_specific = PS0#{active_n_toggle => true}},
next_event(StateName, no_record, State)
end;
handle_info({CloseTag, Socket}, StateName,
Expand Down Expand Up @@ -734,15 +749,17 @@ activate_socket(#state{protocol_specific = #{active_n_toggle := true} = Protocol
static_env = StatEnv
} = State,
PBuffers) ->
do_activate_socket(ProtocolSpec, StatEnv),
{no_record, State#state{protocol_specific = ProtocolSpec#{active_n_toggle => false},
protocol_buffers = PBuffers}}.
PS = do_activate_socket(ProtocolSpec, StatEnv),
{no_record, State#state{protocol_specific = PS, protocol_buffers = PBuffers}}.

do_activate_socket(#{active_n := N},
do_activate_socket(#{active_n := N} = PS,
#static_env{socket = Socket, close_tag = CloseTag, transport_cb = Transport}) ->
case tls_socket:setopts(Transport, Socket, [{active, N}]) of
ok -> ok;
_ -> self() ! {CloseTag, Socket}
ok ->
PS#{active_n_toggle => false, socket_active => N};
_ ->
self() ! {CloseTag, Socket},
PS#{active_n_toggle => false}
end.

%% Decipher next record and concatenate consecutive ?APPLICATION_DATA records into one
Expand Down
17 changes: 13 additions & 4 deletions lib/ssl/src/tls_record.erl
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ init_connection_states(Role, Version, BeastMitigation, MaxEarlyDataSize) ->

%%--------------------------------------------------------------------
-spec get_tls_records(
binary(),
binary() | [binary()],
[tls_version()] | tls_version(),
Buffer0 :: binary() | {'undefined' | #ssl_tls{}, {[binary()],non_neg_integer(),[binary()]}},
tls_max_frag_len(),
Expand All @@ -115,10 +115,19 @@ init_connection_states(Role, Version, BeastMitigation, MaxEarlyDataSize) ->
%% Description: Given old buffer and new data from TCP, packs up a records
%% data
%%--------------------------------------------------------------------
get_tls_records(Data, Versions, Buffer, MaxFragLen, Downgrade) when is_binary(Buffer) ->
parse_tls_records(Versions, {[Data],byte_size(Data),[]}, MaxFragLen, Downgrade, undefined);
get_tls_records([Data], Versions, {Hdr, {Front,Size,Rear}}, MaxFragLen, Downgrade) ->
parse_tls_records(Versions, {Front,Size + byte_size(Data),[Data|Rear]}, MaxFragLen, Downgrade, Hdr);
get_tls_records(Data, Versions, {Hdr, {Front,Size,Rear}}, MaxFragLen, Downgrade)
when is_list(Data) ->
parse_tls_records(Versions, {Front,Size + iolist_size(Data), Data ++ Rear}, MaxFragLen, Downgrade, Hdr);
get_tls_records(Data, Versions, {Hdr, {Front,Size,Rear}}, MaxFragLen, Downgrade) ->
parse_tls_records(Versions, {Front,Size + byte_size(Data),[Data|Rear]}, MaxFragLen, Downgrade, Hdr).
parse_tls_records(Versions, {Front,Size + byte_size(Data),[Data|Rear]}, MaxFragLen, Downgrade, Hdr);
get_tls_records(Data, Versions, <<>>, MaxFragLen, Downgrade)
when is_list(Data) ->
parse_tls_records(Versions, {[], iolist_size(Data), Data}, MaxFragLen, Downgrade, undefined);
get_tls_records(Data, Versions, <<>>, MaxFragLen, Downgrade) ->
parse_tls_records(Versions, {[Data],byte_size(Data),[]}, MaxFragLen, Downgrade, undefined).


%%====================================================================
%% Encoding
Expand Down
24 changes: 16 additions & 8 deletions lib/ssl/src/tls_socket.erl
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@
peername/2,
sockname/2,
port/2,
close/2]).
close/2,
monitor_socket/1]).

-export([split_options/1,
get_socket_opts/3]).

-export([emulated_options/0,
emulated_options/1,
internal_inet_values/0,
internal_inet_values/1,
default_inet_values/0,
init/1,
start_link/3,
Expand Down Expand Up @@ -78,7 +79,7 @@ send(Transport, Socket, Data) ->
listen(Transport, Port, #config{transport_info = {Transport, _, _, _, _},
inet_user = Options,
ssl = SslOpts, emulated = EmOpts} = Config) ->
case Transport:listen(Port, Options ++ internal_inet_values()) of
case Transport:listen(Port, Options ++ internal_inet_values(Transport)) of
{ok, ListenSocket} ->
{ok, Tracker} = inherit_tracker(ListenSocket, EmOpts, SslOpts),
LifeTime = ssl_config:get_ticket_lifetime(),
Expand Down Expand Up @@ -116,7 +117,7 @@ accept(ListenSocket, #config{transport_info = {Transport,_,_,_,_} = CbInfo,
upgrade(Socket, #config{transport_info = {Transport,_,_,_,_}= CbInfo,
ssl = SslOptions,
emulated = EmOpts, connection_cb = ConnectionCb}, Timeout) ->
ok = setopts(Transport, Socket, tls_socket:internal_inet_values()),
ok = setopts(Transport, Socket, internal_inet_values(Transport)),
case peername(Transport, Socket) of
{ok, {Address, Port}} ->
ssl_gen_statem:connect(ConnectionCb, Address, Port, Socket,
Expand All @@ -132,7 +133,7 @@ connect(Address, Port,
emulated = EmOpts, inet_ssl = SocketOpts, connection_cb = ConnetionCb},
Timeout) ->
{Transport, _, _, _, _} = CbInfo,
try Transport:connect(Address, Port, SocketOpts, Timeout) of
try Transport:connect(Address, Port, SocketOpts ++ internal_inet_values(Transport), Timeout) of
{ok, Socket} ->
ssl_gen_statem:connect(ConnetionCb, Address, Port, Socket,
{SslOpts,
Expand Down Expand Up @@ -249,13 +250,20 @@ close(gen_tcp, Socket) ->
close(Transport, Socket) ->
Transport:close(Socket).

monitor_socket({'$socket', _}=Socket) ->
socket:monitor(Socket);
monitor_socket(InetSocket) ->
inet:monitor(InetSocket).

emulated_options() ->
[mode, packet, active, header, packet_size].

emulated_options(Opts) ->
emulated_options(Opts, internal_inet_values(), default_inet_values()).
emulated_options(Opts, [], default_inet_values()).

internal_inet_values() ->
internal_inet_values(tls_socket_tcp) ->
[];
internal_inet_values(_) ->
[{packet_size,0}, {packet, 0}, {header, 0}, {active, false}, {mode,binary}].

default_inet_values() ->
Expand Down Expand Up @@ -329,7 +337,7 @@ start_link(Port, SockOpts, SslOpts) ->
init([Listen, Opts, SslOpts]) ->
process_flag(trap_exit, true),
proc_lib:set_label({tls_listen_tracker, Listen}),
Monitor = inet:monitor(Listen),
Monitor = monitor_socket(Listen),
{ok, #state{emulated_opts = do_set_emulated_opts(Opts, []),
listen_monitor = Monitor,
ssl_opts = SslOpts}}.
Expand Down
Loading

0 comments on commit 8234a06

Please sign in to comment.