aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaimo Niskanen <[email protected]>2019-02-08 11:41:27 +0100
committerRaimo Niskanen <[email protected]>2019-02-13 14:18:23 +0100
commit96cd83b6efed8ae8a1a0008e24885bae66c1834b (patch)
tree56097aece57096bf7fc9e0d485ecbe4a5e0b627b
parent38ce21e37be4578a7a89856ddb91516279e58c13 (diff)
downloadotp-96cd83b6efed8ae8a1a0008e24885bae66c1834b.tar.gz
otp-96cd83b6efed8ae8a1a0008e24885bae66c1834b.tar.bz2
otp-96cd83b6efed8ae8a1a0008e24885bae66c1834b.zip
Use iovec() internally in send path
-rw-r--r--lib/ssl/src/ssl.erl4
-rw-r--r--lib/ssl/src/ssl_connection.erl6
-rw-r--r--lib/ssl/src/tls_record.erl78
-rw-r--r--lib/ssl/src/tls_sender.erl34
4 files changed, 70 insertions, 52 deletions
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index a7d6f28c7a..4a6e022661 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -626,7 +626,7 @@ close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}
send(#sslsocket{pid = [Pid]}, Data) when is_pid(Pid) ->
ssl_connection:send(Pid, Data);
send(#sslsocket{pid = [_, Pid]}, Data) when is_pid(Pid) ->
- tls_sender:send_data(Pid, erlang:iolist_to_binary(Data));
+ tls_sender:send_data(Pid, erlang:iolist_to_iovec(Data));
send(#sslsocket{pid = {_, #config{transport_info={_, udp, _, _}}}}, _) ->
{error,enotconn}; %% Emulate connection behaviour
send(#sslsocket{pid = {dtls,_}}, _) ->
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 461f51dd3a..61524347eb 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -211,9 +211,9 @@ socket_control(dtls_connection = Connection, {_, Socket}, [Pid|_] = Pids, Transp
%%--------------------------------------------------------------------
send(Pid, Data) ->
call(Pid, {application_data,
- %% iolist_to_binary should really
- %% be called iodata_to_binary()
- erlang:iolist_to_binary(Data)}).
+ %% iolist_to_iovec should really
+ %% be called iodata_to_iovec()
+ erlang:iolist_to_iovec(Data)}).
%%--------------------------------------------------------------------
-spec recv(pid(), integer(), timeout()) ->
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index e68f9a19df..7d1f2f5e92 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -105,8 +105,8 @@ encode_handshake(Frag, Version,
ConnectionStates) ->
case iolist_size(Frag) of
N when N > ?MAX_PLAIN_TEXT_LENGTH ->
- Data = split_bin(iolist_to_binary(Frag), Version, BCA, BeastMitigation),
- encode_iolist(?HANDSHAKE, Version, Data, ConnectionStates);
+ Data = split_iovec(erlang:iolist_to_iovec(Frag), Version, BCA, BeastMitigation),
+ encode_fragments(?HANDSHAKE, Version, Data, ConnectionStates);
_ ->
encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates)
end.
@@ -137,13 +137,13 @@ encode_change_cipher_spec(Version, ConnectionStates) ->
%%
%% Description: Encodes data to send on the ssl-socket.
%%--------------------------------------------------------------------
-encode_data(Frag, Version,
+encode_data(Data, Version,
#{current_write := #{beast_mitigation := BeastMitigation,
security_parameters :=
#security_parameters{bulk_cipher_algorithm = BCA}}} =
ConnectionStates) ->
- Data = split_bin(Frag, Version, BCA, BeastMitigation),
- encode_iolist(?APPLICATION_DATA, Version, Data, ConnectionStates).
+ Fragments = split_iovec(Data, Version, BCA, BeastMitigation),
+ encode_fragments(?APPLICATION_DATA, Version, Fragments, ConnectionStates).
%%====================================================================
%% Decoding
@@ -520,22 +520,22 @@ binary_from_front(BinSize, [Bin|Front], Size, Rear, Acc) ->
%%--------------------------------------------------------------------
encode_plain_text(Type, Version, Data, ConnectionStates0) ->
- {[CipherText],ConnectionStates} = encode_iolist(Type, Version, [Data], ConnectionStates0),
+ {[CipherText],ConnectionStates} = encode_fragments(Type, Version, [Data], ConnectionStates0),
{CipherText,ConnectionStates}.
%%--------------------------------------------------------------------
-encode_iolist(Type, Version, Data,
+encode_fragments(Type, Version, Data,
#{current_write := #{compression_state := CompS,
cipher_state := CipherS,
sequence_number := Seq}} = ConnectionStates) ->
- encode_iolist(Type, Version, Data, ConnectionStates, CompS, CipherS, Seq, []).
+ encode_fragments(Type, Version, Data, ConnectionStates, CompS, CipherS, Seq, []).
%%
-encode_iolist(_Type, _Version, [], #{current_write := WriteS} = CS,
+encode_fragments(_Type, _Version, [], #{current_write := WriteS} = CS,
CompS, CipherS, Seq, CipherFragments) ->
{lists:reverse(CipherFragments),
CS#{current_write := WriteS#{compression_state := CompS,
cipher_state := CipherS,
sequence_number := Seq}}};
-encode_iolist(Type, Version, [Text|Data],
+encode_fragments(Type, Version, [Text|Data],
#{current_write := #{security_parameters :=
#security_parameters{cipher_type = ?AEAD,
bulk_cipher_algorithm = BCAlg,
@@ -550,9 +550,9 @@ encode_iolist(Type, Version, [Text|Data],
{CipherFragment,CipherS} = ssl_record:cipher_aead(Version, CompText, CipherS1, StartAdditionalData, SecPars),
Length = byte_size(CipherFragment),
CipherHeader = <<?BYTE(Type), VersionBin/binary, ?UINT16(Length)>>,
- encode_iolist(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
+ encode_fragments(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
[[CipherHeader, CipherFragment] | CipherFragments]);
-encode_iolist(Type, Version, [Text|Data],
+encode_fragments(Type, Version, [Text|Data],
#{current_write := #{security_parameters :=
#security_parameters{compression_algorithm = CompAlg,
mac_algorithm = MacAlgorithm} = SecPars,
@@ -564,35 +564,49 @@ encode_iolist(Type, Version, [Text|Data],
Length = byte_size(CipherFragment),
{MajVer, MinVer} = Version,
CipherHeader = <<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>,
- encode_iolist(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
+ encode_fragments(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
[[CipherHeader, CipherFragment] | CipherFragments]);
-encode_iolist(_Type, _Version, _Data, CS, _CompS, _CipherS, _Seq, _CipherFragments) ->
+encode_fragments(_Type, _Version, _Data, CS, _CompS, _CipherS, _Seq, _CipherFragments) ->
exit({cs, CS}).
%%--------------------------------------------------------------------
%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast, RC4 chiphers are
%% not vulnerable to this attack.
-split_bin(<<FirstByte:8, Rest/binary>>, Version, BCA, one_n_minus_one) when
- BCA =/= ?RC4 andalso ({3, 1} == Version orelse
- {3, 0} == Version) ->
- [[FirstByte]|do_split_bin(Rest)];
+split_iovec([<<FirstByte:8, Rest/binary>>|Data], Version, BCA, one_n_minus_one)
+ when (BCA =/= ?RC4) andalso ({3, 1} == Version orelse
+ {3, 0} == Version) ->
+ [[FirstByte]|split_iovec([Rest|Data])];
%% 0/n splitting countermeasure for clients that are incompatible with 1/n-1
%% splitting.
-split_bin(Bin, Version, BCA, zero_n) when
- BCA =/= ?RC4 andalso ({3, 1} == Version orelse
- {3, 0} == Version) ->
- [<<>>|do_split_bin(Bin)];
-split_bin(Bin, _, _, _) ->
- do_split_bin(Bin).
-
-do_split_bin(<<>>) -> [];
-do_split_bin(Bin) ->
+split_iovec(Data, Version, BCA, zero_n)
+ when (BCA =/= ?RC4) andalso ({3, 1} == Version orelse
+ {3, 0} == Version) ->
+ [<<>>|split_iovec(Data)];
+split_iovec(Data, _Version, _BCA, _BeatMitigation) ->
+ split_iovec(Data).
+
+split_iovec([]) ->
+ [];
+split_iovec(Data) ->
+ {Part,Rest} = split_iovec(Data, ?MAX_PLAIN_TEXT_LENGTH, []),
+ [Part|split_iovec(Rest)].
+%%
+split_iovec([Bin|Data], Size, Acc) ->
case Bin of
- <<Chunk:?MAX_PLAIN_TEXT_LENGTH/binary, Rest/binary>> ->
- [Chunk|do_split_bin(Rest)];
- _ ->
- [Bin]
- end.
+ <<Last:Size/binary, Rest/binary>> ->
+ {lists:reverse(Acc, [Last]),
+ case Rest of
+ <<>> ->
+ Data;
+ <<_/binary>> ->
+ [Rest|Data]
+ end};
+ <<_/binary>> ->
+ split_iovec(Data, Size - byte_size(Bin), [Bin|Acc])
+ end;
+split_iovec([], _Size, Acc) ->
+ {lists:reverse(Acc),[]}.
+
%%--------------------------------------------------------------------
lowest_list_protocol_version(Ver, []) ->
Ver;
diff --git a/lib/ssl/src/tls_sender.erl b/lib/ssl/src/tls_sender.erl
index 8ccb8e287f..feda0b8672 100644
--- a/lib/ssl/src/tls_sender.erl
+++ b/lib/ssl/src/tls_sender.erl
@@ -272,7 +272,7 @@ connection({call, From}, {dist_handshake_complete, _Node, DHandle},
[];
Data ->
[{next_event, internal,
- {application_packets,{self(),undefined},Data}}]
+ {application_packets,{self(),undefined},erlang:iolist_to_iovec(Data)}}]
end]};
connection(internal, {application_packets, From, Data}, StateData) ->
send_application_data(Data, From, ?FUNCTION_NAME, StateData);
@@ -294,11 +294,11 @@ connection(info, dist_data, #data{static = #static{dist_handle = DHandle}}) ->
[];
Data ->
[{next_event, internal,
- {application_packets,{self(),undefined},Data}}]
+ {application_packets,{self(),undefined},erlang:iolist_to_iovec(Data)}}]
end};
connection(info, tick, StateData) ->
consume_ticks(),
- Data = <<0:32>>, % encode_packet(4, <<>>)
+ Data = [<<0:32>>], % encode_packet(4, <<>>)
From = {self(), undefined},
send_application_data(Data, From, ?FUNCTION_NAME, StateData);
connection(info, {send, From, Ref, Data}, _StateData) ->
@@ -309,7 +309,7 @@ connection(info, {send, From, Ref, Data}, _StateData) ->
From ! {Ref, ok},
{keep_state_and_data,
[{next_event, {call, {self(), undefined}},
- {application_data, iolist_to_binary(Data)}}]};
+ {application_data, erlang:iolist_to_iovec(Data)}}]};
?HANDLE_COMMON.
%%--------------------------------------------------------------------
@@ -432,9 +432,7 @@ send_application_data(Data, From, StateName,
{next_state, handshake, StateData0,
[{next_event, internal, {application_packets, From, Data}}]};
false ->
- {Msgs, ConnectionStates} =
- Connection:encode_data(
- iolist_to_binary(Data), Version, ConnectionStates0),
+ {Msgs, ConnectionStates} = Connection:encode_data(Data, Version, ConnectionStates0),
StateData = StateData0#data{connection_states = ConnectionStates},
case Connection:send(Transport, Socket, Msgs) of
ok when DistHandle =/= undefined ->
@@ -452,9 +450,9 @@ send_application_data(Data, From, StateName,
encode_packet(Packet, Data) ->
Len = iolist_size(Data),
case Packet of
- 1 when Len < (1 bsl 8) -> [<<Len:8>>,Data];
- 2 when Len < (1 bsl 16) -> [<<Len:16>>,Data];
- 4 when Len < (1 bsl 32) -> [<<Len:32>>,Data];
+ 1 when Len < (1 bsl 8) -> [<<Len:8>>|Data];
+ 2 when Len < (1 bsl 16) -> [<<Len:16>>|Data];
+ 4 when Len < (1 bsl 32) -> [<<Len:32>>|Data];
N when N =:= 1; N =:= 2; N =:= 4 ->
{error,
{badarg, {packet_to_large, Len, (1 bsl (Packet bsl 3)) - 1}}};
@@ -498,11 +496,17 @@ dist_data(DHandle) ->
none ->
erlang:dist_ctrl_get_data_notification(DHandle),
[];
- Data ->
- %% This is encode_packet(4, Data) without Len check
- %% since the emulator will always deliver a Data
- %% smaller than 4 GB, and the distribution will
- %% therefore always have to use {packet,4}
+ %% This is encode_packet(4, Data) without Len check
+ %% since the emulator will always deliver a Data
+ %% smaller than 4 GB, and the distribution will
+ %% therefore always have to use {packet,4}
+ Data when is_binary(Data) ->
+ Len = byte_size(Data),
+ [<<Len:32>>,Data|dist_data(DHandle)];
+ [BA,BB] = Data ->
+ Len = byte_size(BA) + byte_size(BB),
+ [<<Len:32>>,Data|dist_data(DHandle)];
+ Data when is_list(Data) ->
Len = iolist_size(Data),
[<<Len:32>>,Data|dist_data(DHandle)]
end.