aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/kernel/src/kernel.erl2
-rw-r--r--lib/ssl/doc/src/notes.xml34
-rw-r--r--lib/ssl/src/dtls_connection.erl8
-rw-r--r--lib/ssl/src/ssl_connection.erl2
-rw-r--r--lib/ssl/src/ssl_handshake.erl4
-rw-r--r--lib/ssl/src/tls_connection.erl103
-rw-r--r--lib/ssl/src/tls_connection_1_3.erl35
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl157
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml2
-rw-r--r--lib/tools/doc/src/notes.xml15
-rw-r--r--lib/tools/src/cover.erl40
-rw-r--r--lib/tools/test/cover_SUITE.erl27
-rw-r--r--lib/xmerl/doc/src/notes.xml17
-rw-r--r--lib/xmerl/src/xmerl_sax_parser.erl12
15 files changed, 365 insertions, 95 deletions
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index bfa091a036..bc4f09a023 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -116,7 +116,7 @@ init([]) ->
restart => temporary,
shutdown => 2000,
type => supervisor,
- modules => [user_sup]},
+ modules => [standard_error]},
User = #{id => user,
start => {user_sup, start, []},
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 5fdcf15b5f..01cd630668 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -27,6 +27,23 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 9.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Missing check of size of user_data_buffer made internal
+ socket behave as an active socket instead of active N.
+ This could cause memory problems.</p>
+ <p>
+ Own Id: OTP-15825 Aux Id: ERL-934, OTP-15823 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 9.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -102,6 +119,23 @@
</section>
+<section><title>SSL 9.2.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct solution for retaining tcp flow control OTP-15802
+ (ERL-934) as to not break ssl:recv as reported in
+ (ERL-938)</p>
+ <p>
+ Own Id: OTP-15823 Aux Id: ERL-934, ERL-938 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 9.2.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index e070006900..6928d7a93d 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -51,7 +51,7 @@
-export([encode_alert/3, send_alert/2, send_alert_in_connection/2, close/5, protocol_name/0]).
%% Data handling
--export([next_record/1, socket/4, setopts/3, getopts/3]).
+-export([socket/4, setopts/3, getopts/3]).
%% gen_statem state functions
-export([init/3, error/3, downgrade/3, %% Initiation and take down states
@@ -451,11 +451,11 @@ init({call, From}, {start, Timeout},
HelloVersion = dtls_record:hello_version(Version, SslOpts#ssl_options.versions),
State1 = prepare_flight(State0#state{connection_env = CEnv#connection_env{negotiated_version = Version}}),
{State2, Actions} = send_handshake(Hello, State1#state{connection_env = CEnv#connection_env{negotiated_version = HelloVersion}}),
- State3 = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version}, %% RequestedVersion
+ State = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version}, %% RequestedVersion
session =
Session0#session{session_id = Hello#client_hello.session_id},
start_or_recv_from = From},
- next_event(hello, no_record, State3, [{{timeout, handshake}, Timeout, close} | Actions]);
+ next_event(hello, no_record, State, [{{timeout, handshake}, Timeout, close} | Actions]);
init({call, _} = Type, Event, #state{static_env = #static_env{role = server},
protocol_specific = PS} = State) ->
Result = gen_handshake(?FUNCTION_NAME, Type, Event,
@@ -514,7 +514,7 @@ hello(internal, #client_hello{cookie = <<>>,
VerifyRequest = dtls_handshake:hello_verify_request(Cookie, ?HELLO_VERIFY_REQUEST_VERSION),
State1 = prepare_flight(State0#state{connection_env = CEnv#connection_env{negotiated_version = Version}}),
{State, Actions} = send_handshake(VerifyRequest, State1),
- next_event(?FUNCTION_NAME, no_record,
+ next_event(?FUNCTION_NAME, no_record,
State#state{handshake_env = HsEnv#handshake_env{
tls_handshake_history =
ssl_handshake:init_handshake_history()}},
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index a5f754d2e3..345db7510f 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1194,7 +1194,7 @@ cipher(internal, #next_protocol{selected_protocol = SelectedProtocol},
#state{static_env = #static_env{role = server},
handshake_env = #handshake_env{expecting_finished = true,
expecting_next_protocol_negotiation = true} = HsEnv} = State, Connection) ->
- Connection:next_event(?FUNCTION_NAME, no_record,
+ Connection:next_event(?FUNCTION_NAME, no_record,
State#state{handshake_env = HsEnv#handshake_env{negotiated_protocol = SelectedProtocol,
expecting_next_protocol_negotiation = false}});
cipher(internal, #change_cipher_spec{type = <<1>>}, #state{handshake_env = HsEnv, connection_states = ConnectionStates0} =
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 7b34991f4f..f68d3e9b26 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -98,8 +98,8 @@ hello_request() ->
#hello_request{}.
%%--------------------------------------------------------------------
--spec server_hello(binary(), ssl_record:ssl_version(), ssl_record:connection_states(),
- Extension::map()) -> #server_hello{}.
+%%-spec server_hello(binary(), ssl_record:ssl_version(), ssl_record:connection_states(),
+%% Extension::map()) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index a05858221a..61281a3fb2 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -62,7 +62,7 @@
close/5, protocol_name/0]).
%% Data handling
--export([next_record/1, socket/4, setopts/3, getopts/3]).
+-export([socket/4, setopts/3, getopts/3]).
%% gen_statem state functions
-export([init/3, error/3, downgrade/3, %% Initiation and take down states
@@ -161,32 +161,60 @@ pids(#state{protocol_specific = #{sender := Sender}}) ->
%%====================================================================
%% State transition handling
%%====================================================================
-next_record(#state{handshake_env =
+next_record(_, #state{handshake_env =
#handshake_env{unprocessed_handshake_events = N} = HsEnv}
= State) when N > 0 ->
{no_record, State#state{handshake_env =
HsEnv#handshake_env{unprocessed_handshake_events = N-1}}};
-next_record(#state{protocol_buffers =
- #protocol_buffers{tls_cipher_texts = [_|_] = CipherTexts},
- connection_states = ConnectionStates,
- ssl_options = #ssl_options{padding_check = Check}} = State) ->
+next_record(_, #state{protocol_buffers =
+ #protocol_buffers{tls_cipher_texts = [_|_] = CipherTexts},
+ connection_states = ConnectionStates,
+ ssl_options = #ssl_options{padding_check = Check}} = State) ->
next_record(State, CipherTexts, ConnectionStates, Check);
-next_record(#state{protocol_buffers = #protocol_buffers{tls_cipher_texts = []},
- protocol_specific = #{active_n_toggle := true, active_n := N} = ProtocolSpec,
- static_env = #static_env{socket = Socket,
- close_tag = CloseTag,
- transport_cb = Transport}
- } = State) ->
- case tls_socket:setopts(Transport, Socket, [{active, N}]) of
- ok ->
- {no_record, State#state{protocol_specific = ProtocolSpec#{active_n_toggle => false}}};
- _ ->
- self() ! {CloseTag, Socket},
- {no_record, State}
- end;
-next_record(State) ->
+next_record(connection, #state{protocol_buffers = #protocol_buffers{tls_cipher_texts = []},
+ protocol_specific = #{active_n_toggle := true}
+ } = State) ->
+ %% If ssl application user is not reading data wait to activate socket
+ flow_ctrl(State);
+
+next_record(_, #state{protocol_buffers = #protocol_buffers{tls_cipher_texts = []},
+ protocol_specific = #{active_n_toggle := true}
+ } = State) ->
+ activate_socket(State);
+next_record(_, State) ->
{no_record, State}.
+
+flow_ctrl(#state{user_data_buffer = {_,Size,_},
+ socket_options = #socket_options{active = false},
+ bytes_to_read = undefined} = State) when Size =/= 0 ->
+ {no_record, State};
+flow_ctrl(#state{user_data_buffer = {_,Size,_},
+ socket_options = #socket_options{active = false},
+ bytes_to_read = 0} = State) when Size =/= 0 ->
+ {no_record, State};
+flow_ctrl(#state{user_data_buffer = {_,Size,_},
+ socket_options = #socket_options{active = false},
+ bytes_to_read = BytesToRead} = State) when (Size >= BytesToRead) andalso
+ (BytesToRead > 0) ->
+ {no_record, State};
+flow_ctrl(State) ->
+ activate_socket(State).
+
+
+activate_socket(#state{protocol_specific = #{active_n_toggle := true, active_n := N} = ProtocolSpec,
+ static_env = #static_env{socket = Socket,
+ close_tag = CloseTag,
+ transport_cb = Transport}
+ } = State) ->
+ case tls_socket:setopts(Transport, Socket, [{active, N}]) of
+ ok ->
+ {no_record, State#state{protocol_specific = ProtocolSpec#{active_n_toggle => false}}};
+ _ ->
+ self() ! {CloseTag, Socket},
+ {no_record, State}
+ end.
+
%% Decipher next record and concatenate consecutive ?APPLICATION_DATA records into one
%%
next_record(State, CipherTexts, ConnectionStates, Check) ->
@@ -224,31 +252,20 @@ next_record_done(#state{protocol_buffers = Buffers} = State, CipherTexts, Connec
State#state{protocol_buffers = Buffers#protocol_buffers{tls_cipher_texts = CipherTexts},
connection_states = ConnectionStates}}.
-
next_event(StateName, Record, State) ->
next_event(StateName, Record, State, []).
%%
next_event(StateName, no_record, State0, Actions) ->
- case next_record(State0) of
+ case next_record(StateName, State0) of
{no_record, State} ->
{next_state, StateName, State, Actions};
- {#ssl_tls{} = Record, State} ->
- {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
- #alert{} = Alert ->
- Version = State0#state.connection_env#connection_env.negotiated_version,
- ssl_connection:handle_own_alert(Alert, Version, StateName, State0)
+ {Record, State} ->
+ next_event(StateName, Record, State, Actions)
end;
-next_event(StateName, Record, State, Actions) ->
- case Record of
- no_record ->
- {next_state, StateName, State, Actions};
- #ssl_tls{} = Record ->
- {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
- #alert{} = Alert ->
- Version = State#state.connection_env#connection_env.negotiated_version,
- ssl_connection:handle_own_alert(Alert, Version, StateName, State)
- end.
-
+next_event(StateName, #ssl_tls{} = Record, State, Actions) ->
+ {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
+next_event(StateName, #alert{} = Alert, State, Actions) ->
+ {next_state, StateName, State, [{next_event, internal, Alert} | Actions]}.
%%% TLS record protocol level application data messages
handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName,
@@ -272,12 +289,8 @@ handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, Stat
{stop, _, _} = Stop->
Stop;
{Record, State1} ->
- case next_event(StateName, Record, State1) of
- {next_state, StateName, State, Actions} ->
- ssl_connection:hibernate_after(StateName, State, Actions);
- {stop, _, _} = Stop ->
- Stop
- end
+ {next_state, StateName, State, Actions} = next_event(StateName, Record, State1),
+ ssl_connection:hibernate_after(StateName, State, Actions)
end;
%%% TLS record protocol level handshake messages
handle_protocol_record(#ssl_tls{type = ?HANDSHAKE, fragment = Data},
@@ -1049,7 +1062,7 @@ next_tls_record(Data, StateName,
case tls_record:get_tls_records(Data, Versions, Buf0, SslOpts) of
{Records, Buf1} ->
CT1 = CT0 ++ Records,
- next_record(State0#state{protocol_buffers =
+ next_record(StateName, State0#state{protocol_buffers =
Buffers#protocol_buffers{tls_record_buffer = Buf1,
tls_cipher_texts = CT1}});
#alert{} = Alert ->
diff --git a/lib/ssl/src/tls_connection_1_3.erl b/lib/ssl/src/tls_connection_1_3.erl
index 701a5860c2..76cdebc76f 100644
--- a/lib/ssl/src/tls_connection_1_3.erl
+++ b/lib/ssl/src/tls_connection_1_3.erl
@@ -116,9 +116,8 @@
]).
-start(internal, #change_cipher_spec{}, State0, _Module) ->
- {Record, State} = tls_connection:next_record(State0),
- tls_connection:next_event(?FUNCTION_NAME, Record, State);
+start(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
start(internal, #client_hello{} = Hello, State0, _Module) ->
case tls_handshake_1_3:do_start(Hello, State0) of
#alert{} = Alert ->
@@ -132,9 +131,8 @@ start(Type, Msg, State, Connection) ->
ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
-negotiated(internal, #change_cipher_spec{}, State0, _Module) ->
- {Record, State} = tls_connection:next_record(State0),
- tls_connection:next_event(?FUNCTION_NAME, Record, State);
+negotiated(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
negotiated(internal, Message, State0, _Module) ->
case tls_handshake_1_3:do_negotiated(Message, State0) of
#alert{} = Alert ->
@@ -144,41 +142,36 @@ negotiated(internal, Message, State0, _Module) ->
end.
-wait_cert(internal, #change_cipher_spec{}, State0, _Module) ->
- {Record, State} = tls_connection:next_record(State0),
- tls_connection:next_event(?FUNCTION_NAME, Record, State);
+wait_cert(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
wait_cert(internal,
#certificate_1_3{} = Certificate, State0, _Module) ->
case tls_handshake_1_3:do_wait_cert(Certificate, State0) of
{#alert{} = Alert, State} ->
ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert, State);
- {State1, NextState} ->
- {Record, State} = tls_connection:next_record(State1),
- tls_connection:next_event(NextState, Record, State)
+ {State, NextState} ->
+ tls_connection:next_event(NextState, no_record, State)
end;
wait_cert(Type, Msg, State, Connection) ->
ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
-wait_cv(internal, #change_cipher_spec{}, State0, _Module) ->
- {Record, State} = tls_connection:next_record(State0),
- tls_connection:next_event(?FUNCTION_NAME, Record, State);
+wait_cv(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
wait_cv(internal,
#certificate_verify_1_3{} = CertificateVerify, State0, _Module) ->
case tls_handshake_1_3:do_wait_cv(CertificateVerify, State0) of
{#alert{} = Alert, State} ->
ssl_connection:handle_own_alert(Alert, {3,4}, wait_cv, State);
- {State1, NextState} ->
- {Record, State} = tls_connection:next_record(State1),
- tls_connection:next_event(NextState, Record, State)
+ {State, NextState} ->
+ tls_connection:next_event(NextState, no_record, State)
end;
wait_cv(Type, Msg, State, Connection) ->
ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
-wait_finished(internal, #change_cipher_spec{}, State0, _Module) ->
- {Record, State} = tls_connection:next_record(State0),
- tls_connection:next_event(?FUNCTION_NAME, Record, State);
+wait_finished(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
wait_finished(internal,
#finished{} = Finished, State0, Module) ->
case tls_handshake_1_3:do_wait_finished(Finished, State0) of
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index 27b9c258a0..2d0ffd03d7 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -48,21 +48,27 @@ groups() ->
payload_tests() ->
[server_echos_passive_small,
+ server_echos_passive_chunk_small,
server_echos_active_once_small,
server_echos_active_small,
client_echos_passive_small,
+ client_echos_passive_chunk_small,
client_echos_active_once_small,
client_echos_active_small,
server_echos_passive_big,
+ server_echos_passive_chunk_big,
server_echos_active_once_big,
server_echos_active_big,
client_echos_passive_big,
+ client_echos_passive_chunk_big,
client_echos_active_once_big,
client_echos_active_big,
server_echos_passive_huge,
+ server_echos_passive_chunk_huge,
server_echos_active_once_huge,
server_echos_active_huge,
client_echos_passive_huge,
+ client_echos_passive_chunk_huge,
client_echos_active_once_huge,
client_echos_active_huge,
client_active_once_server_close].
@@ -109,9 +115,11 @@ end_per_group(GroupName, Config) ->
init_per_testcase(TestCase, Config)
when TestCase == server_echos_passive_huge;
+ TestCase == server_echos_passive_chunk_huge;
TestCase == server_echos_active_once_huge;
TestCase == server_echos_active_huge;
TestCase == client_echos_passive_huge;
+ TestCase == client_echos_passive_chunk_huge;
TestCase == client_echos_active_once_huge;
TestCase == client_echos_active_huge ->
case erlang:system_info(system_architecture) of
@@ -124,9 +132,11 @@ init_per_testcase(TestCase, Config)
init_per_testcase(TestCase, Config)
when TestCase == server_echos_passive_big;
+ TestCase == server_echos_passive_chunk_big;
TestCase == server_echos_active_once_big;
TestCase == server_echos_active_big;
TestCase == client_echos_passive_big;
+ TestCase == client_echos_passive_chunk_big;
TestCase == client_echos_active_once_big;
TestCase == client_echos_active_big ->
ct:timetrap({seconds, 60}),
@@ -157,6 +167,22 @@ server_echos_passive_small(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
+server_echos_passive_chunk_small() ->
+ [{doc, "Client sends 1000 bytes in passive mode to server, that receives them in chunks, "
+ "sends them back, and closes."}].
+
+server_echos_passive_chunk_small(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ server_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+
+%%--------------------------------------------------------------------
+
server_echos_active_once_small() ->
[{doc, "Client sends 1000 bytes in active once mode to server, that receives "
" them, sends them back, and closes."}].
@@ -200,6 +226,21 @@ client_echos_passive_small(Config) when is_list(Config) ->
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
+client_echos_passive_chunk__small() ->
+ [{doc, "Server sends 1000 bytes in passive mode to client, that receives them in chunks, "
+ "sends them back, and closes."}].
+
+client_echos_passive_chunk_small(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ client_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+
+%%--------------------------------------------------------------------
client_echos_active_once_small() ->
["Server sends 1000 bytes in active once mode to client, that receives "
"them, sends them back, and closes."].
@@ -241,6 +282,19 @@ server_echos_passive_big(Config) when is_list(Config) ->
Data = binary:copy(<<"1234567890">>, 5000),
server_echos_passive(
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+%%--------------------------------------------------------------------
+server_echos_passive_chunk_big() ->
+ [{doc, "Client sends 50000 bytes to server in passive mode, that receives them, "
+ "sends them back, and closes."}].
+
+server_echos_passive_chunk_big(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ server_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
@@ -286,6 +340,22 @@ client_echos_passive_big(Config) when is_list(Config) ->
client_echos_passive(
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+%%--------------------------------------------------------------------
+client_echos_passive_chunk_big() ->
+ [{doc, "Server sends 50000 bytes to client in passive mode, that receives them, "
+ "sends them back, and closes."}].
+
+client_echos_passive_chunk_big(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ client_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+
%%--------------------------------------------------------------------
client_echos_active_once_big() ->
[{doc, "Server sends 50000 bytes to client in active once mode, that receives"
@@ -329,6 +399,20 @@ server_echos_passive_huge(Config) when is_list(Config) ->
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
+server_echos_passive_chunk_huge() ->
+ [{doc, "Client sends 500000 bytes to server in passive mode, that receives "
+ " them, sends them back, and closes."}].
+
+server_echos_passive_chunk_huge(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ server_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+%%--------------------------------------------------------------------
server_echos_active_once_huge() ->
[{doc, "Client sends 500000 bytes to server in active once mode, that receives "
"them, sends them back, and closes."}].
@@ -369,7 +453,19 @@ client_echos_passive_huge(Config) when is_list(Config) ->
Data = binary:copy(<<"1234567890">>, 50000),
client_echos_passive(
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+%%--------------------------------------------------------------------
+client_echos_passive_chunk_huge() ->
+ [{doc, "Server sends 500000 bytes to client in passive mode, that receives "
+ "them, sends them back, and closes."}].
+client_echos_passive_chunk_huge(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ client_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_active_once_huge() ->
[{doc, "Server sends 500000 bytes to client in active once mode, that receives "
@@ -442,6 +538,28 @@ server_echos_passive(
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+server_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, echoer_chunk, [Length]}},
+ {options, [{active, false}, {mode, binary} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, sender, [Data]}},
+ {options, [{active, false}, {mode, binary} | ClientOpts]}]),
+ %%
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ %%
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
server_echos_active_once(
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
@@ -513,6 +631,31 @@ client_echos_passive(
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+client_echos_passive_chunk(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, sender, [Data]}},
+ {options, [{active, false}, {mode, binary} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, echoer_chunk, [Length]}},
+ {options, [{active, false}, {mode, binary} | ClientOpts]}]),
+ %%
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ %%
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
client_echos_active_once(
Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
Length = byte_size(Data),
@@ -615,6 +758,10 @@ echoer(Socket, Size) ->
ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
echo_recv(Socket, Size * 100).
+echoer_chunk(Socket, Size) ->
+ ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ echo_recv_chunk(Socket, Size, Size * 100).
+
echoer_active_once(Socket, Size) ->
ct:log("Echoer active once: ~p~n", [ssl:getopts(Socket, [active])]),
echo_active_once(Socket, Size * 100).
@@ -632,6 +779,16 @@ echo_recv(Socket, Size) ->
ok = ssl:send(Socket, Data),
echo_recv(Socket, Size - byte_size(Data)).
+
+%% Receive Size bytes
+echo_recv_chunk(_Socket, _, 0) ->
+ ok;
+echo_recv_chunk(Socket, ChunkSize, Size) ->
+ {ok, Data} = ssl:recv(Socket, ChunkSize),
+ ok = ssl:send(Socket, Data),
+ echo_recv_chunk(Socket, ChunkSize, Size - ChunkSize).
+
+
%% Receive Size bytes
echo_active_once(_Socket, 0) ->
ok;
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 3c66ffd852..cbc32cd5a8 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 9.3
+SSL_VSN = 9.3.1
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index 6f6849a19d..ef548ad643 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -40,7 +40,7 @@
<p>
This reference manual describes types generated from the types
in the <c>gen_statem</c> source code, so they are correct.
- However, the generated descriptions also reflect the type hiearchy,
+ However, the generated descriptions also reflect the type hierarchy,
which makes them kind of hard to read.
</p>
<p>
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index fd41e2cbeb..000c6e1ce7 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -74,6 +74,21 @@
</section>
+<section><title>Tools 3.1.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p><c>cover</c> would fail to start if two processes
+ tried to start it at the exact same time.</p>
+ <p>
+ Own Id: OTP-15813 Aux Id: ERL-943 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index 8fe866cb69..2b3af417b6 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -196,6 +196,8 @@ start() ->
receive
{?SERVER,started} ->
{ok,Pid};
+ {?SERVER,{error,Error}} ->
+ {error,Error};
{'DOWN', Ref, _Type, _Object, Info} ->
{error,Info}
end,
@@ -645,19 +647,31 @@ remote_reply(MainNode,Reply) ->
%%%----------------------------------------------------------------------
init_main(Starter) ->
- register(?SERVER,self()),
- ?COVER_MAPPING_TABLE = ets:new(?COVER_MAPPING_TABLE,
- [ordered_set, public, named_table]),
- ?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
- named_table]),
- ?BINARY_TABLE = ets:new(?BINARY_TABLE, [set, public, named_table]),
- ?COLLECTION_TABLE = ets:new(?COLLECTION_TABLE, [set, public,
- named_table]),
- ?COLLECTION_CLAUSE_TABLE = ets:new(?COLLECTION_CLAUSE_TABLE, [set, public,
- named_table]),
- ok = net_kernel:monitor_nodes(true),
- Starter ! {?SERVER,started},
- main_process_loop(#main_state{}).
+ try register(?SERVER,self()) of
+ true ->
+ ?COVER_MAPPING_TABLE = ets:new(?COVER_MAPPING_TABLE,
+ [ordered_set, public, named_table]),
+ ?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
+ named_table]),
+ ?BINARY_TABLE = ets:new(?BINARY_TABLE, [set, public, named_table]),
+ ?COLLECTION_TABLE = ets:new(?COLLECTION_TABLE, [set, public,
+ named_table]),
+ ?COLLECTION_CLAUSE_TABLE = ets:new(?COLLECTION_CLAUSE_TABLE,
+ [set, public, named_table]),
+ ok = net_kernel:monitor_nodes(true),
+ Starter ! {?SERVER,started},
+ main_process_loop(#main_state{})
+ catch
+ error:badarg ->
+ %% The server's already registered; either report that it's already
+ %% started or try again if it died before we could find its pid.
+ case whereis(?SERVER) of
+ undefined ->
+ init_main(Starter);
+ Pid ->
+ Starter ! {?SERVER, {error, {already_started, Pid}}}
+ end
+ end.
main_process_loop(State) ->
receive
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index ee58fd7a10..462767f430 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -37,7 +37,7 @@ all() ->
dont_reconnect_after_stop, stop_node_after_disconnect,
export_import, otp_5031, otp_6115,
otp_8270, otp_10979_hanging_node, otp_14817,
- local_only],
+ local_only, startup_race],
case whereis(cover_server) of
undefined ->
[coverage,StartStop ++ NoStartStop];
@@ -1775,7 +1775,32 @@ local_only(Config) ->
{ok,Name} = test_server:start_node(?FUNCTION_NAME, slave, []),
{error,local_only} = cover:start([Name]),
test_server:stop_node(Name),
+ ok.
+%% ERL-943; We should not crash on startup when multiple servers race to
+%% register the server name.
+startup_race(Config) when is_list(Config) ->
+ PidRefs = [spawn_monitor(fun() ->
+ case cover:start() of
+ {error, {already_started, _Pid}} ->
+ ok;
+ {ok, _Pid} ->
+ ok
+ end
+ end) || _<- lists:seq(1,8)],
+ startup_race_1(PidRefs).
+
+startup_race_1([{Pid, Ref} | PidRefs]) ->
+ receive
+ {'DOWN', Ref, process, Pid, normal} ->
+ startup_race_1(PidRefs);
+ {'DOWN', Ref, process, Pid, _Other} ->
+ ct:fail("Cover server crashed on startup.")
+ after 5000 ->
+ ct:fail("Timed out.")
+ end;
+startup_race_1([]) ->
+ cover:stop(),
ok.
%%--Auxiliary------------------------------------------------------------
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index 37973d0dba..9fb4a430e5 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -47,6 +47,23 @@
</section>
+<section><title>Xmerl 1.3.20.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ <c>xmerl_sax_parser</c> crashed during charset detection
+ when the xml declarations attribute values was missing
+ the closing quotation (&apos; or &quot;).</p>
+ <p>
+ Own Id: OTP-15826</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.20</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/xmerl/src/xmerl_sax_parser.erl b/lib/xmerl/src/xmerl_sax_parser.erl
index fe836fd8cd..2767d02552 100644
--- a/lib/xmerl/src/xmerl_sax_parser.erl
+++ b/lib/xmerl/src/xmerl_sax_parser.erl
@@ -369,8 +369,8 @@ parse_eq(_, State) ->
%%----------------------------------------------------------------------
parse_value(<<C, Rest/binary>>, State) when ?is_whitespace(C) ->
parse_value(Rest, State);
-parse_value(<<C, Rest/binary>>, _State) when C == $'; C == $" ->
- parse_value_1(Rest, C, []);
+parse_value(<<C, Rest/binary>>, State) when C == $'; C == $" ->
+ parse_value_1(Rest, C, [], State);
parse_value(_, State) ->
?fatal_error(State, "\', \" or whitespace expected").
@@ -383,10 +383,12 @@ parse_value(_, State) ->
%% Rest = binary()
%% Description: Parsing an attribute value from the stream.
%%----------------------------------------------------------------------
-parse_value_1(<<Stop, Rest/binary>>, Stop, Acc) ->
+parse_value_1(<<Stop, Rest/binary>>, Stop, Acc, _State) ->
{lists:reverse(Acc), Rest};
-parse_value_1(<<C, Rest/binary>>, Stop, Acc) ->
- parse_value_1(Rest, Stop, [C |Acc]).
+parse_value_1(<<C, Rest/binary>>, Stop, Acc, State) ->
+ parse_value_1(Rest, Stop, [C |Acc], State);
+parse_value_1(_, _Stop, _Acc, State) ->
+ ?fatal_error(State, "end of input and no \' or \" found").
%%======================================================================
%% Default functions