aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/edoc/src/edoc_lib.erl43
-rw-r--r--lib/inets/doc/src/notes.xml83
-rw-r--r--lib/inets/src/http_lib/http_chunk.erl10
-rw-r--r--lib/inets/src/inets_app/inets.appup.src14
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/odbc/c_src/odbcserver.c4
-rw-r--r--lib/odbc/src/odbc.appup.src4
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/public_key/src/public_key.appup.src26
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/ssl/doc/src/ssl.xml7
-rw-r--r--lib/ssl/src/ssl.appup.src2
-rw-r--r--lib/ssl/src/ssl.erl11
-rw-r--r--lib/ssl/src/ssl_connection.erl88
-rw-r--r--lib/ssl/src/ssl_internal.hrl6
-rw-r--r--lib/ssl/test/Makefile3
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl44
-rw-r--r--lib/ssl/test/ssl_test_lib.erl12
-rw-r--r--lib/ssl/vsn.mk3
19 files changed, 274 insertions, 92 deletions
diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl
index c1f95a7a67..6705ccd356 100644
--- a/lib/edoc/src/edoc_lib.erl
+++ b/lib/edoc/src/edoc_lib.erl
@@ -16,7 +16,6 @@
%%
%% $Id$
%%
-%% @private
%% @copyright 2001-2003 Richard Carlsson
%% @author Richard Carlsson <[email protected]>
%% @see edoc
@@ -49,14 +48,17 @@
%% ---------------------------------------------------------------------
%% List and string utilities
+%% @private
timestr({H,M,Sec}) ->
lists:flatten(io_lib:fwrite("~2.2.0w:~2.2.0w:~2.2.0w",[H,M,Sec])).
+%% @private
datestr({Y,M,D}) ->
Ms = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"],
lists:flatten(io_lib:fwrite("~s ~w ~w",[lists:nth(M, Ms),D,Y])).
+%% @private
count(X, Xs) ->
count(X, Xs, 0).
@@ -67,6 +69,7 @@ count(X, [_ | Xs], N) ->
count(_X, [], N) ->
N.
+%% @private
lines(Cs) ->
lines(Cs, [], []).
@@ -77,6 +80,7 @@ lines([C | Cs], As, Ls) ->
lines([], As, Ls) ->
lists:reverse([lists:reverse(As) | Ls]).
+%% @private
split_at(Cs, K) ->
split_at(Cs, K, []).
@@ -87,6 +91,7 @@ split_at([C | Cs], K, As) ->
split_at([], _K, As) ->
{lists:reverse(As), []}.
+%% @private
split_at_stop(Cs) ->
split_at_stop(Cs, []).
@@ -103,6 +108,7 @@ split_at_stop([C | Cs], As) ->
split_at_stop([], As) ->
{lists:reverse(As), []}.
+%% @private
split_at_space(Cs) ->
split_at_space(Cs, []).
@@ -117,17 +123,20 @@ split_at_space([C | Cs], As) ->
split_at_space([], As) ->
{lists:reverse(As), []}.
+%% @private
is_space([$\s | Cs]) -> is_space(Cs);
is_space([$\t | Cs]) -> is_space(Cs);
is_space([$\n | Cs]) -> is_space(Cs);
is_space([_C | _Cs]) -> false;
is_space([]) -> true.
+%% @private
strip_space([$\s | Cs]) -> strip_space(Cs);
strip_space([$\t | Cs]) -> strip_space(Cs);
strip_space([$\n | Cs]) -> strip_space(Cs);
strip_space(Cs) -> Cs.
+%% @private
segment(Es, N) ->
segment(Es, [], [], 0, N).
@@ -140,6 +149,7 @@ segment([], [], Cs, _N, _M) ->
segment([], As, Cs, _N, _M) ->
lists:reverse([lists:reverse(As) | Cs]).
+%% @private
transpose([]) -> [];
transpose([[] | Xss]) -> transpose(Xss);
transpose([[X | Xs] | Xss]) ->
@@ -151,6 +161,7 @@ transpose([[X | Xs] | Xss]) ->
%% end of the summary sentence only if it is also the last segment in
%% the list, or is followed by a 'p' or 'br' ("whitespace") element.
+%% @private
get_first_sentence([#xmlElement{name = p, content = Es} | _]) ->
%% Descend into initial paragraph.
get_first_sentence_1(Es);
@@ -230,6 +241,7 @@ end_of_sentence_1(_, false, _) ->
%% Names must begin with a lowercase letter and contain only
%% alphanumerics and underscores.
+%% @private
is_name([C | Cs]) when C >= $a, C =< $z ->
is_name_1(Cs);
is_name([C | Cs]) when C >= $\337, C =< $\377, C =/= $\367 ->
@@ -252,6 +264,7 @@ is_name_1(_) -> false.
to_atom(A) when is_atom(A) -> A;
to_atom(S) when is_list(S) -> list_to_atom(S).
+%% @private
unique([X | Xs]) -> [X | unique(Xs, X)];
unique([]) -> [].
@@ -267,6 +280,7 @@ unique([], _) -> [].
%% content of <a href="overview-summary.html#ftag-equiv">`@equiv'</a>
%% tags, and strings denoting file names, e.g. in @headerfile. Also used
%% by {@link edoc_run}.
+%% @private
parse_expr(S, L) ->
case erl_scan:string(S ++ ".", L) of
@@ -287,10 +301,11 @@ parse_expr(S, L) ->
%% @doc EDoc "contact information" parsing. This is the type of the
%% content in e.g.
%% <a href="overview-summary.html#mtag-author">`@author'</a> tags.
+%% @private
-%% @type info() = #info{name = string(),
-%% email = string(),
-%% uri = string()}
+%% % @type info() = #info{name = string(),
+%% % email = string(),
+%% % uri = string()}
-record(info, {name = "" :: string(),
email = "" :: string(),
@@ -367,6 +382,7 @@ strip_and_reverse(As) ->
%%
%% TODO: general utf-8 encoding for all of Unicode (0-16#10ffff)
+%% @private
escape_uri([C | Cs]) when C >= $a, C =< $z ->
[C | escape_uri(Cs)];
escape_uri([C | Cs]) when C >= $A, C =< $Z ->
@@ -409,6 +425,7 @@ hex_octet(N) ->
%% Please note that URI are *not* file names. Don't use the stdlib
%% 'filename' module for operations on (any parts of) URI.
+%% @private
join_uri(Base, "") ->
Base;
join_uri("", Path) ->
@@ -418,6 +435,7 @@ join_uri(Base, Path) ->
%% Check for relative URI; "network paths" ("//...") not included!
+%% @private
is_relative_uri([$: | _]) ->
false;
is_relative_uri([$/, $/ | _]) ->
@@ -433,6 +451,7 @@ is_relative_uri([_ | Cs]) ->
is_relative_uri([]) ->
true.
+%% @private
uri_get("file:///" ++ Path) ->
uri_get_file(Path);
uri_get("file://localhost/" ++ Path) ->
@@ -532,6 +551,7 @@ uri_get_ftp(URI) ->
Msg = io_lib:format("cannot access ftp scheme yet: '~s'.", [URI]),
{error, Msg}.
+%% @private
to_label([$\s | Cs]) ->
to_label(Cs);
to_label([$\t | Cs]) ->
@@ -564,6 +584,7 @@ to_label_2(Cs) ->
%% ---------------------------------------------------------------------
%% Files
+%% @private
filename([C | T]) when is_integer(C), C > 0 ->
[C | filename(T)];
filename([H|T]) ->
@@ -576,6 +597,7 @@ filename(N) ->
report("bad filename: `~P'.", [N, 25]),
exit(error).
+%% @private
copy_file(From, To) ->
case file:copy(From, To) of
{ok, _} -> ok;
@@ -600,6 +622,7 @@ list_dir(Dir, Error) ->
F("could not read directory '~s': ~s.", [filename(Dir), R1])
end.
+%% @private
simplify_path(P) ->
case filename:basename(P) of
"." ->
@@ -636,6 +659,7 @@ simplify_path(P) ->
%% exit(error)
%% end.
+%% @private
try_subdir(Dir, Subdir) ->
D = filename:join(Dir, Subdir),
case filelib:is_dir(D) of
@@ -648,6 +672,7 @@ try_subdir(Dir, Subdir) ->
%%
%% @doc Write the given `Text' to the file named by `Name' in directory
%% `Dir'. If the target directory does not exist, it will be created.
+%% @private
write_file(Text, Dir, Name) ->
write_file(Text, Dir, Name, '').
@@ -657,6 +682,7 @@ write_file(Text, Dir, Name) ->
%% Name::edoc:filename(), Package::atom()|string()) -> ok
%% @doc Like {@link write_file/3}, but adds path components to the target
%% directory corresponding to the specified package.
+%% @private
write_file(Text, Dir, Name, Package) ->
Dir1 = filename:join([Dir | packages:split(Package)]),
@@ -672,6 +698,7 @@ write_file(Text, Dir, Name, Package) ->
exit(error)
end.
+%% @private
write_info_file(App, Packages, Modules, Dir) ->
Ts = [{packages, Packages},
{modules, Modules}],
@@ -703,6 +730,7 @@ info_file_data(Ts) ->
%% Local file access - don't complain if file does not exist.
+%% @private
read_info_file(Dir) ->
File = filename:join(Dir, ?INFO_FILE),
case filelib:is_file(File) of
@@ -769,11 +797,13 @@ parse_terms_1([], _As, _Vs) ->
%% ---------------------------------------------------------------------
%% Source files and packages
+%% @private
find_sources(Path, Opts) ->
find_sources(Path, "", Opts).
%% @doc See {@link edoc:run/3} for a description of the options
%% `subpackages', `source_suffix' and `exclude_packages'.
+%% @private
%% NEW-OPTIONS: subpackages, source_suffix, exclude_packages
%% DEFER-OPTIONS: edoc:run/3
@@ -827,6 +857,7 @@ is_package_dir(Name, Dir) ->
is_name(filename:rootname(filename:basename(Name)))
andalso filelib:is_dir(filename:join(Dir, Name)).
+%% @private
find_file([P | Ps], Pkg, Name) ->
Dir = filename:join(P, filename:join(packages:split(Pkg))),
File = filename:join(Dir, Name),
@@ -839,6 +870,7 @@ find_file([P | Ps], Pkg, Name) ->
find_file([], _Pkg, _Name) ->
"".
+%% @private
find_doc_dirs() ->
find_doc_dirs(code:get_path()).
@@ -904,6 +936,7 @@ add_new(K, V, D) ->
%% @spec (Options::proplist()) -> edoc_env()
%% @equiv get_doc_env([], [], [], Opts)
+%% @private
get_doc_env(Opts) ->
get_doc_env([], [], [], Opts).
@@ -952,6 +985,7 @@ get_doc_env(App, Packages, Modules, Opts) ->
%% NEW-OPTIONS: doclet
%% DEFER-OPTIONS: edoc:run/3
+%% @private
run_doclet(Fun, Opts) ->
run_plugin(doclet, ?DEFAULT_DOCLET, Fun, Opts).
@@ -961,6 +995,7 @@ run_doclet(Fun, Opts) ->
%% NEW-OPTIONS: layout
%% DEFER-OPTIONS: edoc:layout/2
+%% @private
run_layout(Fun, Opts) ->
run_plugin(layout, ?DEFAULT_LAYOUT, Fun, Opts).
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 11b0af4310..5da9d98002 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2002</year><year>2010</year>
+ <year>2002</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,50 +32,78 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 5.5.1</title>
+ <section><title>Inets 5.5.2</title>
- <section><title>Fixed Bugs and Malfunctions</title>
+ <section><title>Improvements and New Features</title>
+ <p>-</p>
+
+<!--
<list>
<item>
- <p> Fix format_man_pages so it handles all man sections
- and remove warnings/errors in various man pages. </p>
<p>
- Own Id: OTP-8600</p>
+ Miscellaneous inet6 related problems.</p>
+ <p>Own Id: OTP-8927</p>
</item>
+ </list>
+-->
+
+ </section>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
<item>
- <p>
- [httpc] Pipelined and queued requests not processed when
- connection closed remotelly.</p>
- <p>
- Own Id: OTP-8906</p>
+ <p>[httpd] httpd_response:send_chunk handles empty list and
+ empty binary - i.e. no chunk is sent, but it does
+ not handle a list with an empty binary [&lt;&lt;&gt;&gt;].
+ This will be sent as an empty chunk - which in turn
+ will be encoded by http_chunk to the same as a final
+ chunk, which will make the http client believe that
+ the end of the page is reached.</p>
+ <p>Own Id: OTP-8906</p>
</item>
</list>
</section>
+ </section> <!-- 5.5.2 -->
+
+
+ <section><title>Inets 5.5.1</title>
<section><title>Improvements and New Features</title>
<list>
<item>
- <p>
- Miscellaneous inet6 related problems.</p>
- <p>
- Own Id: OTP-8927</p>
+ <p>Miscellaneous inet6 related problems.</p>
+ <p>Own Id: OTP-8927</p>
</item>
<item>
- <p>
- Updated http-server to make sure URLs in error-messages
- are URL-encoded. Added support in http-client to use
- URL-encoding. Also added the missing include directory
- for the inets application.</p>
- <p>
- Own Id: OTP-8940 Aux Id: seq11735 </p>
+ <p>Updated http-server to make sure URLs in error-messages
+ are URL-encoded. Added support in http-client to use
+ URL-encoding. Also added the missing include directory
+ for the inets application.</p>
+ <p>Own Id: OTP-8940 Aux Id: seq11735 </p>
</item>
</list>
</section>
-</section>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fix format_man_pages so it handles all man sections
+ and remove warnings/errors in various man pages. </p>
+ <p>Own Id: OTP-8600</p>
+ </item>
+ <item>
+ <p>[httpc] Pipelined and queued requests not processed when
+ connection closed remotelly.</p>
+ <p>Own Id: OTP-8906</p>
+ </item>
+ </list>
+ </section>
-<section><title>Inets 5.5</title>
+ </section> <!-- 5.5.1 -->
+
+
+ <section><title>Inets 5.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -120,9 +148,10 @@
</list>
</section>
-</section>
+ </section> <!-- 5.5 -->
+
-<section><title>Inets 5.4</title>
+ <section><title>Inets 5.4</title>
<section><title>Improvements and New Features</title>
<!--
diff --git a/lib/inets/src/http_lib/http_chunk.erl b/lib/inets/src/http_lib/http_chunk.erl
index 621bc68eae..57647438e9 100644
--- a/lib/inets/src/http_lib/http_chunk.erl
+++ b/lib/inets/src/http_lib/http_chunk.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2011. 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
@@ -17,7 +17,8 @@
%% %CopyrightEnd%
%%
%% Description: Implements chunked transfer encoding see RFC2616 section
-%% 3.6.1
+%% 3.6.1
+
-module(http_chunk).
-include("http_internal.hrl").
@@ -28,6 +29,7 @@
%% little at a time on a socket.
-export([decode_size/1, ignore_extensions/1, decode_data/1, decode_trailer/1]).
+
%%%=========================================================================
%%% API
%%%=========================================================================
@@ -81,6 +83,9 @@ encode(Chunk) when is_binary(Chunk)->
HEXSize = list_to_binary(http_util:integer_to_hexlist(size(Chunk))),
<<HEXSize/binary, ?CR, ?LF, Chunk/binary, ?CR, ?LF>>;
+encode([<<>>]) ->
+ [];
+
encode(Chunk) when is_list(Chunk)->
HEXSize = http_util:integer_to_hexlist(erlang:iolist_size(Chunk)),
[HEXSize, ?CR, ?LF, Chunk, ?CR, ?LF].
@@ -88,6 +93,7 @@ encode(Chunk) when is_list(Chunk)->
encode_last() ->
<<$0, ?CR, ?LF, ?CR, ?LF >>.
+
%%-------------------------------------------------------------------------
%% handle_headers(HeaderRecord, ChunkedHeaders) -> NewHeaderRecord
%%
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 0194c65db9..07da8ca961 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -1,7 +1,7 @@
%% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2011. 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
@@ -18,6 +18,11 @@
{"%VSN%",
[
+ {"5.5.1",
+ [
+ {load_module, http_chunk, soft_purge, soft_purge, []}
+ ]
+ },
{"5.5",
[
{restart_application, inets}
@@ -30,7 +35,12 @@
}
],
[
- {"5.4",
+ {"5.5.1",
+ [
+ {load_module, http_chunk, soft_purge, soft_purge, []}
+ ]
+ },
+ {"5.5",
[
{restart_application, inets}
]
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 67737ee552..b1de3fef43 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2010. All Rights Reserved.
+# Copyright Ericsson AB 2001-2011. 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
diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c
index 077d78bfe5..d61ce940c3 100644
--- a/lib/odbc/c_src/odbcserver.c
+++ b/lib/odbc/c_src/odbcserver.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2010. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2011. 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
@@ -472,7 +472,7 @@ static db_result_msg db_connect(byte *args, db_state *state)
&stringlength2ptr, SQL_DRIVER_NOPROMPT);
if (!sql_success(result)) {
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
+ diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state));
strcat((char *)diagnos.error_msg,
" Connection to database failed.");
msg = encode_error_message(diagnos.error_msg);
diff --git a/lib/odbc/src/odbc.appup.src b/lib/odbc/src/odbc.appup.src
index f1a370d925..2a6667ccd3 100644
--- a/lib/odbc/src/odbc.appup.src
+++ b/lib/odbc/src/odbc.appup.src
@@ -1,8 +1,8 @@
%% -*- erlang -*-
{"%VSN%",
[
- {"2.10.8", [{restart_application, ssl}]}
+ {"2.10.9", [{restart_application, ssl}]}
],
[
- {"2.10.8", [{restart_application, ssl}]}
+ {"2.10.9", [{restart_application, ssl}]}
]}.
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index aacf3924db..42a51be33e 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1 +1 @@
-ODBC_VSN = 2.10.9
+ODBC_VSN = 2.10.10
diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src
index 6b6b76d0a5..c65ac7bc99 100644
--- a/lib/public_key/src/public_key.appup.src
+++ b/lib/public_key/src/public_key.appup.src
@@ -1,6 +1,13 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"0.10",
+ [
+ {update, public_key, soft, soft_purge, soft_purge, []},
+ {update, pubkey_pem, soft, soft_purge, soft_purge, []},
+ {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"0.9",
[
{update, public_key, soft, soft_purge, soft_purge, []},
@@ -18,12 +25,19 @@
}
],
[
- {"0.9",
- [
+ {"0.10",
+ [
+ {update, public_key, soft, soft_purge, soft_purge, []},
+ {update, pubkey_pem, soft, soft_purge, soft_purge, []},
+ {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"0.9",
+ [
{update, public_key, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert, soft, soft_purge, soft_purge, []}
- ]
- },
+ {update, pubkey_cert, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"0.8",
[
{update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []},
@@ -32,5 +46,5 @@
{update, pubkey_cert_records, soft, soft_purge, soft_purge, []},
{update, pubkey_cert, soft, soft_purge, soft_purge, []}
]
- }
+ }
]}.
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 334b9d792e..c99fd6fee1 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 0.10
+PUBLIC_KEY_VSN = 0.11
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index daf7b77527..cd5c9281cd 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -269,6 +269,13 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<p> {bad_cert, cert_expired}, {bad_cert, invalid_issuer}, {bad_cert, invalid_signature}, {bad_cert, unknown_ca}, {bad_cert, name_not_permitted}, {bad_cert, missing_basic_constraint}, {bad_cert, invalid_key_usage}</p>
</item>
+ <tag>{hibernate_after, integer()|undefined}</tag>
+ <item>When an integer-value is specified, the <code>ssl_connection</code>
+ will go into hibernation after the specified number of milliseconds
+ of inactivity, thus reducing its memory footprint. When
+ <code>undefined</code> is specified (this is the default), the process
+ will never go into hibernation.
+ </item>
</taglist>
</section>
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index e6a8c557fc..d3e426f254 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,12 +1,14 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"4.1.3", [{restart_application, ssl}]},
{"4.1.2", [{restart_application, ssl}]},
{"4.1.1", [{restart_application, ssl}]},
{"4.1", [{restart_application, ssl}]},
{"4.0.1", [{restart_application, ssl}]}
],
[
+ {"4.1.3", [{restart_application, ssl}]},
{"4.1.2", [{restart_application, ssl}]},
{"4.1.1", [{restart_application, ssl}]},
{"4.1", [{restart_application, ssl}]},
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index b85188b878..3512e194bc 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -60,7 +60,7 @@
{keyfile, path()} | {password, string()} | {cacerts, [der_encoded()]} |
{cacertfile, path()} | {dh, der_encoded()} | {dhfile, path()} |
{ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
- {reuse_session, fun()}.
+ {reuse_session, fun()} | {hibernate_after, integer()|undefined}.
-type verify_type() :: verify_none | verify_peer.
-type path() :: string().
@@ -711,7 +711,8 @@ handle_options(Opts0, _Role) ->
reuse_sessions = handle_option(reuse_sessions, Opts, true),
secure_renegotiate = handle_option(secure_renegotiate, Opts, false),
renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT),
- debug = handle_option(debug, Opts, [])
+ debug = handle_option(debug, Opts, []),
+ hibernate_after = handle_option(hibernate_after, Opts, undefined)
},
CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
@@ -720,7 +721,7 @@ handle_options(Opts0, _Role) ->
depth, cert, certfile, key, keyfile,
password, cacerts, cacertfile, dh, dhfile, ciphers,
debug, reuse_session, reuse_sessions, ssl_imp,
- cb_info, renegotiate_at, secure_renegotiate],
+ cb_info, renegotiate_at, secure_renegotiate, hibernate_after],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
@@ -827,6 +828,10 @@ validate_option(renegotiate_at, Value) when is_integer(Value) ->
validate_option(debug, Value) when is_list(Value); Value == true ->
Value;
+validate_option(hibernate_after, undefined) ->
+ undefined;
+validate_option(hibernate_after, Value) when is_integer(Value), Value >= 0 ->
+ Value;
validate_option(Opt, Value) ->
throw({error, {eoptions, {Opt, Value}}}).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 85245f4342..574e1e9468 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -289,9 +289,9 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
%% gen_fsm callbacks
%%====================================================================
%%--------------------------------------------------------------------
--spec init(list()) -> {ok, state_name(), #state{}} | {stop, term()}.
+-spec init(list()) -> {ok, state_name(), #state{}, timeout()} | {stop, term()}.
%% Possible return values not used now.
-%% | {ok, state_name(), #state{}, timeout()} |
+%% | {ok, state_name(), #state{}} |
%% ignore
%% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or
%% gen_fsm:start_link/3,4, this function is called by the new process to
@@ -311,7 +311,7 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
session_cache = CacheRef,
private_key = Key,
diffie_hellman_params = DHParams},
- {ok, hello, State}
+ {ok, hello, State, get_timeout(State)}
catch
throw:Error ->
{stop, Error}
@@ -412,6 +412,9 @@ hello(Hello = #client_hello{client_version = ClientVersion},
{stop, normal, State}
end;
+hello(timeout, State) ->
+ { next_state, hello, State, hibernate };
+
hello(Msg, State) ->
handle_unexpected_message(Msg, hello, State).
%%--------------------------------------------------------------------
@@ -460,6 +463,9 @@ abbreviated(#finished{verify_data = Data} = Finished,
{stop, normal, State}
end;
+abbreviated(timeout, State) ->
+ { next_state, abbreviated, State, hibernate };
+
abbreviated(Msg, State) ->
handle_unexpected_message(Msg, abbreviated, State).
@@ -582,6 +588,9 @@ certify(#client_key_exchange{exchange_keys = Keys},
{stop, normal, State}
end;
+certify(timeout, State) ->
+ { next_state, certify, State, hibernate };
+
certify(Msg, State) ->
handle_unexpected_message(Msg, certify, State).
@@ -664,6 +673,9 @@ cipher(#finished{verify_data = Data} = Finished,
{stop, normal, State}
end;
+cipher(timeout, State) ->
+ { next_state, cipher, State, hibernate };
+
cipher(Msg, State) ->
handle_unexpected_message(Msg, cipher, State).
@@ -693,6 +705,9 @@ connection(#hello_request{}, #state{host = Host, port = Port,
connection(#client_hello{} = Hello, #state{role = server} = State) ->
hello(Hello, State);
+connection(timeout, State) ->
+ {next_state, connection, State, hibernate};
+
connection(Msg, State) ->
handle_unexpected_message(Msg, connection, State).
%%--------------------------------------------------------------------
@@ -705,7 +720,7 @@ connection(Msg, State) ->
%% the event. Not currently used!
%%--------------------------------------------------------------------
handle_event(_Event, StateName, State) ->
- {next_state, StateName, State}.
+ {next_state, StateName, State, get_timeout(State)}.
%%--------------------------------------------------------------------
-spec handle_sync_event(term(), from(), state_name(), #state{}) ->
@@ -736,7 +751,8 @@ handle_sync_event({application_data, Data0}, From, connection,
{Msgs, [], ConnectionStates} ->
Result = Transport:send(Socket, Msgs),
{reply, Result,
- connection, State#state{connection_states = ConnectionStates}};
+ connection, State#state{connection_states = ConnectionStates},
+ get_timeout(State)};
{Msgs, RestData, ConnectionStates} ->
if
Msgs =/= [] ->
@@ -749,12 +765,14 @@ handle_sync_event({application_data, Data0}, From, connection,
renegotiation = {true, internal}})
end
catch throw:Error ->
- {reply, Error, connection, State}
+ {reply, Error, connection, State, get_timeout(State)}
end;
handle_sync_event({application_data, Data}, From, StateName,
#state{send_queue = Queue} = State) ->
%% In renegotiation priorities handshake, send data when handshake is finished
- {next_state, StateName, State#state{send_queue = queue:in({From, Data}, Queue)}};
+ {next_state, StateName,
+ State#state{send_queue = queue:in({From, Data}, Queue)},
+ get_timeout(State)};
handle_sync_event(start, From, hello, State) ->
hello(start, State#state{from = From});
@@ -768,9 +786,9 @@ handle_sync_event(start, From, hello, State) ->
%% here to make sure it is the users problem and not owers if
%% they upgrade a active socket.
handle_sync_event(start, _, connection, State) ->
- {reply, connected, connection, State};
+ {reply, connected, connection, State, get_timeout(State)};
handle_sync_event(start, From, StateName, State) ->
- {next_state, StateName, State#state{from = From}};
+ {next_state, StateName, State#state{from = From}, get_timeout(State)};
handle_sync_event(close, _, StateName, State) ->
%% Run terminate before returning
@@ -796,7 +814,7 @@ handle_sync_event({shutdown, How0}, _, StateName,
case Transport:shutdown(Socket, How0) of
ok ->
- {reply, ok, StateName, State};
+ {reply, ok, StateName, State, get_timeout(State)};
Error ->
{stop, normal, Error, State}
end;
@@ -807,30 +825,33 @@ handle_sync_event({recv, N}, From, connection = StateName, State0) ->
%% Doing renegotiate wait with handling request until renegotiate is
%% finished. Will be handled by next_state_connection/2.
handle_sync_event({recv, N}, From, StateName, State) ->
- {next_state, StateName, State#state{bytes_to_read = N, from = From,
- recv_during_renegotiation = true}};
+ {next_state, StateName,
+ State#state{bytes_to_read = N, from = From,
+ recv_during_renegotiation = true},
+ get_timeout(State)};
handle_sync_event({new_user, User}, _From, StateName,
State =#state{user_application = {OldMon, _}}) ->
NewMon = erlang:monitor(process, User),
erlang:demonitor(OldMon, [flush]),
- {reply, ok, StateName, State#state{user_application = {NewMon,User}}};
+ {reply, ok, StateName, State#state{user_application = {NewMon,User}},
+ get_timeout(State)};
handle_sync_event({get_opts, OptTags}, _From, StateName,
#state{socket = Socket,
socket_options = SockOpts} = State) ->
OptsReply = get_socket_opts(Socket, OptTags, SockOpts, []),
- {reply, OptsReply, StateName, State};
+ {reply, OptsReply, StateName, State, get_timeout(State)};
handle_sync_event(sockname, _From, StateName,
#state{socket = Socket} = State) ->
SockNameReply = inet:sockname(Socket),
- {reply, SockNameReply, StateName, State};
+ {reply, SockNameReply, StateName, State, get_timeout(State)};
handle_sync_event(peername, _From, StateName,
#state{socket = Socket} = State) ->
PeerNameReply = inet:peername(Socket),
- {reply, PeerNameReply, StateName, State};
+ {reply, PeerNameReply, StateName, State, get_timeout(State)};
handle_sync_event({set_opts, Opts0}, _From, StateName,
#state{socket_options = Opts1,
@@ -840,27 +861,27 @@ handle_sync_event({set_opts, Opts0}, _From, StateName,
State1 = State0#state{socket_options = Opts},
if
Opts#socket_options.active =:= false ->
- {reply, ok, StateName, State1};
+ {reply, ok, StateName, State1, get_timeout(State1)};
Buffer =:= <<>>, Opts1#socket_options.active =:= false ->
%% Need data, set active once
{Record, State2} = next_record_if_active(State1),
case next_state(StateName, Record, State2) of
- {next_state, StateName, State} ->
- {reply, ok, StateName, State};
+ {next_state, StateName, State, Timeout} ->
+ {reply, ok, StateName, State, Timeout};
{stop, Reason, State} ->
{stop, Reason, State}
end;
Buffer =:= <<>> ->
%% Active once already set
- {reply, ok, StateName, State1};
+ {reply, ok, StateName, State1, get_timeout(State1)};
true ->
case application_data(<<>>, State1) of
Stop = {stop,_,_} ->
Stop;
{Record, State2} ->
case next_state(StateName, Record, State2) of
- {next_state, StateName, State} ->
- {reply, ok, StateName, State};
+ {next_state, StateName, State, Timeout} ->
+ {reply, ok, StateName, State, Timeout};
{stop, Reason, State} ->
{stop, Reason, State}
end
@@ -871,7 +892,7 @@ handle_sync_event(renegotiate, From, connection, State) ->
renegotiate(State#state{renegotiation = {true, From}});
handle_sync_event(renegotiate, _, StateName, State) ->
- {reply, {error, already_renegotiating}, StateName, State};
+ {reply, {error, already_renegotiating}, StateName, State, get_timeout(State)};
handle_sync_event(info, _, StateName,
#state{negotiated_version = Version,
@@ -879,19 +900,19 @@ handle_sync_event(info, _, StateName,
AtomVersion = ssl_record:protocol_version(Version),
{reply, {ok, {AtomVersion, ssl_cipher:suite_definition(Suite)}},
- StateName, State};
+ StateName, State, get_timeout(State)};
handle_sync_event(session_info, _, StateName,
#state{session = #session{session_id = Id,
cipher_suite = Suite}} = State) ->
{reply, [{session_id, Id},
{cipher_suite, ssl_cipher:suite_definition(Suite)}],
- StateName, State};
+ StateName, State, get_timeout(State)};
handle_sync_event(peer_certificate, _, StateName,
#state{session = #session{peer_certificate = Cert}}
= State) ->
- {reply, {ok, Cert}, StateName, State}.
+ {reply, {ok, Cert}, StateName, State, get_timeout(State)}.
%%--------------------------------------------------------------------
-spec handle_info(msg(),state_name(), #state{}) ->
@@ -955,7 +976,7 @@ handle_info({'DOWN', MonitorRef, _, _, _}, _,
handle_info(Msg, StateName, State) ->
Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [Msg]),
error_logger:info_report(Report),
- {next_state, StateName, State}.
+ {next_state, StateName, State, get_timeout(State)}.
%%--------------------------------------------------------------------
-spec terminate(reason(), state_name(), #state{}) -> term().
@@ -1778,7 +1799,7 @@ handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet]} = State)
handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet | Packets]} = State0) ->
FsmReturn = {next_state, StateName, State0#state{tls_packets = Packets}},
case Handle(Packet, FsmReturn) of
- {next_state, NextStateName, State} ->
+ {next_state, NextStateName, State, _Timeout} ->
handle_tls_handshake(Handle, NextStateName, State);
{stop, _,_} = Stop ->
Stop
@@ -1789,11 +1810,11 @@ next_state(_, #alert{} = Alert, #state{negotiated_version = Version} = State) ->
{stop, normal, State};
next_state(Next, no_record, State) ->
- {next_state, Next, State};
+ {next_state, Next, State, get_timeout(State)};
next_state(Next, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, State) ->
Alerts = decode_alerts(EncAlerts),
- handle_alerts(Alerts, {next_state, Next, State});
+ handle_alerts(Alerts, {next_state, Next, State, get_timeout(State)});
next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
State0 = #state{tls_handshake_buffer = Buf0, negotiated_version = Version}) ->
@@ -2044,7 +2065,7 @@ handle_alerts([], Result) ->
handle_alerts(_, {stop, _, _} = Stop) ->
%% If it is a fatal alert immediately close
Stop;
-handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
+handle_alerts([Alert | Alerts], {next_state, StateName, State, _Timeout}) ->
handle_alerts(Alerts, handle_alert(Alert, StateName, State)).
handle_alert(#alert{level = ?FATAL} = Alert, StateName,
@@ -2225,3 +2246,8 @@ linux_workaround_transport_delivery_problems(#alert{level = ?FATAL}, Socket) ->
end;
linux_workaround_transport_delivery_problems(_, _) ->
ok.
+
+get_timeout(#state{ssl_options=#ssl_options{hibernate_after=undefined}}) ->
+ infinity;
+get_timeout(#state{ssl_options=#ssl_options{hibernate_after=HibernateAfter}}) ->
+ HibernateAfter.
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 715941e3ad..c28daa271e 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -98,7 +98,11 @@
reuse_sessions, % boolean()
renegotiate_at,
secure_renegotiate,
- debug %
+ debug,
+ hibernate_after % undefined if not hibernating,
+ % or number of ms of inactivity
+ % after which ssl_connection will
+ % go into hibernation
}).
-record(socket_options,
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 823401c863..fd3b6d06ad 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2010. All Rights Reserved.
+# Copyright Ericsson AB 1999-2011. 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
@@ -60,6 +60,7 @@ ERL_FILES = $(MODULES:%=%.erl)
HRL_FILES = ssl_test_MACHINE.hrl
HRL_FILES_SRC = \
+ ssl_int.hrl \
ssl_alert.hrl \
ssl_handshake.hrl
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 8495ddb1d7..4f0907027f 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -29,6 +29,7 @@
-include_lib("public_key/include/public_key.hrl").
-include("ssl_alert.hrl").
+-include("ssl_int.hrl").
-define('24H_in_sec', 86400).
-define(TIMEOUT, 60000).
@@ -250,7 +251,9 @@ all() ->
unknown_server_ca_accept_backwardscompatibilty,
%%different_ca_peer_sign,
no_reuses_session_server_restart_new_cert,
- no_reuses_session_server_restart_new_cert_file, reuseaddr].
+ no_reuses_session_server_restart_new_cert_file, reuseaddr,
+ hibernate
+ ].
groups() ->
[].
@@ -3319,6 +3322,45 @@ reuseaddr(Config) when is_list(Config) ->
ssl_test_lib:close(Client1).
%%--------------------------------------------------------------------
+
+hibernate(doc) ->
+ ["Check that an SSL connection that is started with option "
+ "{hibernate_after, 1000} indeed hibernates after 1000ms of "
+ "inactivity"];
+
+hibernate(suite) ->
+ [];
+
+hibernate(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {Client, #sslsocket{pid=Pid}} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, send_recv_result_active, []}},
+ {options, [{hibernate_after, 1000}|ClientOpts]}]),
+
+ { current_function, { _M, _F, _A } } =
+ process_info(Pid, current_function),
+
+ timer:sleep(1100),
+
+ { current_function, { erlang, hibernate, 3} } =
+ process_info(Pid, current_function),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
send_recv_result(Socket) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index f6ccbe85e3..8c639aa312 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -128,12 +128,14 @@ remove_close_msg(ReconnectTimes) ->
remove_close_msg(ReconnectTimes -1)
end.
-
start_client(Args) ->
- Result = spawn_link(?MODULE, run_client, [Args]),
+ Result = spawn_link(?MODULE, run_client, [lists:delete(return_socket, Args)]),
receive
- connected ->
- Result
+ { connected, Socket } ->
+ case lists:member(return_socket, Args) of
+ true -> { Result, Socket };
+ false -> Result
+ end
end.
run_client(Opts) ->
@@ -145,7 +147,7 @@ run_client(Opts) ->
test_server:format("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
case rpc:call(Node, ssl, connect, [Host, Port, Options]) of
{ok, Socket} ->
- Pid ! connected,
+ Pid ! { connected, Socket },
test_server:format("Client: connected~n", []),
%% In specail cases we want to know the client port, it will
%% be indicated by sending {port, 0} in options list!
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index a4be7bb889..2f1edfa186 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1,2 +1 @@
-
-SSL_VSN = 4.1.3
+SSL_VSN = 4.1.4