diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 7043c040b1a0..1326e6b111fb 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -2551,9 +2551,19 @@ closed. send(#sslsocket{payload_sender = Sender, connection_cb = dtls_gen_connection}, Data) when is_pid(Sender) -> ssl_gen_statem:send(Sender, Data); -send(#sslsocket{payload_sender = Sender, - connection_cb = tls_gen_connection}, Data) when is_pid(Sender) -> - tls_sender:send_data(Sender, erlang:iolist_to_iovec(Data)); +send(#sslsocket{payload_sender = Sender, tab = Tab, + connection_cb = tls_gen_connection}, Data0) when is_pid(Sender) -> + try + Packet = ets:lookup_element(Tab, {socket_options, packet}, 2), + case encode_packet(Packet, Data0) of + {error, _} = Error -> + Error; + Data -> + tls_sender:send_data(Sender, erlang:iolist_to_iovec(Data)) + end + catch error:badarg -> + {error, closed} + end; send(#sslsocket{listener_config = #config{connection_cb = dtls_gen_connection}}, _) -> {error,enotconn}; %% Emulate connection behaviour send(#sslsocket{socket_handle = ListenSocket, @@ -3130,31 +3140,21 @@ getopts(#sslsocket{}, OptionTags) -> SslSocket :: sslsocket(), Options :: [gen_tcp:option()]. %%-------------------------------------------------------------------- -setopts(#sslsocket{connection_handler = Controller}, [{active, _}] = Active) when is_pid(Controller) -> +setopts(#sslsocket{connection_handler = Controller}, [{active, _}] = Active) + when is_pid(Controller) -> ssl_gen_statem:set_opts(Controller, Active); -setopts(#sslsocket{connection_handler = Controller, payload_sender = Sender, - connection_cb = tls_gen_connection}, Options0) when is_pid(Controller), is_list(Options0) -> - try proplists:expand([{binary, [{mode, binary}]}, - {list, [{mode, list}]}], Options0) of +setopts(#sslsocket{connection_handler = Controller, connection_cb = tls_gen_connection}, Options0) + when is_pid(Controller), is_list(Options0) -> + try proplists:expand([{binary, [{mode, binary}]}, {list, [{mode, list}]}], Options0) of Options -> - case proplists:get_value(packet, Options, undefined) of - undefined -> - ssl_gen_statem:set_opts(Controller, Options); - PacketOpt -> - case tls_sender:setopts(Sender, [{packet, PacketOpt}]) of - ok -> - ssl_gen_statem:set_opts(Controller, Options); - Error -> - Error - end - end + ssl_gen_statem:set_opts(Controller, Options) catch _:_ -> {error, {options, {not_a_proplist, Options0}}} end; -setopts(#sslsocket{connection_handler = Controller}, Options0) when is_pid(Controller), is_list(Options0) -> - try proplists:expand([{binary, [{mode, binary}]}, - {list, [{mode, list}]}], Options0) of +setopts(#sslsocket{connection_handler = Controller}, Options0) + when is_pid(Controller), is_list(Options0) -> + try proplists:expand([{binary, [{mode, binary}]}, {list, [{mode, list}]}], Options0) of Options -> ssl_gen_statem:set_opts(Controller, Options) catch @@ -5229,6 +5229,20 @@ unambiguous_path(Value) -> end, validate_filename(UP, cacertfile). +-compile({inline, encode_packet/2}). +encode_packet(Packet, Data) -> + Len = iolist_size(Data), + case Packet of + 1 when Len < (1 bsl 8) -> [<>|Data]; + 2 when Len < (1 bsl 16) -> [<>|Data]; + 4 when Len < (1 bsl 32) -> [<>|Data]; + N when N =:= 1; N =:= 2; N =:= 4 -> + {error, + {badarg, {packet_to_large, Len, (1 bsl (Packet bsl 3)) - 1}}}; + _ -> + Data + end. + %%%################################################################ %%%# %%%# Tracing diff --git a/lib/ssl/src/ssl_gen_statem.erl b/lib/ssl/src/ssl_gen_statem.erl index 592f785706e8..060b202092bf 100644 --- a/lib/ssl/src/ssl_gen_statem.erl +++ b/lib/ssl/src/ssl_gen_statem.erl @@ -842,9 +842,10 @@ handle_call({set_opts, Opts0}, From, StateName, transport_cb = Transport}, connection_env = #connection_env{user_application = {_Mon, Pid}}, - socket_options = Opts1 + socket_options = Opts1, + tab = Tab } = State0) -> - {Reply, Opts} = set_socket_opts(Connection, Transport, Socket, Opts0, Opts1, []), + {Reply, Opts} = set_socket_opts(Connection, Transport, Socket, Tab, Opts0, Opts1, []), case {proplists:lookup(active, Opts0), Opts} of {{_, N}, #socket_options{active=false}} when is_integer(N) -> send_user(Pid,{ssl_passive,UserSocket}); @@ -1966,9 +1967,9 @@ get_socket_opts(Connection, Transport, Socket, [Tag | Tags], SockOpts, Acc) -> get_socket_opts(_,_, _,Opts, _,_) -> {error, {options, {socket_options, Opts, function_clause}}}. -set_socket_opts(_,_,_, [], SockOpts, []) -> +set_socket_opts(_,_,_, _Tab, [], SockOpts, []) -> {ok, SockOpts}; -set_socket_opts(ConnectionCb, Transport, Socket, [], SockOpts, Other) -> +set_socket_opts(ConnectionCb, Transport, Socket, _Tab, [], SockOpts, Other) -> %% Set non emulated options try ConnectionCb:setopts(Transport, Socket, Other) of ok -> @@ -1981,11 +1982,11 @@ set_socket_opts(ConnectionCb, Transport, Socket, [], SockOpts, Other) -> {{error, {options, {socket_options, Other, Error}}}, SockOpts} end; -set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active}| Opts], SockOpts, Other) +set_socket_opts(ConnectionCb, Transport, Socket, Tab, [{active, Active}| Opts], SockOpts, Other) when Active == once; Active == true; Active == false -> - set_socket_opts(ConnectionCb, Transport, Socket, Opts, + set_socket_opts(ConnectionCb, Transport, Socket, Tab, Opts, SockOpts#socket_options{active = Active}, Other); -set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active1} = Opt| Opts], +set_socket_opts(ConnectionCb, Transport, Socket, Tab, [{active, Active1} = Opt| Opts], SockOpts=#socket_options{active = Active0}, Other) when Active1 >= -32768, Active1 =< 32767 -> Active = if @@ -2006,19 +2007,19 @@ set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active1} = Opt| Opts] error -> {{error, {options, {socket_options, Opt}} }, SockOpts}; _ -> - set_socket_opts(ConnectionCb, Transport, Socket, Opts, + set_socket_opts(ConnectionCb, Transport, Socket, Tab, Opts, SockOpts#socket_options{active = Active}, Other) end; -set_socket_opts(_,_, _, [{active, _} = Opt| _], SockOpts, _) -> +set_socket_opts(_,_, _, _Tab, [{active, _} = Opt| _], SockOpts, _) -> {{error, {options, {socket_options, Opt}} }, SockOpts}; -set_socket_opts(ConnectionCb, Transport,Socket, [{mode, Mode}| Opts], SockOpts, Other) +set_socket_opts(ConnectionCb, Transport, Socket, Tab, [{mode, Mode}| Opts], SockOpts, Other) when Mode == list; Mode == binary -> - set_socket_opts(ConnectionCb, Transport, Socket, Opts, + set_socket_opts(ConnectionCb, Transport, Socket, Tab, Opts, SockOpts#socket_options{mode = Mode}, Other); -set_socket_opts(_, _, _, [{mode, _} = Opt| _], SockOpts, _) -> +set_socket_opts(_, _, _, _Tab, [{mode, _} = Opt| _], SockOpts, _) -> {{error, {options, {socket_options, Opt}}}, SockOpts}; -set_socket_opts(ConnectionCb, Transport,Socket, [{packet, Packet}| Opts], SockOpts, Other) +set_socket_opts(tls_gen_connection, Transport, Socket, Tab, [{packet, Packet}| Opts], SockOpts, Other) when Packet == raw; Packet == 0; Packet == 1; @@ -2034,30 +2035,30 @@ set_socket_opts(ConnectionCb, Transport,Socket, [{packet, Packet}| Opts], SockOp Packet == httph; Packet == http_bin; Packet == httph_bin -> - set_socket_opts(ConnectionCb, Transport, Socket, Opts, + true = ets:insert(Tab, {{socket_options, packet}, Packet}), + set_socket_opts(tls_gen_connection, Transport, Socket, Tab, Opts, SockOpts#socket_options{packet = Packet}, Other); -set_socket_opts(_, _, _, [{packet, _} = Opt| _], SockOpts, _) -> +set_socket_opts(_, _, _, _Tab, [{packet, _} = Opt| _], SockOpts, _) -> {{error, {options, {socket_options, Opt}}}, SockOpts}; -set_socket_opts(ConnectionCb, Transport, Socket, [{header, Header}| Opts], SockOpts, Other) +set_socket_opts(tls_gen_connection, Transport, Socket, Tab, [{header, Header}| Opts], SockOpts, Other) when is_integer(Header) -> - set_socket_opts(ConnectionCb, Transport, Socket, Opts, + set_socket_opts(tls_gen_connection, Transport, Socket, Tab, Opts, SockOpts#socket_options{header = Header}, Other); -set_socket_opts(_, _, _, [{header, _} = Opt| _], SockOpts, _) -> +set_socket_opts(_, _, _, _Tab, [{header, _} = Opt| _], SockOpts, _) -> {{error,{options, {socket_options, Opt}}}, SockOpts}; -set_socket_opts(ConnectionCb, Transport,Socket, [{packet_size, Size}| Opts], SockOpts, Other) when is_integer(Size) -> - set_socket_opts(ConnectionCb, Transport, Socket, Opts, +set_socket_opts(tls_gen_connection, Transport,Socket, Tab, [{packet_size, Size}| Opts], SockOpts, Other) + when is_integer(Size) -> + set_socket_opts(tls_gen_connection, Transport, Socket, Tab, Opts, SockOpts#socket_options{packet_size = Size}, Other); -set_socket_opts(_,_, _, [{packet_size, _} = Opt| _], SockOpts, _) -> +set_socket_opts(_,_, _, _Tab, [{packet_size, _} = Opt| _], SockOpts, _) -> {{error, {options, {socket_options, Opt}} }, SockOpts}; -set_socket_opts(ConnectionCb, Transport, Socket, [Opt | Opts], SockOpts, Other) -> - set_socket_opts(ConnectionCb, Transport, Socket, Opts, SockOpts, [Opt | Other]). +set_socket_opts(ConnectionCb, Transport, Socket, Tab, [Opt | Opts], SockOpts, Other) -> + set_socket_opts(ConnectionCb, Transport, Socket, Tab, Opts, SockOpts, [Opt | Other]). ssl_options_list(SslOptions) -> L = maps:to_list(SslOptions), ssl_options_list(L, []). - - ssl_options_list([], Acc) -> lists:reverse(Acc); %% Skip internal options, only return user options diff --git a/lib/ssl/src/tls_dtls_gen_connection.erl b/lib/ssl/src/tls_dtls_gen_connection.erl index f48014ebb627..0db2638ae8fb 100644 --- a/lib/ssl/src/tls_dtls_gen_connection.erl +++ b/lib/ssl/src/tls_dtls_gen_connection.erl @@ -151,6 +151,8 @@ initial_state(Role, Sender, Tab, Host, Port, Socket, {SSLOptions, SocketOptions, SslSocket = tls_socket:socket([self(),Sender], CbModule, Socket, tls_gen_connection, Tab, Trackers), + true = ets:insert(Tab, {{socket_options, packet}, SocketOptions#socket_options.packet}), + InitStatEnv = #static_env{ role = Role, user_socket = SslSocket, diff --git a/lib/ssl/src/tls_gen_connection_1_3.erl b/lib/ssl/src/tls_gen_connection_1_3.erl index e858307b91de..d787240ebe69 100644 --- a/lib/ssl/src/tls_gen_connection_1_3.erl +++ b/lib/ssl/src/tls_gen_connection_1_3.erl @@ -66,6 +66,8 @@ initial_state(Role, Sender, Tab, Host, Port, Socket, UserMonitor = erlang:monitor(process, User), SslSocket = tls_socket:socket([self(),Sender], CbModule, Socket, tls_gen_connection, Tab, Trackers), + true = ets:insert(Tab, {{socket_options, packet}, SocketOptions#socket_options.packet}), + InitStatEnv = #static_env{ role = Role, user_socket = SslSocket, diff --git a/lib/ssl/src/tls_sender.erl b/lib/ssl/src/tls_sender.erl index e9fcc6dbcd02..65aa46afb677 100644 --- a/lib/ssl/src/tls_sender.erl +++ b/lib/ssl/src/tls_sender.erl @@ -275,15 +275,8 @@ init(_, _, _) -> StateData :: term()) -> gen_statem:event_handler_result(atom()). %%-------------------------------------------------------------------- -connection({call, From}, {application_data, AppData}, - #data{static = #static{socket_options = #socket_options{packet = Packet}}} = - StateData) -> - case encode_packet(Packet, AppData) of - {error, _} = Error -> - {next_state, connection, StateData, [{reply, From, Error}]}; - Data -> - send_application_data(Data, From, connection, StateData) - end; +connection({call, From}, {application_data, Data}, StateData) -> + send_application_data(Data, From, connection, StateData); connection({call, From}, {post_handshake_data, HSData}, StateData) -> send_post_handshake_data(HSData, From, connection, StateData); connection({call, From}, {ack_alert, #alert{} = Alert}, StateData0) -> @@ -611,20 +604,6 @@ key_update_at(?TLS_1_3, _, KeyUpdateAt) -> key_update_at(_, _, KeyUpdateAt) -> KeyUpdateAt. --compile({inline, encode_packet/2}). -encode_packet(Packet, Data) -> - Len = iolist_size(Data), - case Packet of - 1 when Len < (1 bsl 8) -> [<>|Data]; - 2 when Len < (1 bsl 16) -> [<>|Data]; - 4 when Len < (1 bsl 32) -> [<>|Data]; - N when N =:= 1; N =:= 2; N =:= 4 -> - {error, - {badarg, {packet_to_large, Len, (1 bsl (Packet bsl 3)) - 1}}}; - _ -> - Data - end. - set_opts(SocketOptions, [{packet, N}]) -> SocketOptions#socket_options{packet = N}. diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 9eb87700f816..ca9235038993 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -2546,18 +2546,25 @@ client_reject_packet_opt(Config, PacketOpt) -> Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, {from, self()}, - {mfa, {ssl_test_lib, no_result_msg ,[]}}, + {mfa, {ssl_test_lib, no_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client_error([{node, ServerNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {ssl_test_lib, no_result_msg, []}}, - {options, [PacketOpt | - ClientOpts]}]), - - ssl_test_lib:check_result(Client, {error, {options, {not_supported, PacketOpt}}}). + {mfa, {ssl_test_lib, no_result, []}}, + {options, [PacketOpt | ClientOpts]}]), + + ok = ssl_test_lib:check_result(Client, {error, {options, {not_supported, PacketOpt}}}), + Client2 = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl, setopts, [[PacketOpt]]}}, + {options, ClientOpts}]), + ssl_test_lib:check_result(Client2, {error, {options, {socket_options, PacketOpt}}}), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client2). send_switch_packet(SslSocket, Data, NextPacket) -> spawn(fun() -> ssl:send(SslSocket, Data) end),