diff options
Diffstat (limited to 'lib')
454 files changed, 15243 insertions, 9712 deletions
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml index ccf07a9cc1..e86dbd9f5e 100644 --- a/lib/asn1/doc/src/asn1ct.xml +++ b/lib/asn1/doc/src/asn1ct.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>asn1.sgml</file> </header> - <module>asn1ct</module> + <module since="">asn1ct</module> <modulesummary>ASN.1 compiler and compile-time support functions</modulesummary> <description> <p>The ASN.1 compiler takes an ASN.1 module as input and generates a @@ -72,8 +72,8 @@ <funcs> <func> - <name>compile(Asn1module) -> ok | {error, Reason}</name> - <name>compile(Asn1module, Options) -> ok | {error, Reason}</name> + <name since="">compile(Asn1module) -> ok | {error, Reason}</name> + <name since="">compile(Asn1module, Options) -> ok | {error, Reason}</name> <fsummary>Compiles an ASN.1 module and generates encode/decode functions according to encoding rules BER or PER.</fsummary> <type> <v>Asn1module = atom() | string()</v> @@ -336,7 +336,7 @@ File3.asn</pre> </func> <func> - <name>value(Module, Type) -> {ok, Value} | {error, Reason}</name> + <name since="">value(Module, Type) -> {ok, Value} | {error, Reason}</name> <fsummary>Creates an ASN.1 value for test purposes.</fsummary> <type> <v>Module = Type = atom()</v> @@ -361,9 +361,9 @@ File3.asn</pre> </func> <func> - <name>test(Module) -> ok | {error, Reason}</name> - <name>test(Module, Type | Options) -> ok | {error, Reason}</name> - <name>test(Module, Type, Value | Options) -> ok | {error, Reason}</name> + <name since="">test(Module) -> ok | {error, Reason}</name> + <name since="">test(Module, Type | Options) -> ok | {error, Reason}</name> + <name since="">test(Module, Type, Value | Options) -> ok | {error, Reason}</name> <fsummary>Performs a test of encode and decode for types in an ASN.1 module.</fsummary> <type> <v>Module = Type = atom()</v> diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index a3b3f927eb..7887a2c3ea 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>common_test_app.sgml</file> </header> - <module>common_test</module> + <module since="">common_test</module> <modulesummary>A framework for automated testing of any target nodes.</modulesummary> <description> @@ -68,7 +68,7 @@ <funcs> <func> - <name>Module:all() -> Tests | {skip,Reason} </name> + <name since="">Module:all() -> Tests | {skip,Reason} </name> <fsummary>Returns the list of all test case groups and test cases in the module.</fsummary> <type> @@ -115,7 +115,7 @@ </func> <func> - <name>Module:groups() -> GroupDefs</name> + <name since="">Module:groups() -> GroupDefs</name> <fsummary>Returns a list of test case group definitions.</fsummary> <type> <v>GroupDefs = [Group]</v> @@ -140,7 +140,7 @@ </func> <func> - <name>Module:suite() -> [Info] </name> + <name since="">Module:suite() -> [Info] </name> <fsummary>Test suite info function (providing default data for the suite).</fsummary> <type> @@ -213,7 +213,7 @@ </func> <func> - <name>Module:init_per_suite(Config) -> NewConfig | {skip,Reason} | + <name since="">Module:init_per_suite(Config) -> NewConfig | {skip,Reason} | {skip_and_save,Reason,SaveConfig}</name> <fsummary>Test suite initializations.</fsummary> <type> @@ -248,7 +248,7 @@ </func> <func> - <name>Module:end_per_suite(Config) -> term() | + <name since="">Module:end_per_suite(Config) -> term() | {save_config,SaveConfig}</name> <fsummary>Test suite finalization.</fsummary> <type> @@ -272,7 +272,7 @@ </func> <func> - <name>Module:group(GroupName) -> [Info] </name> + <name since="OTP R15B">Module:group(GroupName) -> [Info] </name> <fsummary>Test case group information function (providing default data for a test case group, that is, its test cases and subgroups).</fsummary> @@ -352,7 +352,7 @@ </func> <func> - <name>Module:init_per_group(GroupName, Config) -> NewConfig | + <name since="">Module:init_per_group(GroupName, Config) -> NewConfig | {skip,Reason}</name> <fsummary>Test case group initializations.</fsummary> <type> @@ -390,7 +390,7 @@ </func> <func> - <name>Module:end_per_group(GroupName, Config) -> term() | + <name since="">Module:end_per_group(GroupName, Config) -> term() | {return_group_result,Status}</name> <fsummary>Test case group finalization.</fsummary> <type> @@ -424,7 +424,7 @@ </func> <func> - <name>Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name> + <name since="">Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name> <fsummary>Test case initializations.</fsummary> <type> <v> TestCase = atom()</v> @@ -454,7 +454,7 @@ </func> <func> - <name>Module:end_per_testcase(TestCase, Config) -> term() | {fail,Reason} | {save_config,SaveConfig}</name> + <name since="">Module:end_per_testcase(TestCase, Config) -> term() | {fail,Reason} | {save_config,SaveConfig}</name> <fsummary>Test case finalization.</fsummary> <type> <v>TestCase = atom()</v> @@ -486,7 +486,7 @@ </func> <func> - <name>Module:Testcase() -> [Info] </name> + <name since="OTP R14B">Module:Testcase() -> [Info] </name> <fsummary>Test case information function.</fsummary> <type> <v>Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns}</v> @@ -560,7 +560,7 @@ </func> <func> - <name>Module:Testcase(Config) -> term() | {skip,Reason} | {comment,Comment} | {save_config,SaveConfig} | {skip_and_save,Reason,SaveConfig} | exit() </name> + <name since="OTP R14B">Module:Testcase(Config) -> term() | {skip,Reason} | {comment,Comment} | {save_config,SaveConfig} | {skip_and_save,Reason,SaveConfig} | exit() </name> <fsummary>A test case.</fsummary> <type> <v>Config = SaveConfig = [{Key,Value}]</v> diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml index c0380c4142..83c0ecb309 100644 --- a/lib/common_test/doc/src/ct.xml +++ b/lib/common_test/doc/src/ct.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct.xml</file> </header> - <module>ct</module> + <module since="">ct</module> <modulesummary>Main user interface for the Common Test framework.</modulesummary> <description> @@ -139,7 +139,7 @@ <funcs> <func> - <name>abort_current_testcase(Reason) -> ok | {error, ErrorReason}</name> + <name since="">abort_current_testcase(Reason) -> ok | {error, ErrorReason}</name> <fsummary>Aborts the currently executing test case.</fsummary> <type> <v>Reason = term()</v> @@ -157,7 +157,7 @@ </func> <func> - <name>add_config(Callback, Config) -> ok | {error, Reason}</name> + <name since="OTP R14B">add_config(Callback, Config) -> ok | {error, Reason}</name> <fsummary>Loads configuration variables using the specified callback module and configuration string.</fsummary> <type> @@ -176,7 +176,7 @@ </func> <func> - <name>break(Comment) -> ok | {error, Reason}</name> + <name since="OTP R15B02">break(Comment) -> ok | {error, Reason}</name> <fsummary>Cancels any active timetrap and pause the execution of the current test case until the user calls function continue/0.</fsummary> <type> @@ -206,7 +206,7 @@ </func> <func> - <name>break(TestCase, Comment) -> ok | {error, Reason}</name> + <name since="OTP R15B02">break(TestCase, Comment) -> ok | {error, Reason}</name> <fsummary>Works the same way as break/1, only argument TestCase makes it possible to pause a test case executing in a parallel group.</fsummary> <type> @@ -228,7 +228,7 @@ </func> <func> - <name>capture_get() -> ListOfStrings</name> + <name since="OTP R15B">capture_get() -> ListOfStrings</name> <fsummary>Equivalent to capture_get([default]).</fsummary> <type> <v>ListOfStrings = [string()]</v> @@ -240,7 +240,7 @@ </func> <func> - <name>capture_get(ExclCategories) -> ListOfStrings</name> + <name since="OTP R15B">capture_get(ExclCategories) -> ListOfStrings</name> <fsummary>Returns and purges the list of text strings buffered during the latest session of capturing printouts to stdout.</fsummary> <type> @@ -262,7 +262,7 @@ </func> <func> - <name>capture_start() -> ok</name> + <name since="OTP R15B">capture_start() -> ok</name> <fsummary>Starts capturing all text strings printed to stdout during execution of the test case.</fsummary> <desc><marker id="capture_start-0"/> @@ -276,7 +276,7 @@ </func> <func> - <name>capture_stop() -> ok</name> + <name since="OTP R15B">capture_stop() -> ok</name> <fsummary>Stops capturing text strings (a session started with capture_start/0).</fsummary> <desc><marker id="capture_stop-0"/> @@ -290,7 +290,7 @@ </func> <func> - <name>comment(Comment) -> ok</name> + <name since="">comment(Comment) -> ok</name> <fsummary>Prints the specified Comment in the comment field in the table on the test suite result page.</fsummary> <type> @@ -307,7 +307,7 @@ </func> <func> - <name>comment(Format, Args) -> ok</name> + <name since="OTP R15B">comment(Format, Args) -> ok</name> <fsummary>Prints the formatted string in the comment field in the table on the test suite result page.</fsummary> <type> @@ -326,7 +326,7 @@ </func> <func> - <name>continue() -> ok</name> + <name since="OTP R15B02">continue() -> ok</name> <fsummary>This function must be called to continue after a test case (not executing in a parallel group) has called break/1.</fsummary> <desc><marker id="continue-0"/> @@ -337,7 +337,7 @@ </func> <func> - <name>continue(TestCase) -> ok</name> + <name since="OTP R15B02">continue(TestCase) -> ok</name> <fsummary>This function must be called to continue after a test case has called break/2.</fsummary> <type> @@ -353,7 +353,7 @@ </func> <func> - <name>decrypt_config_file(EncryptFileName, TargetFileName) -> ok | {error, Reason}</name> + <name since="">decrypt_config_file(EncryptFileName, TargetFileName) -> ok | {error, Reason}</name> <fsummary>Decrypts EncryptFileName, previously generated with encrypt_config_file/2,3.</fsummary> <type> @@ -372,7 +372,7 @@ </func> <func> - <name>decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) -> ok | {error, Reason}</name> + <name since="">decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) -> ok | {error, Reason}</name> <fsummary>Decrypts EncryptFileName, previously generated with encrypt_config_file/2,3.</fsummary> <type> @@ -390,7 +390,7 @@ </func> <func> - <name>encrypt_config_file(SrcFileName, EncryptFileName) -> ok | {error, Reason}</name> + <name since="">encrypt_config_file(SrcFileName, EncryptFileName) -> ok | {error, Reason}</name> <fsummary>Encrypts the source configuration file with DES3 and saves the result in file EncryptFileName.</fsummary> <type> @@ -416,7 +416,7 @@ </func> <func> - <name>encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) -> ok | {error, Reason}</name> + <name since="">encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) -> ok | {error, Reason}</name> <fsummary>Encrypts the source configuration file with DES3 and saves the result in the target file EncryptFileName.</fsummary> <type> @@ -442,7 +442,7 @@ </func> <func> - <name>fail(Reason) -> ok</name> + <name since="">fail(Reason) -> ok</name> <fsummary>Terminates a test case with the specified error Reason.</fsummary> <type> @@ -454,7 +454,7 @@ </func> <func> - <name>fail(Format, Args) -> ok</name> + <name since="OTP R15B">fail(Format, Args) -> ok</name> <fsummary>Terminates a test case with an error message specified by a format string and a list of values (used as arguments to io_lib:format/2).</fsummary> @@ -470,7 +470,7 @@ </func> <func> - <name>get_config(Required) -> Value</name> + <name since="">get_config(Required) -> Value</name> <fsummary>Equivalent to get_config(Required, undefined, []).</fsummary> <desc><marker id="get_config-1"/> <p>Equivalent to <seealso marker="#get_config-3"><c>ct:get_config(Required, @@ -479,7 +479,7 @@ </func> <func> - <name>get_config(Required, Default) -> Value</name> + <name since="">get_config(Required, Default) -> Value</name> <fsummary>Equivalent to get_config(Required, Default, []).</fsummary> <desc><marker id="get_config-2"/> <p>Equivalent to <seealso marker="#get_config-3"><c>ct:get_config(Required, @@ -488,7 +488,7 @@ </func> <func> - <name>get_config(Required, Default, Opts) -> ValueOrElement</name> + <name since="">get_config(Required, Default, Opts) -> ValueOrElement</name> <fsummary>Reads configuration data values.</fsummary> <type> <v>Required = KeyOrName | {KeyOrName, SubKey} | {KeyOrName, SubKey, SubKey}</v> @@ -554,7 +554,7 @@ </func> <func> - <name>get_event_mgr_ref() -> EvMgrRef</name> + <name since="OTP 17.5">get_event_mgr_ref() -> EvMgrRef</name> <fsummary>Gets a reference to the <c>Common Test</c> event manager.</fsummary> <type> <v>EvMgrRef = atom()</v> @@ -572,7 +572,7 @@ </func> <func> - <name>get_progname() -> string()</name> + <name since="OTP 21.0">get_progname() -> string()</name> <fsummary>Returns the command used to start this Erlang instance.</fsummary> <desc><marker id="get_progname-0"/> <p>Returns the command used to start this Erlang instance. @@ -582,7 +582,7 @@ </func> <func> - <name>get_status() -> TestStatus | {error, Reason} | no_tests_running</name> + <name since="">get_status() -> TestStatus | {error, Reason} | no_tests_running</name> <fsummary>Returns status of ongoing test.</fsummary> <type> <v>TestStatus = [StatusElem]</v> @@ -608,7 +608,7 @@ </func> <func> - <name>get_target_name(Handle) -> {ok, TargetName} | {error, Reason}</name> + <name since="">get_target_name(Handle) -> {ok, TargetName} | {error, Reason}</name> <fsummary>Returns the name of the target that the specified connection belongs to.</fsummary> <type> @@ -622,7 +622,7 @@ </func> <func> - <name>get_testspec_terms() -> TestSpecTerms | undefined</name> + <name since="OTP 18.0">get_testspec_terms() -> TestSpecTerms | undefined</name> <fsummary>Gets a list of all test specification terms used to configure and run this test.</fsummary> <type> @@ -636,7 +636,7 @@ </func> <func> - <name>get_testspec_terms(Tags) -> TestSpecTerms | undefined</name> + <name since="OTP 18.0">get_testspec_terms(Tags) -> TestSpecTerms | undefined</name> <fsummary>Reads one or more terms from the test specification used to configure and run this test.</fsummary> <type> @@ -663,7 +663,7 @@ </func> <func> - <name>get_timetrap_info() -> {Time, {Scaling,ScaleVal}}</name> + <name since="OTP R15B">get_timetrap_info() -> {Time, {Scaling,ScaleVal}}</name> <fsummary>Reads information about the timetrap set for the current test case.</fsummary> <type> @@ -682,7 +682,7 @@ </func> <func> - <name>get_verbosity(Category) -> Level | undefined</name> + <name since="OTP 19.1">get_verbosity(Category) -> Level | undefined</name> <fsummary>Read the verbosity level for a logging category.</fsummary> <type> <v>Category = default | atom()</v> @@ -697,7 +697,7 @@ </func> <func> - <name>install(Opts) -> ok | {error, Reason}</name> + <name since="">install(Opts) -> ok | {error, Reason}</name> <fsummary>Installs configuration files and event handlers.</fsummary> <type> <v>Opts = [Opt]</v> @@ -724,7 +724,7 @@ </func> <func> - <name>listenv(Telnet) -> [Env]</name> + <name since="">listenv(Telnet) -> [Env]</name> <fsummary>Performs command listenv on the specified Telnet connection and returns the result as a list of key-value pairs.</fsummary> <type> @@ -740,7 +740,7 @@ </func> <func> - <name>log(Format) -> ok</name> + <name since="">log(Format) -> ok</name> <fsummary>Equivalent to log(default, 50, Format, [], []).</fsummary> <desc><marker id="log-1"/> <p>Equivalent to @@ -749,7 +749,7 @@ </func> <func> - <name>log(X1, X2) -> ok</name> + <name since="">log(X1, X2) -> ok</name> <fsummary>Equivalent to log(Category, Importance, Format, FormatArgs, []).</fsummary> <type> @@ -763,7 +763,7 @@ </func> <func> - <name>log(X1, X2, X3) -> ok</name> + <name since="">log(X1, X2, X3) -> ok</name> <fsummary>Equivalent to log(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -778,7 +778,7 @@ </func> <func> - <name>log(X1, X2, X3, X4) -> ok</name> + <name since="OTP R15B02">log(X1, X2, X3, X4) -> ok</name> <fsummary>Equivalent to log(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -794,7 +794,7 @@ </func> <func> - <name>log(Category, Importance, Format, FormatArgs, Opts) -> ok</name> + <name since="OTP 18.3">log(Category, Importance, Format, FormatArgs, Opts) -> ok</name> <fsummary>Prints from a test case to the log file.</fsummary> <type> <v>Category = atom()</v> @@ -825,7 +825,7 @@ </func> <func> - <name>make_priv_dir() -> ok | {error, Reason}</name> + <name since="OTP R15B01">make_priv_dir() -> ok | {error, Reason}</name> <fsummary>If the test has been started with option create_priv_dir set to manual_per_tc, in order for the test case to use the private directory, it must first create it by calling this function.</fsummary> @@ -841,7 +841,7 @@ </func> <func> - <name>notify(Name, Data) -> ok</name> + <name since="OTP R15B02">notify(Name, Data) -> ok</name> <fsummary>Sends an asynchronous notification of type Name with Data to the <c>Common Test</c> event manager.</fsummary> <type> @@ -859,7 +859,7 @@ </func> <func> - <name>pal(Format) -> ok</name> + <name since="">pal(Format) -> ok</name> <fsummary>Equivalent to pal(default, 50, Format, [], []).</fsummary> <desc><marker id="pal-1"/> <p>Equivalent to @@ -869,7 +869,7 @@ </func> <func> - <name>pal(X1, X2) -> ok</name> + <name since="">pal(X1, X2) -> ok</name> <fsummary>Equivalent to pal(Category, Importance, Format, FormatArgs, []).</fsummary> <type> @@ -883,7 +883,7 @@ </func> <func> - <name>pal(X1, X2, X3) -> ok</name> + <name since="">pal(X1, X2, X3) -> ok</name> <fsummary>Equivalent to pal(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -898,7 +898,7 @@ </func> <func> - <name>pal(X1, X2, X3, X4) -> ok</name> + <name since="OTP R15B02">pal(X1, X2, X3, X4) -> ok</name> <fsummary>Equivalent to pal(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -914,7 +914,7 @@ </func> <func> - <name>pal(Category, Importance, Format, FormatArgs, Opts) -> ok</name> + <name since="OTP 19.2">pal(Category, Importance, Format, FormatArgs, Opts) -> ok</name> <fsummary>Prints and logs from a test case.</fsummary> <type> <v>Category = atom()</v> @@ -945,7 +945,7 @@ </func> <func> - <name>parse_table(Data) -> {Heading, Table}</name> + <name since="">parse_table(Data) -> {Heading, Table}</name> <fsummary>Parses the printout from an SQL table and returns a list of tuples.</fsummary> <type> @@ -967,7 +967,7 @@ </func> <func> - <name>print(Format) -> ok</name> + <name since="">print(Format) -> ok</name> <fsummary>Equivalent to print(default, 50, Format, [], []).</fsummary> <desc><marker id="print-1"/> <p>Equivalent to <seealso marker="#print-5"><c>ct:print(default, @@ -976,7 +976,7 @@ </func> <func> - <name>print(X1, X2) -> ok</name> + <name since="OTP R15B02">print(X1, X2) -> ok</name> <fsummary>Equivalent to print(Category, Importance, Format, FormatArgs, []).</fsummary> <type> @@ -990,7 +990,7 @@ </func> <func> - <name>print(X1, X2, X3) -> ok</name> + <name since="">print(X1, X2, X3) -> ok</name> <fsummary>Equivalent to print(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -1005,7 +1005,7 @@ </func> <func> - <name>print(X1, X2, X3, X4) -> ok</name> + <name since="OTP R15B02">print(X1, X2, X3, X4) -> ok</name> <fsummary>Equivalent to print(Category, Importance, Format, FormatArgs, Opts).</fsummary> <type> @@ -1021,7 +1021,7 @@ </func> <func> - <name>print(Category, Importance, Format, FormatArgs, Opts) -> ok</name> + <name since="OTP 19.2">print(Category, Importance, Format, FormatArgs, Opts) -> ok</name> <fsummary>Prints from a test case to the console.</fsummary> <type> <v>Category = atom()</v> @@ -1048,7 +1048,7 @@ </func> <func> - <name>reload_config(Required) -> ValueOrElement | {error, Reason}</name> + <name since="OTP R14B">reload_config(Required) -> ValueOrElement | {error, Reason}</name> <fsummary>Reloads configuration file containing specified configuration key.</fsummary> <type> @@ -1071,7 +1071,7 @@ </func> <func> - <name>remaining_test_procs() -> {TestProcs,SharedGL,OtherGLs}</name> + <name since="OTP 20.2">remaining_test_procs() -> {TestProcs,SharedGL,OtherGLs}</name> <fsummary>>This function will return the identity of test- and group leader processes that are still running at the time of this call.</fsummary> <type> @@ -1107,7 +1107,7 @@ </func> <func> - <name>remove_config(Callback, Config) -> ok</name> + <name since="OTP R14B">remove_config(Callback, Config) -> ok</name> <fsummary>Removes configuration variables (together with their aliases) that were loaded with specified callback module and configuration string.</fsummary> @@ -1124,7 +1124,7 @@ </func> <func> - <name>require(Required) -> ok | {error, Reason}</name> + <name since="">require(Required) -> ok | {error, Reason}</name> <fsummary>Checks if the required configuration is available.</fsummary> <type> <v>Required = Key | {Key, SubKeys} | {Key, SubKey, SubKeys}</v> @@ -1178,7 +1178,7 @@ </func> <func> - <name>require(Name, Required) -> ok | {error, Reason}</name> + <name since="">require(Name, Required) -> ok | {error, Reason}</name> <fsummary>Checks if the required configuration is available and gives it a name.</fsummary> <type> @@ -1237,7 +1237,7 @@ </func> <func> - <name>run(TestDirs) -> Result</name> + <name since="">run(TestDirs) -> Result</name> <fsummary>Runs all test cases in all suites in the specified directories.</fsummary> <type> @@ -1251,7 +1251,7 @@ </func> <func> - <name>run(TestDir, Suite) -> Result</name> + <name since="">run(TestDir, Suite) -> Result</name> <fsummary>Runs all test cases in the specified suite.</fsummary> <desc><marker id="run-2"/> <p>Runs all test cases in the specified suite.</p> @@ -1261,7 +1261,7 @@ </func> <func> - <name>run(TestDir, Suite, Cases) -> Result</name> + <name since="">run(TestDir, Suite, Cases) -> Result</name> <fsummary>Runs the specified test cases.</fsummary> <type> <v>TestDir = string()</v> @@ -1283,7 +1283,7 @@ </func> <func> - <name>run_test(Opts) -> Result</name> + <name since="">run_test(Opts) -> Result</name> <fsummary>Runs tests as specified by the combination of options in Opts.</fsummary> <type> @@ -1355,7 +1355,7 @@ </func> <func> - <name>run_testspec(TestSpec) -> Result</name> + <name since="">run_testspec(TestSpec) -> Result</name> <fsummary>Runs a test specified by TestSpec.</fsummary> <type> <v>TestSpec = [term()]</v> @@ -1375,7 +1375,7 @@ </func> <func> - <name>set_verbosity(Category, Level) -> ok</name> + <name since="OTP 19.1">set_verbosity(Category, Level) -> ok</name> <fsummary>Set the verbosity level for a logging category.</fsummary> <type> <v>Category = default | atom()</v> @@ -1390,7 +1390,7 @@ </func> <func> - <name>sleep(Time) -> ok</name> + <name since="OTP R14B">sleep(Time) -> ok</name> <fsummary>This function, similar to timer:sleep/1, suspends the test case for a specified time.</fsummary> <type> @@ -1412,7 +1412,7 @@ </func> <func> - <name>start_interactive() -> ok</name> + <name since="">start_interactive() -> ok</name> <fsummary>Starts <c>Common Test</c> in interactive mode.</fsummary> <desc><marker id="start_interactive-0"/> <p>Starts <c>Common Test</c> in interactive mode.</p> @@ -1440,7 +1440,7 @@ </func> <func> - <name>step(TestDir, Suite, Case) -> Result</name> + <name since="">step(TestDir, Suite, Case) -> Result</name> <fsummary>Steps through a test case with the debugger.</fsummary> <type> <v>Case = atom()</v> @@ -1453,7 +1453,7 @@ </func> <func> - <name>step(TestDir, Suite, Case, Opts) -> Result</name> + <name since="">step(TestDir, Suite, Case, Opts) -> Result</name> <fsummary>Steps through a test case with the debugger.</fsummary> <type> <v>Case = atom()</v> @@ -1470,7 +1470,7 @@ </func> <func> - <name>stop_interactive() -> ok</name> + <name since="">stop_interactive() -> ok</name> <fsummary>Exits the interactive mode.</fsummary> <desc><marker id="stop_interactive-0"/> <p>Exits the interactive mode.</p> @@ -1482,7 +1482,7 @@ </func> <func> - <name>sync_notify(Name, Data) -> ok</name> + <name since="OTP R15B02">sync_notify(Name, Data) -> ok</name> <fsummary>Sends a synchronous notification of type Name with Data to the <c>Common Test</c> event manager.</fsummary> <type> @@ -1501,7 +1501,7 @@ </func> <func> - <name>testcases(TestDir, Suite) -> Testcases | {error, Reason}</name> + <name since="">testcases(TestDir, Suite) -> Testcases | {error, Reason}</name> <fsummary>Returns all test cases in the specified suite.</fsummary> <type> <v>TestDir = string()</v> @@ -1515,7 +1515,7 @@ </func> <func> - <name>timetrap(Time) -> ok</name> + <name since="OTP R14B">timetrap(Time) -> ok</name> <fsummary>Sets a new timetrap for the running test case.</fsummary> <type> <v>Time = {hours, Hours} | {minutes, Mins} | {seconds, Secs} | Millisecs | infinity | Func</v> @@ -1539,7 +1539,7 @@ </func> <func> - <name>userdata(TestDir, Suite) -> SuiteUserData | {error, Reason}</name> + <name since="">userdata(TestDir, Suite) -> SuiteUserData | {error, Reason}</name> <fsummary>Returns any data specified with tag userdata in the list of tuples returned from Suite:suite/0.</fsummary> <type> @@ -1556,7 +1556,7 @@ </func> <func> - <name>userdata(TestDir, Suite, Case::GroupOrCase) -> TCUserData | {error, Reason}</name> + <name since="">userdata(TestDir, Suite, Case::GroupOrCase) -> TCUserData | {error, Reason}</name> <fsummary>Returns any data specified with tag userdata in the list of tuples returned from Suite:group(GroupName) or Suite:Case().</fsummary> <type> diff --git a/lib/common_test/doc/src/ct_cover.xml b/lib/common_test/doc/src/ct_cover.xml index 89d944acbe..61365d3522 100644 --- a/lib/common_test/doc/src/ct_cover.xml +++ b/lib/common_test/doc/src/ct_cover.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_cover.xml</file> </header> - <module>ct_cover</module> + <module since="">ct_cover</module> <modulesummary>Common Test framework code coverage support module. </modulesummary> @@ -47,7 +47,7 @@ <funcs> <func> - <name>add_nodes(Nodes) -> {ok, StartedNodes} | {error, Reason}</name> + <name since="">add_nodes(Nodes) -> {ok, StartedNodes} | {error, Reason}</name> <fsummary>Adds nodes to current cover test (only works if cover support is active).</fsummary> <type> @@ -67,7 +67,7 @@ </func> <func> - <name>cross_cover_analyse(Level, Tests) -> ok</name> + <name since="OTP R16B">cross_cover_analyse(Level, Tests) -> ok</name> <fsummary>Accumulates cover results over multiple tests.</fsummary> <type> <v>Level = overview | details</v> @@ -83,7 +83,7 @@ </func> <func> - <name>remove_nodes(Nodes) -> ok | {error, Reason}</name> + <name since="">remove_nodes(Nodes) -> ok | {error, Reason}</name> <fsummary>Removes nodes from the current cover test.</fsummary> <type> <v>Nodes = [atom()]</v> diff --git a/lib/common_test/doc/src/ct_ftp.xml b/lib/common_test/doc/src/ct_ftp.xml index 592c5eb05d..7ee6049486 100644 --- a/lib/common_test/doc/src/ct_ftp.xml +++ b/lib/common_test/doc/src/ct_ftp.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_ftp.xml</file> </header> - <module>ct_ftp</module> + <module since="">ct_ftp</module> <modulesummary>FTP client module (based on the FTP application).</modulesummary> <description> @@ -59,7 +59,7 @@ <funcs> <func> - <name>cd(Connection, Dir) -> ok | {error, Reason}</name> + <name since="">cd(Connection, Dir) -> ok | {error, Reason}</name> <fsummary>Changes directory on remote host.</fsummary> <type> <v>Connection = connection()</v> @@ -71,7 +71,7 @@ </func> <func> - <name>close(Connection) -> ok | {error, Reason}</name> + <name since="">close(Connection) -> ok | {error, Reason}</name> <fsummary>Closes the FTP connection.</fsummary> <type> <v>Connection = connection()</v> @@ -82,7 +82,7 @@ </func> <func> - <name>delete(Connection, File) -> ok | {error, Reason}</name> + <name since="">delete(Connection, File) -> ok | {error, Reason}</name> <fsummary>Deletes a file on remote host.</fsummary> <type> <v>Connection = connection()</v> @@ -94,7 +94,7 @@ </func> <func> - <name>get(KeyOrName, RemoteFile, LocalFile) -> ok | {error, Reason}</name> + <name since="">get(KeyOrName, RemoteFile, LocalFile) -> ok | {error, Reason}</name> <fsummary>Opens an FTP connection and fetches a file from the remote host.</fsummary> <type> @@ -122,7 +122,7 @@ </func> <func> - <name>ls(Connection, Dir) -> {ok, Listing} | {error, Reason}</name> + <name since="">ls(Connection, Dir) -> {ok, Listing} | {error, Reason}</name> <fsummary>Lists directory Dir.</fsummary> <type> <v>Connection = connection()</v> @@ -135,7 +135,7 @@ </func> <func> - <name>open(KeyOrName) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(KeyOrName) -> {ok, Handle} | {error, Reason}</name> <fsummary>Opens an FTP connection to the specified node.</fsummary> <type> <v>KeyOrName = Key | Name</v> @@ -164,7 +164,7 @@ </func> <func> - <name>put(KeyOrName, LocalFile, RemoteFile) -> ok | {error, Reason}</name> + <name since="">put(KeyOrName, LocalFile, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Opens an FTP connection and sends a file to the remote host.</fsummary> <type> @@ -203,7 +203,7 @@ </func> <func> - <name>recv(Connection, RemoteFile) -> ok | {error, Reason}</name> + <name since="">recv(Connection, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Fetches a file over FTP.</fsummary> <desc><marker id="recv-2"/> <p>Fetches a file over FTP.</p> @@ -215,7 +215,7 @@ </func> <func> - <name>recv(Connection, RemoteFile, LocalFile) -> ok | {error, Reason}</name> + <name since="">recv(Connection, RemoteFile, LocalFile) -> ok | {error, Reason}</name> <fsummary>Fetches a file over FTP.</fsummary> <type> <v>Connection = connection()</v> @@ -230,7 +230,7 @@ </func> <func> - <name>send(Connection, LocalFile) -> ok | {error, Reason}</name> + <name since="">send(Connection, LocalFile) -> ok | {error, Reason}</name> <fsummary>Sends a file over FTP.</fsummary> <desc><marker id="send-2"/> <p>Sends a file over FTP.</p> @@ -243,7 +243,7 @@ </func> <func> - <name>send(Connection, LocalFile, RemoteFile) -> ok | {error, Reason}</name> + <name since="">send(Connection, LocalFile, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Sends a file over FTP.</fsummary> <type> <v>Connection = connection()</v> @@ -258,7 +258,7 @@ </func> <func> - <name>type(Connection, Type) -> ok | {error, Reason}</name> + <name since="">type(Connection, Type) -> ok | {error, Reason}</name> <fsummary>Changes the file transfer type.</fsummary> <type> <v>Connection = connection()</v> diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml index 954be0ffba..048552e4bb 100644 --- a/lib/common_test/doc/src/ct_hooks.xml +++ b/lib/common_test/doc/src/ct_hooks.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>ct_hooks.sgml</file> </header> - <module>ct_hooks</module> + <module since="OTP R14B02">ct_hooks</module> <modulesummary>A callback interface on top of Common Test.</modulesummary> <description> @@ -75,7 +75,7 @@ <funcs> <func> - <name>Module:init(Id, Opts) -> {ok, State} | {ok, State, Priority}</name> + <name since="OTP R14B02">Module:init(Id, Opts) -> {ok, State} | {ok, State, Priority}</name> <fsummary>Initiates the Common Test Hook.</fsummary> <type> <v>Id = reference() | term()</v> @@ -109,7 +109,7 @@ </func> <func> - <name>Module:pre_init_per_suite(SuiteName, InitData, CTHState) -> Result</name> + <name since="OTP R14B02">Module:pre_init_per_suite(SuiteName, InitData, CTHState) -> Result</name> <fsummary>Called before init_per_suite.</fsummary> <type> <v>SuiteName = atom()</v> @@ -161,7 +161,7 @@ </func> <func> - <name>Module:post_init_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> + <name since="OTP R14B02">Module:post_init_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> <fsummary>Called after init_per_suite.</fsummary> <type> <v>SuiteName = atom()</v> @@ -208,7 +208,7 @@ </func> <func> - <name>Module:pre_init_per_group(SuiteName, GroupName, InitData, CTHState) -> Result</name> + <name since="OTP 19.3">Module:pre_init_per_group(SuiteName, GroupName, InitData, CTHState) -> Result</name> <fsummary>Called before init_per_group.</fsummary> <type> <v>SuiteName = atom()</v> @@ -241,7 +241,7 @@ </func> <func> - <name>Module:post_init_per_group(SuiteName, GroupName, Config, Return, CTHState) -> Result</name> + <name since="OTP 19.3">Module:post_init_per_group(SuiteName, GroupName, Config, Return, CTHState) -> Result</name> <fsummary>Called after init_per_group.</fsummary> <type> <v>SuiteName = atom()</v> @@ -274,7 +274,7 @@ </func> <func> - <name>Module:pre_init_per_testcase(SuiteName, TestcaseName, InitData, CTHState) -> Result</name> + <name since="OTP 19.3">Module:pre_init_per_testcase(SuiteName, TestcaseName, InitData, CTHState) -> Result</name> <fsummary>Called before init_per_testcase.</fsummary> <type> <v>SuiteName = atom()</v> @@ -311,7 +311,7 @@ </func> <func> - <name>Module:post_init_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -> Result</name> + <name since="OTP 19.3">Module:post_init_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -> Result</name> <fsummary>Called after init_per_testcase.</fsummary> <type> <v>SuiteName = atom()</v> @@ -344,7 +344,7 @@ </func> <func> - <name>Module:pre_end_per_testcase(SuiteName, TestcaseName, EndData, CTHState) -> Result</name> + <name since="OTP 19.3">Module:pre_end_per_testcase(SuiteName, TestcaseName, EndData, CTHState) -> Result</name> <fsummary>Called before end_per_testcase.</fsummary> <type> <v>SuiteName = atom()</v> @@ -380,7 +380,7 @@ </func> <func> - <name>Module:post_end_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -> Result</name> + <name since="OTP 19.3">Module:post_end_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -> Result</name> <fsummary>Called after end_per_testcase.</fsummary> <type> <v>SuiteName = atom()</v> @@ -413,7 +413,7 @@ </func> <func> - <name>Module:pre_end_per_group(SuiteName, GroupName, EndData, CTHState) -> Result</name> + <name since="OTP 19.3">Module:pre_end_per_group(SuiteName, GroupName, EndData, CTHState) -> Result</name> <fsummary>Called before end_per_group.</fsummary> <type> <v>SuiteName = atom()</v> @@ -446,7 +446,7 @@ </func> <func> - <name>Module:post_end_per_group(SuiteName, GroupName, Config, Return, CTHState) -> Result</name> + <name since="OTP 19.3">Module:post_end_per_group(SuiteName, GroupName, Config, Return, CTHState) -> Result</name> <fsummary>Called after end_per_group.</fsummary> <type> <v>SuiteName = atom()</v> @@ -479,7 +479,7 @@ </func> <func> - <name>Module:pre_end_per_suite(SuiteName, EndData, CTHState) -> Result</name> + <name since="OTP R14B02">Module:pre_end_per_suite(SuiteName, EndData, CTHState) -> Result</name> <fsummary>Called before end_per_suite.</fsummary> <type> <v>SuiteName = atom()</v> @@ -506,7 +506,7 @@ </func> <func> - <name>Module:post_end_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> + <name since="OTP R14B02">Module:post_end_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> <fsummary>Called after end_per_suite.</fsummary> <type> <v>SuiteName = atom()</v> @@ -533,7 +533,7 @@ </func> <func> - <name>Module:on_tc_fail(SuiteName, TestName, Reason, CTHState) -> NewCTHState</name> + <name since="OTP 19.3">Module:on_tc_fail(SuiteName, TestName, Reason, CTHState) -> NewCTHState</name> <fsummary>Called after the CTH scope ends.</fsummary> <type> <v>SuiteName = atom()</v> @@ -577,7 +577,7 @@ </func> <func> - <name>Module:on_tc_skip(SuiteName, TestName, Reason, CTHState) -> NewCTHState</name> + <name since="OTP 19.3">Module:on_tc_skip(SuiteName, TestName, Reason, CTHState) -> NewCTHState</name> <fsummary>Called after the CTH scope ends.</fsummary> <type> <v>SuiteName = atom()</v> @@ -623,7 +623,7 @@ </func> <func> - <name>Module:terminate(CTHState)</name> + <name since="OTP R14B02">Module:terminate(CTHState)</name> <fsummary>Called after the CTH scope ends.</fsummary> <type> <v>CTHState = term()</v> @@ -637,7 +637,7 @@ </func> <func> - <name>Module:id(Opts) -> Id</name> + <name since="OTP R14B02">Module:id(Opts) -> Id</name> <fsummary>Called before the init function of a CTH.</fsummary> <type> <v>Opts = term()</v> diff --git a/lib/common_test/doc/src/ct_master.xml b/lib/common_test/doc/src/ct_master.xml index 6bde4644c6..2ab421fe9e 100644 --- a/lib/common_test/doc/src/ct_master.xml +++ b/lib/common_test/doc/src/ct_master.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_master.xml</file> </header> - <module>ct_master</module> + <module since="">ct_master</module> <modulesummary>Distributed test execution control for Common Test.</modulesummary> <description> @@ -46,7 +46,7 @@ <funcs> <func> - <name>abort() -> ok</name> + <name since="">abort() -> ok</name> <fsummary>Stops all running tests.</fsummary> <desc><marker id="abort-0"/> <p>Stops all running tests.</p> @@ -54,7 +54,7 @@ </func> <func> - <name>abort(Nodes) -> ok</name> + <name since="">abort(Nodes) -> ok</name> <fsummary>Stops tests on specified nodes.</fsummary> <type> <v>Nodes = atom() | [atom()]</v> @@ -65,7 +65,7 @@ </func> <func> - <name>basic_html(Bool) -> ok</name> + <name since="OTP R15B01">basic_html(Bool) -> ok</name> <fsummary>If set to true, the ct_master logs are written on a primitive HTML format, not using the <c>Common Test</c> CSS style sheet.</fsummary> <type> @@ -79,7 +79,7 @@ </func> <func> - <name>get_event_mgr_ref() -> MasterEvMgrRef</name> + <name since="OTP 17.5">get_event_mgr_ref() -> MasterEvMgrRef</name> <fsummary>Gets a reference to the <c>Common Test</c> master event manager.</fsummary> <type> @@ -98,7 +98,7 @@ </func> <func> - <name>progress() -> [{Node, Status}]</name> + <name since="">progress() -> [{Node, Status}]</name> <fsummary>Returns test progress.</fsummary> <type> <v>Node = atom()</v> @@ -112,7 +112,7 @@ </func> <func> - <name>run(TestSpecs) -> ok</name> + <name since="">run(TestSpecs) -> ok</name> <fsummary>Equivalent to run(TestSpecs, false, [], []).</fsummary> <type> <v>TestSpecs = string() | [SeparateOrMerged]</v> @@ -124,7 +124,7 @@ </func> <func> - <name>run(TestSpecs, InclNodes, ExclNodes) -> ok</name> + <name since="">run(TestSpecs, InclNodes, ExclNodes) -> ok</name> <fsummary>Equivalent to run(TestSpecs, false, InclNodes, ExclNodes). </fsummary> <type> @@ -140,7 +140,7 @@ </func> <func> - <name>run(TestSpecs, AllowUserTerms, InclNodes, ExclNodes) -> ok</name> + <name since="">run(TestSpecs, AllowUserTerms, InclNodes, ExclNodes) -> ok</name> <fsummary>Tests are spawned on the nodes as specified in TestSpecs. </fsummary> <type> @@ -162,7 +162,7 @@ </func> <func> - <name>run_on_node(TestSpecs, Node) -> ok</name> + <name since="">run_on_node(TestSpecs, Node) -> ok</name> <fsummary>Equivalent to run_on_node(TestSpecs, false, Node).</fsummary> <type> <v>TestSpecs = string() | [SeparateOrMerged]</v> @@ -177,7 +177,7 @@ </func> <func> - <name>run_on_node(TestSpecs, AllowUserTerms, Node) -> ok</name> + <name since="">run_on_node(TestSpecs, AllowUserTerms, Node) -> ok</name> <fsummary>Tests are spawned on Node according to TestSpecs.</fsummary> <type> <v>TestSpecs = string() | [SeparateOrMerged]</v> @@ -191,7 +191,7 @@ </func> <func> - <name>run_test(Node, Opts) -> ok</name> + <name since="">run_test(Node, Opts) -> ok</name> <fsummary>Tests are spawned on Node using ct:run_test/1.</fsummary> <type> <v>Node = atom()</v> diff --git a/lib/common_test/doc/src/ct_netconfc.xml b/lib/common_test/doc/src/ct_netconfc.xml index 7ec8f23073..8fbe5f3df6 100644 --- a/lib/common_test/doc/src/ct_netconfc.xml +++ b/lib/common_test/doc/src/ct_netconfc.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_netconfc.xml</file> </header> - <module>ct_netconfc</module> + <module since="OTP R15B02">ct_netconfc</module> <modulesummary>NETCONF client module.</modulesummary> <description> @@ -312,8 +312,8 @@ <funcs> <func> - <name name="action" arity="2"/> - <name name="action" arity="3"/> + <name name="action" arity="2" since="OTP R15B02"/> + <name name="action" arity="3" since="OTP R15B02"/> <fsummary>Executes an action.</fsummary> <desc> <p>Executes an action. If the return type is void, <c>ok</c> is @@ -322,8 +322,8 @@ </func> <func> - <name name="close_session" arity="1"/> - <name name="close_session" arity="2"/> + <name name="close_session" arity="1" since="OTP R15B02"/> + <name name="close_session" arity="2" since="OTP R15B02"/> <fsummary>Requests graceful termination of the session associated with the client.</fsummary> <desc> @@ -339,7 +339,7 @@ </func> <func> - <name name="connect" arity="1"/> + <name name="connect" arity="1" since="OTP 20.0"/> <fsummary>Opens an SSH connection to a NETCONF server.</fsummary> <desc> <p>Opens an SSH connection to a NETCONF server.</p> @@ -361,7 +361,7 @@ </func> <func> - <name name="connect" arity="2"/> + <name name="connect" arity="2" since="OTP 20.0"/> <fsummary>Opens an SSH connection to a named NETCONF server.</fsummary> <desc> <p>Open an SSH connection to a named NETCONF server.</p> @@ -399,8 +399,8 @@ </func> <func> - <name name="copy_config" arity="3"/> - <name name="copy_config" arity="4"/> + <name name="copy_config" arity="3" since="OTP R15B02"/> + <name name="copy_config" arity="4" since="OTP R15B02"/> <fsummary>Copies configuration data.</fsummary> <desc> <p>Copies configuration data.</p> @@ -412,12 +412,12 @@ </func> <func> - <name>create_subscription(Client) -> Result</name> - <name>create_subscription(Client, Stream) -> Result</name> - <name>create_subscription(Client, Stream, Filter) -> Result</name> - <name>create_subscription(Client, Stream, Filter, Timeout) -> Result</name> - <name name="create_subscription" arity="5" clause_i="2"/> - <name name="create_subscription" arity="6"/> + <name since="OTP R15B02">create_subscription(Client) -> Result</name> + <name since="OTP R15B02">create_subscription(Client, Stream) -> Result</name> + <name since="OTP R15B02">create_subscription(Client, Stream, Filter) -> Result</name> + <name since="OTP R15B02">create_subscription(Client, Stream, Filter, Timeout) -> Result</name> + <name name="create_subscription" arity="5" clause_i="2" since="OTP R15B02"/> + <name name="create_subscription" arity="6" since="OTP R15B02"/> <fsummary>Creates a subscription for event notifications.</fsummary> <desc> <p>Creates a subscription for event notifications.</p> @@ -490,8 +490,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="delete_config" arity="2"/> - <name name="delete_config" arity="3"/> + <name name="delete_config" arity="2" since="OTP R15B02"/> + <name name="delete_config" arity="3" since="OTP R15B02"/> <fsummary>Deletes configuration data.</fsummary> <desc> <p>Deletes configuration data.</p> @@ -502,7 +502,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="disconnect" arity="1"/> + <name name="disconnect" arity="1" since="OTP 20.0"/> <fsummary>Closes the given SSH connection.</fsummary> <desc> <p>Closes the given SSH connection.</p> @@ -514,10 +514,10 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="edit_config" arity="3"/> - <name name="edit_config" arity="4" clause_i="1"/> - <name name="edit_config" arity="4" clause_i="2"/> - <name name="edit_config" arity="5"/> + <name name="edit_config" arity="3" since="OTP R15B02"/> + <name name="edit_config" arity="4" clause_i="1" since="OTP 18.0"/> + <name name="edit_config" arity="4" clause_i="2" since="OTP R15B02"/> + <name name="edit_config" arity="5" since="OTP 18.0"/> <fsummary>Edits configuration data.</fsummary> <desc> <p>Edits configuration data.</p> @@ -542,8 +542,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get" arity="2"/> - <name name="get" arity="3"/> + <name name="get" arity="2" since="OTP R15B02"/> + <name name="get" arity="3" since="OTP R15B02"/> <fsummary>Gets data.</fsummary> <desc> <p>Gets data.</p> @@ -557,8 +557,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get_capabilities" arity="1"/> - <name name="get_capabilities" arity="2"/> + <name name="get_capabilities" arity="1" since="OTP R15B02"/> + <name name="get_capabilities" arity="2" since="OTP R15B02"/> <fsummary>Returns the server side capabilities.</fsummary> <desc> <p>Returns the server side capabilities.</p> @@ -582,8 +582,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get_config" arity="3"/> - <name name="get_config" arity="4"/> + <name name="get_config" arity="3" since="OTP R15B02"/> + <name name="get_config" arity="4" since="OTP R15B02"/> <fsummary>Gets configuration data.</fsummary> <desc> <p>Gets configuration data.</p> @@ -597,10 +597,10 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get_event_streams" arity="1"/> - <name name="get_event_streams" arity="2" clause_i="1"/> - <name name="get_event_streams" arity="2" clause_i="2"/> - <name name="get_event_streams" arity="3"/> + <name name="get_event_streams" arity="1" since="OTP 20.0"/> + <name name="get_event_streams" arity="2" clause_i="1" since="OTP R15B02"/> + <name name="get_event_streams" arity="2" clause_i="2" since="OTP 20.0"/> + <name name="get_event_streams" arity="3" since="OTP R15B02"/> <fsummary>Sends a request to get the specified event streams.</fsummary> <desc> <p>Sends a request to get the specified event streams.</p> @@ -637,8 +637,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="get_session_id" arity="1"/> - <name name="get_session_id" arity="2"/> + <name name="get_session_id" arity="1" since="OTP R15B02"/> + <name name="get_session_id" arity="2" since="OTP R15B02"/> <fsummary>Returns the session Id associated with the specified client.</fsummary> <desc> @@ -647,9 +647,9 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="hello" arity="1"/> - <name name="hello" arity="2"/> - <name name="hello" arity="3"/> + <name name="hello" arity="1" since="OTP R15B02"/> + <name name="hello" arity="2" since="OTP R15B02"/> + <name name="hello" arity="3" since="OTP 17.5.3"/> <fsummary>Exchanges hello messages with the server.</fsummary> <desc> <p>Exchanges <c>hello</c> messages with the server.</p> @@ -660,8 +660,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="kill_session" arity="2"/> - <name name="kill_session" arity="3"/> + <name name="kill_session" arity="2" since="OTP R15B02"/> + <name name="kill_session" arity="3" since="OTP R15B02"/> <fsummary>Forces termination of the session associated with the supplied session Id.</fsummary> <desc> @@ -682,8 +682,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="lock" arity="2"/> - <name name="lock" arity="3"/> + <name name="lock" arity="2" since="OTP R15B02"/> + <name name="lock" arity="3" since="OTP R15B02"/> <fsummary>Locks the configuration target.</fsummary> <desc> <p>Locks the configuration target.</p> @@ -703,7 +703,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="only_open" arity="1"/> + <name name="only_open" arity="1" since="OTP R15B02"/> <fsummary>Opens a NETCONF session, but does not send hello.</fsummary> <desc> <p>Opens a NETCONF session, but does not send <c>hello</c>.</p> @@ -714,7 +714,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="only_open" arity="2"/> + <name name="only_open" arity="2" since="OTP R15B02"/> <fsummary>Opens a named NETCONF session, but does not send hello.</fsummary> <desc> <p>Opens a named NETCONF session, but does not send <c>hello</c>.</p> @@ -725,7 +725,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="open" arity="1"/> + <name name="open" arity="1" since="OTP R15B02"/> <fsummary>Opens a NETCONF session and exchanges hello messages.</fsummary> <desc> <p>Opens a NETCONF session and exchanges <c>hello</c> messages.</p> @@ -749,7 +749,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="open" arity="2"/> + <name name="open" arity="2" since="OTP R15B02"/> <fsummary>Opens a named NETCONF session and exchanges hello messages.</fsummary> <desc> @@ -791,8 +791,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="send" arity="2"/> - <name name="send" arity="3"/> + <name name="send" arity="2" since="OTP R16B02"/> + <name name="send" arity="3" since="OTP R16B02"/> <fsummary>Sends an XML document to the server.</fsummary> <desc> <p>Sends an XML document to the server.</p> @@ -804,8 +804,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="send_rpc" arity="2"/> - <name name="send_rpc" arity="3"/> + <name name="send_rpc" arity="2" since="OTP R16B02"/> + <name name="send_rpc" arity="3" since="OTP R16B02"/> <fsummary>Sends a NETCONF rpc request to the server.</fsummary> <desc> <p>Sends a NETCONF <c>rpc</c> request to the server.</p> @@ -820,10 +820,10 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="session" arity="1"/> - <name name="session" arity="2" clause_i="1"/> - <name name="session" arity="2" clause_i="2"/> - <name name="session" arity="3"/> + <name name="session" arity="1" since="OTP 20.0"/> + <name name="session" arity="2" clause_i="1" since="OTP 20.0"/> + <name name="session" arity="2" clause_i="2" since="OTP 20.0"/> + <name name="session" arity="3" since="OTP 20.0"/> <fsummary>Opens a NETCONF session as a channel on the given SSH connection, and exchanges hello messages with the server.</fsummary> @@ -848,8 +848,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre> </func> <func> - <name name="unlock" arity="2"/> - <name name="unlock" arity="3"/> + <name name="unlock" arity="2" since="OTP R15B02"/> + <name name="unlock" arity="3" since="OTP R15B02"/> <fsummary>Unlocks the configuration target.</fsummary> <desc> <p>Unlocks the configuration target.</p> diff --git a/lib/common_test/doc/src/ct_property_test.xml b/lib/common_test/doc/src/ct_property_test.xml index 028e5eb69f..1e01d9a5d7 100644 --- a/lib/common_test/doc/src/ct_property_test.xml +++ b/lib/common_test/doc/src/ct_property_test.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_property_test.xml</file> </header> - <module>ct_property_test</module> + <module since="OTP 17.3">ct_property_test</module> <modulesummary>EXPERIMENTAL support in Common Test for calling property-based tests.</modulesummary> @@ -79,7 +79,7 @@ <funcs> <func> - <name>init_per_suite(Config) -> Config | {skip, Reason}</name> + <name since="OTP 17.3">init_per_suite(Config) -> Config | {skip, Reason}</name> <fsummary>Initializes Config for property testing.</fsummary> <desc><marker id="init_per_suite-1"/> <p>Initializes <c>Config</c> for property testing.</p> @@ -98,7 +98,7 @@ </func> <func> - <name>quickcheck(Property, Config) -> true | {fail, Reason}</name> + <name since="OTP 17.3">quickcheck(Property, Config) -> true | {fail, Reason}</name> <fsummary>Calls quickcheck and returns the result in a form suitable for Common Test.</fsummary> <desc><marker id="quickcheck-2"/> diff --git a/lib/common_test/doc/src/ct_rpc.xml b/lib/common_test/doc/src/ct_rpc.xml index 90e6b833f7..00a4dcec08 100644 --- a/lib/common_test/doc/src/ct_rpc.xml +++ b/lib/common_test/doc/src/ct_rpc.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_rpc.xml</file> </header> - <module>ct_rpc</module> + <module since="">ct_rpc</module> <modulesummary>Common Test specific layer on Erlang/OTP rpc.</modulesummary> <description> @@ -43,7 +43,7 @@ <funcs> <func> - <name>app_node(App, Candidates) -> NodeName</name> + <name since="">app_node(App, Candidates) -> NodeName</name> <fsummary>From a set of candidate nodes determines which of them is running the application App.</fsummary> <type> @@ -61,7 +61,7 @@ </func> <func> - <name>app_node(App, Candidates, FailOnBadRPC) -> NodeName</name> + <name since="">app_node(App, Candidates, FailOnBadRPC) -> NodeName</name> <fsummary>Same as app_node/2, except that argument FailOnBadRPC determines if the search for a candidate node is to stop if badrpc is received at some point.</fsummary> @@ -81,7 +81,7 @@ </func> <func> - <name>app_node(App, Candidates, FailOnBadRPC, Cookie) -> NodeName</name> + <name since="">app_node(App, Candidates, FailOnBadRPC, Cookie) -> NodeName</name> <fsummary>Same as app_node/2, except that argument FailOnBadRPC determines if the search for a candidate node is to stop if badrpc is received at some point.</fsummary> @@ -105,7 +105,7 @@ </func> <func> - <name>call(Node, Module, Function, Args) -> term() | {badrpc, Reason}</name> + <name since="">call(Node, Module, Function, Args) -> term() | {badrpc, Reason}</name> <fsummary>Same as call(Node, Module, Function, Args, infinity).</fsummary> <desc><marker id="call-4"/> <p>Same as <c>call(Node, Module, Function, Args, infinity)</c>.</p> @@ -113,7 +113,7 @@ </func> <func> - <name>call(Node, Module, Function, Args, TimeOut) -> term() | {badrpc, Reason}</name> + <name since="">call(Node, Module, Function, Args, TimeOut) -> term() | {badrpc, Reason}</name> <fsummary>Evaluates apply(Module, Function, Args) on the node Node.</fsummary> <type> @@ -136,7 +136,7 @@ </func> <func> - <name>call(Node, Module, Function, Args, TimeOut, Cookie) -> term() | {badrpc, Reason}</name> + <name since="">call(Node, Module, Function, Args, TimeOut, Cookie) -> term() | {badrpc, Reason}</name> <fsummary>Evaluates apply(Module, Function, Args) on the node Node.</fsummary> <type> @@ -163,7 +163,7 @@ </func> <func> - <name>cast(Node, Module, Function, Args) -> ok</name> + <name since="">cast(Node, Module, Function, Args) -> ok</name> <fsummary>Evaluates apply(Module, Function, Args) on the node Node.</fsummary> <type> @@ -187,7 +187,7 @@ </func> <func> - <name>cast(Node, Module, Function, Args, Cookie) -> ok</name> + <name since="">cast(Node, Module, Function, Args, Cookie) -> ok</name> <fsummary>Evaluates apply(Module, Function, Args) on the node Node.</fsummary> <type> diff --git a/lib/common_test/doc/src/ct_slave.xml b/lib/common_test/doc/src/ct_slave.xml index 9d9aa50051..84e619482d 100644 --- a/lib/common_test/doc/src/ct_slave.xml +++ b/lib/common_test/doc/src/ct_slave.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_slave.xml</file> </header> - <module>ct_slave</module> + <module since="OTP R14B">ct_slave</module> <modulesummary>Common Test framework functions for starting and stopping nodes for Large-Scale Testing.</modulesummary> @@ -50,7 +50,7 @@ <funcs> <func> - <name>start(Node) -> Result</name> + <name since="OTP R14B">start(Node) -> Result</name> <fsummary>Starts an Erlang node with name Node on the local host.</fsummary> <type> @@ -68,7 +68,7 @@ </func> <func> - <name>start(HostOrNode, NodeOrOpts) -> Result</name> + <name since="OTP R14B">start(HostOrNode, NodeOrOpts) -> Result</name> <fsummary>Starts an Erlang node with default options on a specified host, or on the local host with specified options.</fsummary> <type> @@ -90,7 +90,7 @@ </func> <func> - <name>start(Host, Node, Opts) -> Result</name> + <name since="OTP R14B">start(Host, Node, Opts) -> Result</name> <fsummary>Starts an Erlang node with name Node on host Host as specified by the combination of options in Opts.</fsummary> <type> @@ -184,7 +184,7 @@ </func> <func> - <name>stop(Node) -> Result</name> + <name since="OTP R14B">stop(Node) -> Result</name> <fsummary>Stops the running Erlang node with name Node on the local host.</fsummary> <type> @@ -199,7 +199,7 @@ </func> <func> - <name>stop(Host, Node) -> Result</name> + <name since="OTP R14B">stop(Host, Node) -> Result</name> <fsummary>Stops the running Erlang node with name Node on host Host.</fsummary> <type> diff --git a/lib/common_test/doc/src/ct_snmp.xml b/lib/common_test/doc/src/ct_snmp.xml index 0a5e52b16c..343781814a 100644 --- a/lib/common_test/doc/src/ct_snmp.xml +++ b/lib/common_test/doc/src/ct_snmp.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_snmp.xml</file> </header> - <module>ct_snmp</module> + <module since="">ct_snmp</module> <modulesummary>Common Test user interface module for the SNMP application.</modulesummary> <description> @@ -240,7 +240,7 @@ <funcs> <func> - <name>get_next_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> + <name since="">get_next_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> <fsummary>Issues a synchronous SNMP get next request.</fsummary> <type> <v>Agent = agent_name()</v> @@ -254,7 +254,7 @@ </func> <func> - <name>get_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> + <name since="">get_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> <fsummary>Issues a synchronous SNMP get request.</fsummary> <type> <v>Agent = agent_name()</v> @@ -268,7 +268,7 @@ </func> <func> - <name>load_mibs(Mibs) -> ok | {error, Reason}</name> + <name since="">load_mibs(Mibs) -> ok | {error, Reason}</name> <fsummary>Loads the MIBs into agent snmp_master_agent.</fsummary> <type> <v>Mibs = [MibName]</v> @@ -281,7 +281,7 @@ </func> <func> - <name>register_agents(MgrAgentConfName, ManagedAgents) -> ok | {error, Reason}</name> + <name since="">register_agents(MgrAgentConfName, ManagedAgents) -> ok | {error, Reason}</name> <fsummary>Explicitly instructs the manager to handle this agent.</fsummary> <type> @@ -300,7 +300,7 @@ </func> <func> - <name>register_users(MgrAgentConfName, Users) -> ok | {error, Reason}</name> + <name since="">register_users(MgrAgentConfName, Users) -> ok | {error, Reason}</name> <fsummary>Registers the manager entity (=user) responsible for specific agent(s).</fsummary> <type> @@ -319,7 +319,7 @@ </func> <func> - <name>register_usm_users(MgrAgentConfName, UsmUsers) -> ok | {error, Reason}</name> + <name since="">register_usm_users(MgrAgentConfName, UsmUsers) -> ok | {error, Reason}</name> <fsummary>Explicitly instructs the manager to handle this USM user.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -337,7 +337,7 @@ </func> <func> - <name>set_info(Config) -> [{Agent, OldVarsAndVals, NewVarsAndVals}]</name> + <name since="">set_info(Config) -> [{Agent, OldVarsAndVals, NewVarsAndVals}]</name> <fsummary>Returns a list of all successful set requests performed in the test case in reverse order.</fsummary> <type> @@ -357,7 +357,7 @@ </func> <func> - <name>set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> SnmpReply</name> + <name since="">set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> SnmpReply</name> <fsummary>Issues a synchronous SNMP set request.</fsummary> <type> <v>Agent = agent_name()</v> @@ -372,7 +372,7 @@ </func> <func> - <name>start(Config, MgrAgentConfName) -> ok</name> + <name since="">start(Config, MgrAgentConfName) -> ok</name> <fsummary>Equivalent to start(Config, MgrAgentConfName, undefined).</fsummary> <desc><marker id="start-2"/> @@ -383,7 +383,7 @@ </func> <func> - <name>start(Config, MgrAgentConfName, SnmpAppConfName) -> ok</name> + <name since="">start(Config, MgrAgentConfName, SnmpAppConfName) -> ok</name> <fsummary>Starts an SNMP manager and/or agent.</fsummary> <type> <v>Config = [{Key, Value}]</v> @@ -415,7 +415,7 @@ </func> <func> - <name>stop(Config) -> ok</name> + <name since="">stop(Config) -> ok</name> <fsummary>Stops the SNMP manager and/or agent, and removes all files created.</fsummary> <type> @@ -430,7 +430,7 @@ </func> <func> - <name>unload_mibs(Mibs) -> ok | {error, Reason}</name> + <name since="OTP R16B">unload_mibs(Mibs) -> ok | {error, Reason}</name> <fsummary>Unloads the MIBs from agent snmp_master_agent.</fsummary> <type> <v>Mibs = [MibName]</v> @@ -443,7 +443,7 @@ </func> <func> - <name>unregister_agents(MgrAgentConfName) -> ok</name> + <name since="">unregister_agents(MgrAgentConfName) -> ok</name> <fsummary>Unregisters all managed agents.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -455,7 +455,7 @@ </func> <func> - <name>unregister_agents(MgrAgentConfName, ManagedAgents) -> ok</name> + <name since="OTP R16B">unregister_agents(MgrAgentConfName, ManagedAgents) -> ok</name> <fsummary>Unregisters the specified managed agents.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -468,7 +468,7 @@ </func> <func> - <name>unregister_users(MgrAgentConfName) -> ok</name> + <name since="">unregister_users(MgrAgentConfName) -> ok</name> <fsummary>Unregisters all users.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -480,7 +480,7 @@ </func> <func> - <name>unregister_users(MgrAgentConfName, Users) -> ok</name> + <name since="OTP R16B">unregister_users(MgrAgentConfName, Users) -> ok</name> <fsummary>Unregisters the specified users.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -493,7 +493,7 @@ </func> <func> - <name>unregister_usm_users(MgrAgentConfName) -> ok</name> + <name since="OTP R16B">unregister_usm_users(MgrAgentConfName) -> ok</name> <fsummary>Unregisters all USM users.</fsummary> <type> <v>MgrAgentConfName = atom()</v> @@ -505,7 +505,7 @@ </func> <func> - <name>unregister_usm_users(MgrAgentConfName, UsmUsers) -> ok</name> + <name since="OTP R16B">unregister_usm_users(MgrAgentConfName, UsmUsers) -> ok</name> <fsummary>Unregisters the specified USM users.</fsummary> <type> <v>MgrAgentConfName = atom()</v> diff --git a/lib/common_test/doc/src/ct_ssh.xml b/lib/common_test/doc/src/ct_ssh.xml index 0c7efed154..8d9f31aff8 100644 --- a/lib/common_test/doc/src/ct_ssh.xml +++ b/lib/common_test/doc/src/ct_ssh.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_ssh.xml</file> </header> - <module>ct_ssh</module> + <module since="">ct_ssh</module> <modulesummary>SSH/SFTP client module.</modulesummary> <description> @@ -95,7 +95,7 @@ <funcs> <func> - <name>apread(SSH, Handle, Position, Length) -> Result</name> + <name since="">apread(SSH, Handle, Position, Length) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -109,7 +109,7 @@ </func> <func> - <name>apread(SSH, Server, Handle, Position, Length) -> Result</name> + <name since="">apread(SSH, Server, Handle, Position, Length) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -123,7 +123,7 @@ </func> <func> - <name>apwrite(SSH, Handle, Position, Data) -> Result</name> + <name since="">apwrite(SSH, Handle, Position, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -137,7 +137,7 @@ </func> <func> - <name>apwrite(SSH, Server, Handle, Position, Data) -> Result</name> + <name since="">apwrite(SSH, Server, Handle, Position, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -151,7 +151,7 @@ </func> <func> - <name>aread(SSH, Handle, Len) -> Result</name> + <name since="">aread(SSH, Handle, Len) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -165,7 +165,7 @@ </func> <func> - <name>aread(SSH, Server, Handle, Len) -> Result</name> + <name since="">aread(SSH, Server, Handle, Len) -> Result</name> <fsummary>For inforamtion and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -179,7 +179,7 @@ </func> <func> - <name>awrite(SSH, Handle, Data) -> Result</name> + <name since="">awrite(SSH, Handle, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -193,7 +193,7 @@ </func> <func> - <name>awrite(SSH, Server, Handle, Data) -> Result</name> + <name since="">awrite(SSH, Server, Handle, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -207,7 +207,7 @@ </func> <func> - <name>close(SSH, Handle) -> Result</name> + <name since="">close(SSH, Handle) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -221,7 +221,7 @@ </func> <func> - <name>close(SSH, Server, Handle) -> Result</name> + <name since="">close(SSH, Server, Handle) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -235,7 +235,7 @@ </func> <func> - <name>connect(KeyOrName) -> {ok, Handle} | {error, Reason}</name> + <name since="">connect(KeyOrName) -> {ok, Handle} | {error, Reason}</name> <fsummary>Equivalent to connect(KeyOrName, host, []).</fsummary> <desc><marker id="connect-1"/> <p>Equivalent to @@ -245,7 +245,7 @@ </func> <func> - <name>connect(KeyOrName, ConnType) -> {ok, Handle} | {error, Reason}</name> + <name since="">connect(KeyOrName, ConnType) -> {ok, Handle} | {error, Reason}</name> <fsummary>Equivalent to connect(KeyOrName, ConnType, []).</fsummary> <desc><marker id="connect-2"/> <p>Equivalent to @@ -255,7 +255,7 @@ </func> <func> - <name>connect(KeyOrName, ConnType, ExtraOpts) -> {ok, Handle} | {error, Reason}</name> + <name since="">connect(KeyOrName, ConnType, ExtraOpts) -> {ok, Handle} | {error, Reason}</name> <fsummary>Opens an SSH or SFTP connection using the information associated with KeyOrName.</fsummary> <type> @@ -301,7 +301,7 @@ </func> <func> - <name>del_dir(SSH, Name) -> Result</name> + <name since="">del_dir(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -315,7 +315,7 @@ </func> <func> - <name>del_dir(SSH, Server, Name) -> Result</name> + <name since="">del_dir(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -329,7 +329,7 @@ </func> <func> - <name>delete(SSH, Name) -> Result</name> + <name since="">delete(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -343,7 +343,7 @@ </func> <func> - <name>delete(SSH, Server, Name) -> Result</name> + <name since="">delete(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -357,7 +357,7 @@ </func> <func> - <name>disconnect(SSH) -> ok | {error, Reason}</name> + <name since="">disconnect(SSH) -> ok | {error, Reason}</name> <fsummary>Closes an SSH/SFTP connection.</fsummary> <type> <v>SSH = connection()</v> @@ -369,7 +369,7 @@ </func> <func> - <name>exec(SSH, Command) -> {ok, Data} | {error, Reason}</name> + <name since="">exec(SSH, Command) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to exec(SSH, Command, DefaultTimeout).</fsummary> <desc><marker id="exec-2"/> <p>Equivalent to @@ -379,7 +379,7 @@ </func> <func> - <name>exec(SSH, Command, Timeout) -> {ok, Data} | {error, Reason}</name> + <name since="">exec(SSH, Command, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Requests server to perform Command.</fsummary> <type> <v>SSH = connection()</v> @@ -396,7 +396,7 @@ </func> <func> - <name>exec(SSH, ChannelId, Command, Timeout) -> {ok, Data} | {error, Reason}</name> + <name since="">exec(SSH, ChannelId, Command, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Requests server to perform Command.</fsummary> <type> <v>SSH = connection()</v> @@ -414,7 +414,7 @@ </func> <func> - <name>get_file_info(SSH, Handle) -> Result</name> + <name since="">get_file_info(SSH, Handle) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -428,7 +428,7 @@ </func> <func> - <name>get_file_info(SSH, Server, Handle) -> Result</name> + <name since="">get_file_info(SSH, Server, Handle) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -442,7 +442,7 @@ </func> <func> - <name>list_dir(SSH, Path) -> Result</name> + <name since="">list_dir(SSH, Path) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -456,7 +456,7 @@ </func> <func> - <name>list_dir(SSH, Server, Path) -> Result</name> + <name since="">list_dir(SSH, Server, Path) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -470,7 +470,7 @@ </func> <func> - <name>make_dir(SSH, Name) -> Result</name> + <name since="">make_dir(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -484,7 +484,7 @@ </func> <func> - <name>make_dir(SSH, Server, Name) -> Result</name> + <name since="">make_dir(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -498,7 +498,7 @@ </func> <func> - <name>make_symlink(SSH, Name, Target) -> Result</name> + <name since="">make_symlink(SSH, Name, Target) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -512,7 +512,7 @@ </func> <func> - <name>make_symlink(SSH, Server, Name, Target) -> Result</name> + <name since="">make_symlink(SSH, Server, Name, Target) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -526,7 +526,7 @@ </func> <func> - <name>open(SSH, File, Mode) -> Result</name> + <name since="">open(SSH, File, Mode) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -540,7 +540,7 @@ </func> <func> - <name>open(SSH, Server, File, Mode) -> Result</name> + <name since="">open(SSH, Server, File, Mode) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -554,7 +554,7 @@ </func> <func> - <name>opendir(SSH, Path) -> Result</name> + <name since="">opendir(SSH, Path) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -568,7 +568,7 @@ </func> <func> - <name>opendir(SSH, Server, Path) -> Result</name> + <name since="">opendir(SSH, Server, Path) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -582,7 +582,7 @@ </func> <func> - <name>position(SSH, Handle, Location) -> Result</name> + <name since="">position(SSH, Handle, Location) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -596,7 +596,7 @@ </func> <func> - <name>position(SSH, Server, Handle, Location) -> Result</name> + <name since="">position(SSH, Server, Handle, Location) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -610,7 +610,7 @@ </func> <func> - <name>pread(SSH, Handle, Position, Length) -> Result</name> + <name since="">pread(SSH, Handle, Position, Length) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -624,7 +624,7 @@ </func> <func> - <name>pread(SSH, Server, Handle, Position, Length) -> Result</name> + <name since="">pread(SSH, Server, Handle, Position, Length) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -638,7 +638,7 @@ </func> <func> - <name>pwrite(SSH, Handle, Position, Data) -> Result</name> + <name since="">pwrite(SSH, Handle, Position, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -652,7 +652,7 @@ </func> <func> - <name>pwrite(SSH, Server, Handle, Position, Data) -> Result</name> + <name since="">pwrite(SSH, Server, Handle, Position, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -666,7 +666,7 @@ </func> <func> - <name>read(SSH, Handle, Len) -> Result</name> + <name since="">read(SSH, Handle, Len) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -680,7 +680,7 @@ </func> <func> - <name>read(SSH, Server, Handle, Len) -> Result</name> + <name since="">read(SSH, Server, Handle, Len) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -694,7 +694,7 @@ </func> <func> - <name>read_file(SSH, File) -> Result</name> + <name since="">read_file(SSH, File) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -708,7 +708,7 @@ </func> <func> - <name>read_file(SSH, Server, File) -> Result</name> + <name since="">read_file(SSH, Server, File) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -722,7 +722,7 @@ </func> <func> - <name>read_file_info(SSH, Name) -> Result</name> + <name since="">read_file_info(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -736,7 +736,7 @@ </func> <func> - <name>read_file_info(SSH, Server, Name) -> Result</name> + <name since="">read_file_info(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -750,7 +750,7 @@ </func> <func> - <name>read_link(SSH, Name) -> Result</name> + <name since="">read_link(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -764,7 +764,7 @@ </func> <func> - <name>read_link(SSH, Server, Name) -> Result</name> + <name since="">read_link(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -778,7 +778,7 @@ </func> <func> - <name>read_link_info(SSH, Name) -> Result</name> + <name since="">read_link_info(SSH, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -792,7 +792,7 @@ </func> <func> - <name>read_link_info(SSH, Server, Name) -> Result</name> + <name since="">read_link_info(SSH, Server, Name) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -806,7 +806,7 @@ </func> <func> - <name>receive_response(SSH, ChannelId) -> {ok, Data} | {error, Reason}</name> + <name since="">receive_response(SSH, ChannelId) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to receive_response(SSH, ChannelId, close).</fsummary> <desc><marker id="receive_response-2"/> @@ -817,7 +817,7 @@ ChannelId, close)</c></seealso>.</p> </func> <func> - <name>receive_response(SSH, ChannelId, End) -> {ok, Data} | {error, Reason}</name> + <name since="">receive_response(SSH, ChannelId, End) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to receive_response(SSH, ChannelId, End, DefaultTimeout).</fsummary> <desc><marker id="receive_response-3"/> @@ -828,7 +828,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>receive_response(SSH, ChannelId, End, Timeout) -> {ok, Data} | {timeout, Data} | {error, Reason}</name> + <name since="">receive_response(SSH, ChannelId, End, Timeout) -> {ok, Data} | {timeout, Data} | {error, Reason}</name> <fsummary>Receives expected data from server on the specified session channel.</fsummary> <type> @@ -863,7 +863,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>rename(SSH, OldName, NewName) -> Result</name> + <name since="">rename(SSH, OldName, NewName) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -877,7 +877,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>rename(SSH, Server, OldName, NewName) -> Result</name> + <name since="">rename(SSH, Server, OldName, NewName) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -891,7 +891,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send(SSH, ChannelId, Data) -> ok | {error, Reason}</name> + <name since="">send(SSH, ChannelId, Data) -> ok | {error, Reason}</name> <fsummary>Equivalent to send(SSH, ChannelId, 0, Data, DefaultTimeout).</fsummary> <desc><marker id="send-3"/> @@ -901,7 +901,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send(SSH, ChannelId, Data, Timeout) -> ok | {error, Reason}</name> + <name since="">send(SSH, ChannelId, Data, Timeout) -> ok | {error, Reason}</name> <fsummary>Equivalent to send(SSH, ChannelId, 0, Data, Timeout).</fsummary> <desc><marker id="send-4"/> <p>Equivalent to <seealso marker="#send-5"><c>ct_ssh:send(SSH, @@ -910,7 +910,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send(SSH, ChannelId, Type, Data, Timeout) -> ok | {error, Reason}</name> + <name since="">send(SSH, ChannelId, Type, Data, Timeout) -> ok | {error, Reason}</name> <fsummary>Sends data to server on specified session channel.</fsummary> <type> <v>SSH = connection()</v> @@ -926,7 +926,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send_and_receive(SSH, ChannelId, Data) -> {ok, Data} | {error, Reason}</name> + <name since="">send_and_receive(SSH, ChannelId, Data) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to send_and_receive(SSH, ChannelId, Data, close).</fsummary> <desc><marker id="send_and_receive-3"/> @@ -937,7 +937,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send_and_receive(SSH, ChannelId, Data, End) -> {ok, Data} | {error, Reason}</name> + <name since="">send_and_receive(SSH, ChannelId, Data, End) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to send_and_receive(SSH, ChannelId, 0, Data, End, DefaultTimeout).</fsummary> <desc><marker id="send_and_receive-4"/> @@ -948,7 +948,7 @@ ChannelId, 0, Data, End, DefaultTimeout)</c></seealso>.</p> </func> <func> - <name>send_and_receive(SSH, ChannelId, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> + <name since="">send_and_receive(SSH, ChannelId, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to send_and_receive(SSH, ChannelId, 0, Data, End, Timeout).</fsummary> <desc><marker id="send_and_receive-5"/> @@ -959,7 +959,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> + <name since="">send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Sends data to server on specified session channel and waits to receive the server response.</fsummary> <type> @@ -981,7 +981,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>session_close(SSH, ChannelId) -> ok | {error, Reason}</name> + <name since="">session_close(SSH, ChannelId) -> ok | {error, Reason}</name> <fsummary>Closes an SSH session channel.</fsummary> <type> <v>SSH = connection()</v> @@ -994,7 +994,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>session_open(SSH) -> {ok, ChannelId} | {error, Reason}</name> + <name since="">session_open(SSH) -> {ok, ChannelId} | {error, Reason}</name> <fsummary>Equivalent to session_open(SSH, DefaultTimeout).</fsummary> <desc><marker id="session_open-1"/> <p>Equivalent to @@ -1004,7 +1004,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>session_open(SSH, Timeout) -> {ok, ChannelId} | {error, Reason}</name> + <name since="">session_open(SSH, Timeout) -> {ok, ChannelId} | {error, Reason}</name> <fsummary>Opens a channel for an SSH session.</fsummary> <type> <v>SSH = connection()</v> @@ -1018,7 +1018,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>sftp_connect(SSH) -> {ok, Server} | {error, Reason}</name> + <name since="">sftp_connect(SSH) -> {ok, Server} | {error, Reason}</name> <fsummary>Starts an SFTP session on an already existing SSH connection.</fsummary> <type> @@ -1034,7 +1034,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>shell(SSH, ChannelId) -> ok | {error, Reason}</name> + <name since="OTP 20.0">shell(SSH, ChannelId) -> ok | {error, Reason}</name> <fsummary>Equivalent to shell(SSH, ChannelId, DefaultTimeout).</fsummary> <desc><marker id="shell-2"/> <p>Equivalent to @@ -1044,7 +1044,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>shell(SSH, ChannelId, Timeout) -> ok | {error, Reason}</name> + <name since="OTP 20.0">shell(SSH, ChannelId, Timeout) -> ok | {error, Reason}</name> <fsummary>Requests that the user default shell is executed at the server end.</fsummary> <type> @@ -1061,7 +1061,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>subsystem(SSH, ChannelId, Subsystem) -> Status | {error, Reason}</name> + <name since="">subsystem(SSH, ChannelId, Subsystem) -> Status | {error, Reason}</name> <fsummary>Equivalent to subsystem(SSH, ChannelId, Subsystem, DefaultTimeout).</fsummary> <desc><marker id="subsystem-3"/> @@ -1072,7 +1072,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>subsystem(SSH, ChannelId, Subsystem, Timeout) -> Status | {error, Reason}</name> + <name since="">subsystem(SSH, ChannelId, Subsystem, Timeout) -> Status | {error, Reason}</name> <fsummary>Sends a request to execute a predefined subsystem.</fsummary> <type> <v>SSH = connection()</v> @@ -1088,7 +1088,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write(SSH, Handle, Data) -> Result</name> + <name since="">write(SSH, Handle, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1102,7 +1102,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write(SSH, Server, Handle, Data) -> Result</name> + <name since="">write(SSH, Server, Handle, Data) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1116,7 +1116,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write_file(SSH, File, Iolist) -> Result</name> + <name since="">write_file(SSH, File, Iolist) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1130,7 +1130,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write_file(SSH, Server, File, Iolist) -> Result</name> + <name since="">write_file(SSH, Server, File, Iolist) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1144,7 +1144,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write_file_info(SSH, Name, Info) -> Result</name> + <name since="">write_file_info(SSH, Name, Info) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> @@ -1158,7 +1158,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> </func> <func> - <name>write_file_info(SSH, Server, Name, Info) -> Result</name> + <name since="">write_file_info(SSH, Server, Name, Info) -> Result</name> <fsummary>For information and other types, see ssh_sftp(3).</fsummary> <type> <v>SSH = connection()</v> diff --git a/lib/common_test/doc/src/ct_telnet.xml b/lib/common_test/doc/src/ct_telnet.xml index 8e85cccc99..76f5305c46 100644 --- a/lib/common_test/doc/src/ct_telnet.xml +++ b/lib/common_test/doc/src/ct_telnet.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_telnet.xml</file> </header> - <module>ct_telnet</module> + <module since="">ct_telnet</module> <modulesummary>Common Test specific layer on top of Telnet client ct_telnet_client.erl</modulesummary> <description> @@ -205,7 +205,7 @@ <funcs> <func> - <name>close(Connection) -> ok | {error, Reason}</name> + <name since="">close(Connection) -> ok | {error, Reason}</name> <fsummary>Closes the Telnet connection and stops the process managing it.</fsummary> <type> @@ -223,7 +223,7 @@ </func> <func> - <name>cmd(Connection, Cmd) -> {ok, Data} | {error, Reason}</name> + <name since="">cmd(Connection, Cmd) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to cmd(Connection, Cmd, []).</fsummary> <desc><marker id="cmd-2"/> <p>Equivalent to @@ -233,24 +233,27 @@ </func> <func> - <name>cmd(Connection, Cmd, Opts) -> {ok, Data} | {error, Reason}</name> + <name since="">cmd(Connection, Cmd, Opts) -> {ok, Data} | {error, Reason}</name> <fsummary>Sends a command through Telnet and waits for prompt.</fsummary> <type> <v>Connection = connection()</v> <v>Cmd = string()</v> <v>Opts = [Opt]</v> - <v>Opt = {timeout, timeout()} | {newline, boolean()}</v> + <v>Opt = {timeout, timeout()} | {newline, boolean() | string()}</v> <v>Data = [string()]</v> <v>Reason = term()</v> </type> <desc><marker id="cmd-3"/> <p>Sends a command through Telnet and waits for prompt.</p> - <p>By default, this function adds a new line to the end of the + <p>By default, this function adds "\n" to the end of the specified command. If this is not desired, use option <c>{newline,false}</c>. This is necessary, for example, when sending Telnet command sequences prefixed with character - Interprete As Command (IAC).</p> + Interpret As Command (IAC). Option <c>{newline,string()}</c> + can also be used if a different line end than "\n" is + required, for instance <c>{newline,"\r\n"}</c>, to add both + carriage return and newline characters.</p> <p>Option <c>timeout</c> specifies how long the client must wait for prompt. If the time expires, the function returns @@ -262,7 +265,7 @@ </func> <func> - <name>cmdf(Connection, CmdFormat, Args) -> {ok, Data} | {error, Reason}</name> + <name since="">cmdf(Connection, CmdFormat, Args) -> {ok, Data} | {error, Reason}</name> <fsummary>Equivalent to cmdf(Connection, CmdFormat, Args, []).</fsummary> <desc><marker id="cmdf-3"/> <p>Equivalent to @@ -272,7 +275,7 @@ </func> <func> - <name>cmdf(Connection, CmdFormat, Args, Opts) -> {ok, Data} | {error, Reason}</name> + <name since="">cmdf(Connection, CmdFormat, Args, Opts) -> {ok, Data} | {error, Reason}</name> <fsummary>Sends a Telnet command and waits for prompt (uses a format string and a list of arguments to build the command).</fsummary> <type> @@ -280,7 +283,7 @@ <v>CmdFormat = string()</v> <v>Args = list()</v> <v>Opts = [Opt]</v> - <v>Opt = {timeout, timeout()} | {newline, boolean()}</v> + <v>Opt = {timeout, timeout()} | {newline, boolean() | string()}</v> <v>Data = [string()]</v> <v>Reason = term()</v> </type> @@ -294,7 +297,7 @@ </func> <func> - <name>expect(Connection, Patterns) -> term()</name> + <name since="">expect(Connection, Patterns) -> term()</name> <fsummary>Equivalent to expect(Connections, Patterns, []).</fsummary> <desc><marker id="expect-2"/> <p>Equivalent to @@ -304,7 +307,7 @@ </func> <func> - <name>expect(Connection, Patterns, Opts) -> {ok, Match} | {ok, MatchList, HaltReason} | {error, Reason}</name> + <name since="">expect(Connection, Patterns, Opts) -> {ok, Match} | {ok, MatchList, HaltReason} | {error, Reason}</name> <fsummary>Gets data from Telnet and waits for the expected pattern.</fsummary> <type> @@ -339,7 +342,7 @@ subexpression number <c>N</c>. Subexpressions are denoted with <c>'(' ')'</c> in the regular expression.</p> - <p>If a <c>Tag</c> is speciifed, the returned <c>Match</c> also + <p>If a <c>Tag</c> is specified, the returned <c>Match</c> also includes the matched <c>Tag</c>. Otherwise, only <c>RxMatch</c> is returned.</p> @@ -382,7 +385,7 @@ can abort the operation of waiting for prompt.</p></item> <tag><c>repeat | repeat, N</c></tag> <item><p>The pattern(s) must be matched multiple times. If <c>N</c> - is speciified, the pattern(s) are matched <c>N</c> times, and + is specified, the pattern(s) are matched <c>N</c> times, and the function returns <c>HaltReason = done</c>. This option can be interrupted by one or more <c>HaltPatterns</c>. <c>MatchList</c> is always returned, that is, a list of <c>Match</c> instead of @@ -422,7 +425,7 @@ </func> <func> - <name>get_data(Connection) -> {ok, Data} | {error, Reason}</name> + <name since="">get_data(Connection) -> {ok, Data} | {error, Reason}</name> <fsummary>Gets all data received by the Telnet client since the last command was sent.</fsummary> <type> @@ -446,7 +449,7 @@ </func> <func> - <name>open(Name) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(Name) -> {ok, Handle} | {error, Reason}</name> <fsummary>Equivalent to open(Name, telnet).</fsummary> <desc><marker id="open-1"/> <p>Equivalent to @@ -456,7 +459,7 @@ </func> <func> - <name>open(Name, ConnType) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(Name, ConnType) -> {ok, Handle} | {error, Reason}</name> <fsummary>Opens a Telnet connection to the specified target host.</fsummary> <type> @@ -471,7 +474,7 @@ </func> <func> - <name>open(KeyOrName, ConnType, TargetMod) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(KeyOrName, ConnType, TargetMod) -> {ok, Handle} | {error, Reason}</name> <fsummary>Equivalent to open(KeyOrName, ConnType, TargetMod, []).</fsummary> <desc><marker id="open-3"/> <p>Equivalent to @@ -481,7 +484,7 @@ </func> <func> - <name>open(KeyOrName, ConnType, TargetMod, Extra) -> {ok, Handle} | {error, Reason}</name> + <name since="">open(KeyOrName, ConnType, TargetMod, Extra) -> {ok, Handle} | {error, Reason}</name> <fsummary>Opens a Telnet connection to the specified target host.</fsummary> <type> @@ -531,7 +534,7 @@ </func> <func> - <name>send(Connection, Cmd) -> ok | {error, Reason}</name> + <name since="">send(Connection, Cmd) -> ok | {error, Reason}</name> <fsummary>Equivalent to send(Connection, Cmd, []).</fsummary> <desc><marker id="send-2"/> <p>Equivalent to @@ -541,23 +544,26 @@ </func> <func> - <name>send(Connection, Cmd, Opts) -> ok | {error, Reason}</name> + <name since="OTP 17.4">send(Connection, Cmd, Opts) -> ok | {error, Reason}</name> <fsummary>Sends a Telnet command and returns immediately.</fsummary> <type> <v>Connection = connection()</v> <v>Cmd = string()</v> <v>Opts = [Opt]</v> - <v>Opt = {newline, boolean()}</v> + <v>Opt = {newline, boolean() | string()}</v> <v>Reason = term()</v> </type> <desc><marker id="send-3"/> <p>Sends a Telnet command and returns immediately.</p> - <p>By default, this function adds a newline to the end of the + <p>By default, this function adds "\n" to the end of the specified command. If this is not desired, option <c>{newline,false}</c> can be used. This is necessary, for example, when sending Telnet command sequences prefixed with character - Interprete As Command (IAC).</p> + Interpret As Command (IAC). Option <c>{newline,string()}</c> + can also be used if a different line end than "\n" is + required, for instance <c>{newline,"\r\n"}</c>, to add both + carriage return and newline characters.</p> <p>The resulting output from the command can be read with <seealso marker="#get_data-1"><c>ct_telnet:get_data/2</c></seealso> or @@ -566,7 +572,7 @@ </func> <func> - <name>sendf(Connection, CmdFormat, Args) -> ok | {error, Reason}</name> + <name since="">sendf(Connection, CmdFormat, Args) -> ok | {error, Reason}</name> <fsummary>Equivalent to sendf(Connection, CmdFormat, Args, []).</fsummary> <desc><marker id="sendf-3"/> <p>Equivalent to @@ -576,7 +582,7 @@ </func> <func> - <name>sendf(Connection, CmdFormat, Args, Opts) -> ok | {error, Reason}</name> + <name since="OTP 17.4">sendf(Connection, CmdFormat, Args, Opts) -> ok | {error, Reason}</name> <fsummary>Sends a Telnet command and returns immediately (uses a format string and a list of arguments to build the command).</fsummary> <type> @@ -584,12 +590,15 @@ <v>CmdFormat = string()</v> <v>Args = list()</v> <v>Opts = [Opt]</v> - <v>Opt = {newline, boolean()}</v> + <v>Opt = {newline, boolean() | string()}</v> <v>Reason = term()</v> </type> <desc><marker id="sendf-4"/> <p>Sends a Telnet command and returns immediately (uses a format string and a list of arguments to build the command).</p> + + <p>For details, see + <seealso marker="#send-3"><c>ct_telnet:send/3</c></seealso>.</p> </desc> </func> </funcs> diff --git a/lib/common_test/doc/src/ct_testspec.xml b/lib/common_test/doc/src/ct_testspec.xml index 36893f66cf..9cb9a2ae9f 100644 --- a/lib/common_test/doc/src/ct_testspec.xml +++ b/lib/common_test/doc/src/ct_testspec.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ct_testspec.xml</file> </header> - <module>ct_testspec</module> + <module since="OTP 19.3">ct_testspec</module> <modulesummary>Parsing of test specifications for Common Test. </modulesummary> @@ -46,7 +46,7 @@ <funcs> <func> - <name>get_tests(SpecsIn) -> {ok, [{Specs,Tests}]} | {error, Reason}</name> + <name since="OTP 19.3">get_tests(SpecsIn) -> {ok, [{Specs,Tests}]} | {error, Reason}</name> <fsummary>Parse the given test specification files and return the tests to run and skip.</fsummary> <type> <v>SpecsIn = [string()] | [[string()]]</v> diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml index 118dcd88bd..38fdc2442e 100644 --- a/lib/common_test/doc/src/notes.xml +++ b/lib/common_test/doc/src/notes.xml @@ -75,6 +75,44 @@ </section> +<section><title>Common_Test 1.15.4.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The status of a test case which failed with timetrap + timeout in <c>end_per_testcase</c> could not be modified + by returning <c>{fail,Reason}</c> from a + <c>post_end_per_testcase</c> hook function. This is now + corrected.</p> + <p> + Own Id: OTP-15584 Aux Id: ERIERL-282 </p> + </item> + </list> + </section> + +</section> + +<section><title>Common_Test 1.15.4.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The status of a test case which failed with timetrap + timeout in <c>end_per_testcase</c> could not be modified + by returning <c>{fail,Reason}</c> from a + <c>post_end_per_testcase</c> hook function. This is now + corrected.</p> + <p> + Own Id: OTP-15584 Aux Id: ERIERL-282 </p> + </item> + </list> + </section> + +</section> + <section><title>Common_Test 1.15.4</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -4026,8 +4064,3 @@ <section><title>common_test 1.3.0</title> </section> </chapter> - - - - - diff --git a/lib/common_test/doc/src/unix_telnet.xml b/lib/common_test/doc/src/unix_telnet.xml index b2314a53ec..03d91b7dbe 100644 --- a/lib/common_test/doc/src/unix_telnet.xml +++ b/lib/common_test/doc/src/unix_telnet.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>unix_telnet.xml</file> </header> - <module>unix_telnet</module> + <module since="">unix_telnet</module> <modulesummary>Callback module for ct_telnet, for connecting to a Telnet server on a UNIX host.</modulesummary> @@ -80,7 +80,7 @@ <funcs> <func> - <name>connect(ConnName, Ip, Port, Timeout, KeepAlive, TCPNoDelay, Extra) -> {ok, Handle} | {error, Reason}</name> + <name since="OTP 18.3.3">connect(ConnName, Ip, Port, Timeout, KeepAlive, TCPNoDelay, Extra) -> {ok, Handle} | {error, Reason}</name> <fsummary>Callback for ct_telnet.erl.</fsummary> <type> <v>ConnName = target_name()</v> @@ -107,7 +107,7 @@ </func> <func> - <name>get_prompt_regexp() -> PromptRegexp</name> + <name since="">get_prompt_regexp() -> PromptRegexp</name> <fsummary>Callback for ct_telnet.erl.</fsummary> <type> <v>PromptRegexp = prompt_regexp()</v> diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl index a10d939919..a07e61199b 100644 --- a/lib/common_test/src/ct_config.erl +++ b/lib/common_test/src/ct_config.erl @@ -592,7 +592,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {file,KeyFile}) -> encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) -> _ = crypto:start(), - {Key,IVec} = make_crypto_key(Key), + {CryptoKey,IVec} = make_crypto_key(Key), case file:read_file(SrcFileName) of {ok,Bin0} -> Bin1 = term_to_binary({SrcFileName,Bin0}), @@ -600,7 +600,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) -> 0 -> Bin1; N -> list_to_binary([Bin1,random_bytes(8-N)]) end, - EncBin = crypto:block_encrypt(des3_cbc, Key, IVec, Bin2), + EncBin = crypto:block_encrypt(des3_cbc, CryptoKey, IVec, Bin2), case file:write_file(EncryptFileName, EncBin) of ok -> io:format("~ts --(encrypt)--> ~ts~n", @@ -631,10 +631,10 @@ decrypt_config_file(EncryptFileName, TargetFileName, {file,KeyFile}) -> decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) -> _ = crypto:start(), - {Key,IVec} = make_crypto_key(Key), + {CryptoKey,IVec} = make_crypto_key(Key), case file:read_file(EncryptFileName) of {ok,Bin} -> - DecBin = crypto:block_decrypt(des3_cbc, Key, IVec, Bin), + DecBin = crypto:block_decrypt(des3_cbc, CryptoKey, IVec, Bin), case catch binary_to_term(DecBin) of {'EXIT',_} -> {error,bad_file}; diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl index 29188a648e..6a758c4ea3 100644 --- a/lib/common_test/src/ct_netconfc.erl +++ b/lib/common_test/src/ct_netconfc.erl @@ -583,7 +583,7 @@ get_config(Client, Source, Filter, Timeout) -> -spec edit_config(Client, Target, Config) -> Result when Client :: client(), Target :: netconf_db(), - Config :: simple_xml(), + Config :: simple_xml() | [simple_xml()], Result :: ok | {error,error_reason()}. edit_config(Client, Target, Config) -> edit_config(Client, Target, Config, ?DEFAULT_TIMEOUT). @@ -591,7 +591,7 @@ edit_config(Client, Target, Config) -> -spec edit_config(Client, Target, Config, OptParams) -> Result when Client :: client(), Target :: netconf_db(), - Config :: simple_xml(), + Config :: simple_xml() | [simple_xml()], OptParams :: [simple_xml()], Result :: ok | {error,error_reason()}; (Client, Target, Config, Timeout) -> Result when @@ -608,10 +608,12 @@ edit_config(Client, Target, Config, OptParams) when is_list(OptParams) -> -spec edit_config(Client, Target, Config, OptParams, Timeout) -> Result when Client :: client(), Target :: netconf_db(), - Config :: simple_xml(), + Config :: simple_xml() | [simple_xml()], OptParams :: [simple_xml()], Timeout :: timeout(), Result :: ok | {error,error_reason()}. +edit_config(Client, Target, Config, OptParams, Timeout) when not is_list(Config)-> + edit_config(Client, Target, [Config], OptParams, Timeout); edit_config(Client, Target, Config, OptParams, Timeout) -> call(Client, {send_rpc_op, edit_config, [Target,Config,OptParams], Timeout}). @@ -1113,7 +1115,7 @@ encode_rpc_operation(get,[Filter]) -> encode_rpc_operation(get_config,[Source,Filter]) -> {'get-config',[{source,[Source]}] ++ filter(Filter)}; encode_rpc_operation(edit_config,[Target,Config,OptParams]) -> - {'edit-config',[{target,[Target]}] ++ OptParams ++ [{config,[Config]}]}; + {'edit-config',[{target,[Target]}] ++ OptParams ++ [{config,Config}]}; encode_rpc_operation(delete_config,[Target]) -> {'delete-config',[{target,[Target]}]}; encode_rpc_operation(copy_config,[Target,Source]) -> diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index f9abecfd38..174008c790 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.erl @@ -194,6 +194,15 @@ send(Connection,Cmd,Opts) -> check_send_opts([{newline,Bool}|Opts]) when is_boolean(Bool) -> check_send_opts(Opts); +check_send_opts([{newline,String}|Opts]) when is_list(String) -> + case lists:all(fun(I) when is_integer(I), I>=0, I=<127 -> true; + (_) -> false + end, String) of + true -> + check_send_opts(Opts); + false -> + {error,{invalid_option,{newline,String}}} + end; check_send_opts([Invalid|_]) -> {error,{invalid_option,Invalid}}; check_send_opts([]) -> @@ -211,10 +220,16 @@ expect(Connection,Patterns) -> expect(Connection,Patterns,Opts) -> case get_handle(Connection) of - {ok,Pid} -> - call(Pid,{expect,Patterns,Opts}); - Error -> - Error + {ok,Pid} -> + case call(Pid,{expect,Patterns,Opts}) of + {error,Reason} when element(1,Reason)==bad_pattern -> + %% Faulty user input - should fail the test case + exit({Reason,{?MODULE,?FUNCTION_NAME,3}}); + Other -> + Other + end; + Error -> + Error end. %%%================================================================= @@ -674,60 +689,68 @@ silent_teln_expect(Name,Pid,Data,Pattern,Prx,Opts) -> %% 3b) Repeat (sequence): 2) is repeated either N times or until a %% halt condition is fulfilled. teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) -> - HaltPatterns = + HaltPatterns0 = case get_ignore_prompt(Opts) of true -> get_haltpatterns(Opts); false -> [prompt | get_haltpatterns(Opts)] end, - - PromptCheck = get_prompt_check(Opts), - - {WaitForPrompt,Pattern1,Opts1} = wait_for_prompt(Pattern0,Opts), - - Seq = get_seq(Opts1), - Pattern2 = convert_pattern(Pattern1,Seq), - {IdleTimeout,TotalTimeout} = get_timeouts(Opts1), - - EO = #eo{teln_pid=Pid, - prx=Prx, - idle_timeout=IdleTimeout, - total_timeout=TotalTimeout, - seq=Seq, - haltpatterns=HaltPatterns, - prompt_check=PromptCheck}, + case convert_pattern(HaltPatterns0,false) of + {ok,HaltPatterns} -> + {WaitForPrompt,Pattern1,Opts1} = wait_for_prompt(Pattern0,Opts), + Seq = get_seq(Opts1), + case convert_pattern(Pattern1,Seq) of + {ok,Pattern2} -> + {IdleTimeout,TotalTimeout} = get_timeouts(Opts1), + PromptCheck = get_prompt_check(Opts1), + + EO = #eo{teln_pid=Pid, + prx=Prx, + idle_timeout=IdleTimeout, + total_timeout=TotalTimeout, + seq=Seq, + haltpatterns=HaltPatterns, + prompt_check=PromptCheck}, - case get_repeat(Opts1) of - false -> - case teln_expect1(Name,Pid,Data,Pattern2,[],EO) of - {ok,Matched,Rest} when WaitForPrompt -> - case lists:reverse(Matched) of - [{prompt,_},Matched1] -> - {ok,Matched1,Rest}; - [{prompt,_}|Matched1] -> - {ok,lists:reverse(Matched1),Rest} - end; - {ok,Matched,Rest} -> - {ok,Matched,Rest}; - {halt,Why,Rest} -> - {error,Why,Rest}; - {error,Reason} -> - {error,Reason} - end; - N -> - EO1 = EO#eo{repeat=N}, - repeat_expect(Name,Pid,Data,Pattern2,[],EO1) + case get_repeat(Opts1) of + false -> + case teln_expect1(Name,Pid,Data,Pattern2,[],EO) of + {ok,Matched,Rest} when WaitForPrompt -> + case lists:reverse(Matched) of + [{prompt,_},Matched1] -> + {ok,Matched1,Rest}; + [{prompt,_}|Matched1] -> + {ok,lists:reverse(Matched1),Rest} + end; + {ok,Matched,Rest} -> + {ok,Matched,Rest}; + {halt,Why,Rest} -> + {error,Why,Rest}; + {error,Reason} -> + {error,Reason} + end; + N -> + EO1 = EO#eo{repeat=N}, + repeat_expect(Name,Pid,Data,Pattern2,[],EO1) + end; + Error -> + Error + end; + Error -> + Error end. -convert_pattern(Pattern,Seq) - when is_list(Pattern) and not is_integer(hd(Pattern)) -> - case Seq of - true -> Pattern; - false -> rm_dupl(Pattern,[]) - end; +convert_pattern(Pattern0,Seq) + when Pattern0==[] orelse (is_list(Pattern0) and not is_integer(hd(Pattern0))) -> + Pattern = + case Seq of + true -> Pattern0; + false -> rm_dupl(Pattern0,[]) + end, + compile_pattern(Pattern,[]); convert_pattern(Pattern,_Seq) -> - [Pattern]. + compile_pattern([Pattern],[]). rm_dupl([P|Ps],Acc) -> case lists:member(P,Acc) of @@ -739,6 +762,25 @@ rm_dupl([P|Ps],Acc) -> rm_dupl([],Acc) -> lists:reverse(Acc). +compile_pattern([prompt|Patterns],Acc) -> + compile_pattern(Patterns,[prompt|Acc]); +compile_pattern([{prompt,_}=P|Patterns],Acc) -> + compile_pattern(Patterns,[P|Acc]); +compile_pattern([{Tag,Pattern}|Patterns],Acc) -> + try re:compile(Pattern,[unicode]) of + {ok,MP} -> compile_pattern(Patterns,[{Tag,MP}|Acc]); + {error,Error} -> {error,{bad_pattern,{Tag,Pattern},Error}} + catch error:badarg -> {error,{bad_pattern,{Tag,Pattern}}} + end; +compile_pattern([Pattern|Patterns],Acc) -> + try re:compile(Pattern,[unicode]) of + {ok,MP} -> compile_pattern(Patterns,[MP|Acc]); + {error,Error} -> {error,{bad_pattern,Pattern,Error}} + catch error:badarg -> {error,{bad_pattern,Pattern}} + end; +compile_pattern([],Acc) -> + {ok,lists:reverse(Acc)}. + get_timeouts(Opts) -> {case lists:keysearch(idle_timeout,1,Opts) of {value,{_,T}} -> @@ -772,7 +814,7 @@ get_seq(Opts) -> get_haltpatterns(Opts) -> case lists:keysearch(halt,1,Opts) of {value,{halt,HaltPatterns}} -> - convert_pattern(HaltPatterns,false); + HaltPatterns; false -> [] end. @@ -1068,7 +1110,7 @@ match_line(Name,Pid,Line,[{prompt,PromptType}|Patterns],FoundPrompt,Term, when PromptType=/=FoundPrompt -> match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag); match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,Term,EO,RetTag) -> - case re:run(Line,Pattern,[{capture,all,list},unicode]) of + case re:run(Line,Pattern,[{capture,all,list}]) of nomatch -> match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag); {match,Match} -> @@ -1076,7 +1118,7 @@ match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,Term,EO,RetTag) -> {RetTag,{Tag,Match}} end; match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,Term,EO,RetTag) -> - case re:run(Line,Pattern,[{capture,all,list},unicode]) of + case re:run(Line,Pattern,[{capture,all,list}]) of nomatch -> match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag); {match,Match} -> diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl index 76e4b9ea70..007477c855 100644 --- a/lib/common_test/src/ct_telnet_client.erl +++ b/lib/common_test/src/ct_telnet_client.erl @@ -101,9 +101,11 @@ close(Pid) -> end. send_data(Pid, Data) -> - send_data(Pid, Data, true). + send_data(Pid, Data, "\n"). send_data(Pid, Data, true) -> - send_data(Pid, Data++"\n", false); + send_data(Pid, Data, "\n"); +send_data(Pid, Data, Newline) when is_list(Newline) -> + send_data(Pid, Data++Newline, false); send_data(Pid, Data, false) -> Pid ! {send_data, Data}, ok. diff --git a/lib/common_test/src/test_server.erl b/lib/common_test/src/test_server.erl index a896a0551b..9eda3f2152 100644 --- a/lib/common_test/src/test_server.erl +++ b/lib/common_test/src/test_server.erl @@ -850,17 +850,23 @@ spawn_fw_call(Mod,EPTC={end_per_testcase,Func},EndConf,Pid, "WARNING: end_per_testcase failed!</font>", {died,W} end, - try do_end_tc_call(Mod,EPTC,{Pid,Report,[EndConf]}, Why) of - _ -> ok - catch - _:FwEndTCErr -> - exit({fw_notify_done,end_tc,FwEndTCErr}) - end, - FailLoc = proplists:get_value(tc_fail_loc, EndConf), + FailLoc0 = proplists:get_value(tc_fail_loc, EndConf), + {RetVal1,FailLoc} = + try do_end_tc_call(Mod,EPTC,{Pid,Report,[EndConf]}, Why) of + Why -> + {RetVal,FailLoc0}; + {failed,_} = R -> + {R,[{Mod,Func}]}; + R -> + {R,FailLoc0} + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, %% finished, report back (if end_per_testcase fails, a warning %% should be printed as part of the comment) SendTo ! {self(),fw_notify_done, - {Time,RetVal,FailLoc,[],Warn}} + {Time,RetVal1,FailLoc,[],Warn}} end, spawn_link(FwCall); @@ -902,14 +908,25 @@ spawn_fw_call(Mod,Func,CurrConf,Pid,Error,Loc,SendTo) -> FwErrorNotifyErr}) end, Conf = [{tc_status,{failed,Error}}|CurrConf], - try do_end_tc_call(Mod,EndTCFunc,{Pid,Error,[Conf]},Error) of - _ -> ok - catch - _:FwEndTCErr -> - exit({fw_notify_done,end_tc,FwEndTCErr}) - end, + {Time,RetVal,Loc1} = + try do_end_tc_call(Mod,EndTCFunc,{Pid,Error,[Conf]},Error) of + Error -> + {died, Error, Loc}; + {failed,Reason} = NewReturn -> + fw_error_notify(Mod,Func1,Conf,Reason), + {died, NewReturn, [{Mod,Func}]}; + NewReturn -> + T = case Error of + {timetrap_timeout,TT} -> TT; + _ -> 0 + end, + {T, NewReturn, Loc} + catch + _:FwEndTCErr -> + exit({fw_notify_done,end_tc,FwEndTCErr}) + end, %% finished, report back - SendTo ! {self(),fw_notify_done,{died,Error,Loc,[],undefined}} + SendTo ! {self(),fw_notify_done,{Time,RetVal,Loc1,[],undefined}} end, spawn_link(FwCall). diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl index 0f5636a789..44b86b1dfe 100644 --- a/lib/common_test/test/ct_hooks_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE.erl @@ -84,7 +84,7 @@ all(suite) -> fail_post_suite_cth, skip_pre_suite_cth, skip_pre_end_cth, skip_pre_init_tc_cth, skip_post_suite_cth, recover_post_suite_cth, update_config_cth, - state_update_cth, options_cth, same_id_cth, + state_update_cth, update_result_cth, options_cth, same_id_cth, fail_n_skip_with_minimal_cth, prio_cth, no_config, no_init_suite_config, no_init_config, no_end_config, failed_sequence, repeat_force_stop, config_clash, @@ -209,6 +209,10 @@ state_update_cth(Config) when is_list(Config) -> do_test(state_update_cth, "ct_cth_fail_one_skip_one_SUITE.erl", [state_update_cth,state_update_cth],Config). +update_result_cth(Config) -> + do_test(update_result_cth, "ct_cth_update_result_post_end_tc_SUITE.erl", + [update_result_post_end_tc_cth],Config). + options_cth(Config) when is_list(Config) -> do_test(options_cth, "ct_cth_empty_SUITE.erl", [{empty_cth,[test]}],Config). @@ -1099,6 +1103,106 @@ test_events(state_update_cth) -> {?eh,stop_logging,[]} ]; +test_events(update_result_cth) -> + Suite = ct_cth_update_result_post_end_tc_SUITE, + [ + {?eh,start_logging,'_'}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, + {?eh,tc_start,{Suite,init_per_suite}}, + {?eh,tc_done,{Suite,init_per_suite,ok}}, + + {?eh,tc_start,{Suite,tc_ok_to_fail}}, + {?eh,cth,{'_',post_end_per_testcase,[Suite,tc_ok_to_fail,'_',ok,[]]}}, + {?eh,tc_done,{Suite,tc_ok_to_fail,{failed,{error,"Test failure"}}}}, + {?eh,cth,{'_',on_tc_fail,'_'}}, + {?eh,test_stats,{0,1,{0,0}}}, + + {?eh,tc_start,{Suite,tc_ok_to_skip}}, + {?eh,cth,{'_',post_end_per_testcase,[Suite,tc_ok_to_skip,'_',ok,[]]}}, + {?eh,tc_done,{Suite,tc_ok_to_skip,{skipped,"Test skipped"}}}, + {?eh,cth,{'_',on_tc_skip,'_'}}, + {?eh,test_stats,{0,1,{1,0}}}, + + {?eh,tc_start,{Suite,tc_fail_to_ok}}, + {?eh,cth,{'_',post_end_per_testcase, + [Suite,tc_fail_to_ok,'_', + {error,{test_case_failed,"should be changed to ok"}},[]]}}, + {?eh,tc_done,{Suite,tc_fail_to_ok,ok}}, + {?eh,test_stats,{1,1,{1,0}}}, + + {?eh,tc_start,{Suite,tc_fail_to_skip}}, + {?eh,cth,{'_',post_end_per_testcase, + [Suite,tc_fail_to_skip,'_', + {error,{test_case_failed,"should be changed to skip"}},[]]}}, + {?eh,tc_done,{Suite,tc_fail_to_skip,{skipped,"Test skipped"}}}, + {?eh,cth,{'_',on_tc_skip,'_'}}, + {?eh,test_stats,{1,1,{2,0}}}, + + {?eh,tc_start,{Suite,tc_timetrap_to_ok}}, + {?eh,cth,{'_',post_end_per_testcase, + [Suite,tc_timetrap_to_ok,'_',{timetrap_timeout,3000},[]]}}, + {?eh,tc_done,{Suite,tc_timetrap_to_ok,ok}}, + {?eh,test_stats,{2,1,{2,0}}}, + + {?eh,tc_start,{Suite,tc_timetrap_to_skip}}, + {?eh,cth,{'_',post_end_per_testcase, + [Suite,tc_timetrap_to_skip,'_',{timetrap_timeout,3000},[]]}}, + {?eh,tc_done,{Suite,tc_timetrap_to_skip,{skipped,"Test skipped"}}}, + {?eh,cth,{'_',on_tc_skip,'_'}}, + {?eh,test_stats,{2,1,{3,0}}}, + + {?eh,tc_start,{Suite,tc_skip_to_fail}}, + {?eh,cth,{'_',post_end_per_testcase, + [Suite,tc_skip_to_fail,'_', + {skip,"should be changed to fail"},[]]}}, + {?eh,tc_done,{Suite,tc_skip_to_fail,{failed,{error,"Test failure"}}}}, + {?eh,cth,{'_',on_tc_fail,'_'}}, + {?eh,test_stats,{2,2,{3,0}}}, + + {?eh,tc_start,{Suite,end_fail_to_fail}}, + {?eh,cth,{'_',post_end_per_testcase, + [Suite,end_fail_to_fail,'_', + {failed, + {Suite,end_per_testcase, + {'EXIT',{test_case_failed,"change result when end fails"}}}},[]]}}, + {?eh,tc_done,{Suite,end_fail_to_fail,{failed,{error,"Test failure"}}}}, + {?eh,cth,{'_',on_tc_fail,'_'}}, + {?eh,test_stats,{2,3,{3,0}}}, + + {?eh,tc_start,{Suite,end_fail_to_skip}}, + {?eh,cth,{'_',post_end_per_testcase, + [Suite,end_fail_to_skip,'_', + {failed, + {Suite,end_per_testcase, + {'EXIT',{test_case_failed,"change result when end fails"}}}},[]]}}, + {?eh,tc_done,{Suite,end_fail_to_skip,{skipped,"Test skipped"}}}, + {?eh,cth,{'_',on_tc_skip,'_'}}, + {?eh,test_stats,{2,3,{4,0}}}, + + {?eh,tc_start,{Suite,end_timetrap_to_fail}}, + {?eh,cth,{'_',post_end_per_testcase, + [Suite,end_timetrap_to_fail,'_', + {failed,{Suite,end_per_testcase,{timetrap_timeout,3000}}},[]]}}, + {?eh,tc_done,{Suite,end_timetrap_to_fail,{failed,{error,"Test failure"}}}}, + {?eh,cth,{'_',on_tc_fail,'_'}}, + {?eh,test_stats,{2,4,{4,0}}}, + + {?eh,tc_start,{Suite,end_timetrap_to_skip}}, + {?eh,cth,{'_',post_end_per_testcase, + [Suite,end_timetrap_to_skip,'_', + {failed,{Suite,end_per_testcase,{timetrap_timeout,3000}}},[]]}}, + {?eh,tc_done,{Suite,end_timetrap_to_skip,{skipped,"Test skipped"}}}, + {?eh,cth,{'_',on_tc_skip,'_'}}, + {?eh,test_stats,{2,4,{5,0}}}, + + {?eh,tc_start,{Suite,end_per_suite}}, + {?eh,tc_done,{Suite,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,cth,{'_',terminate,[[]]}}, + {?eh,stop_logging,[]} + ]; + test_events(options_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_update_result_post_end_tc_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_update_result_post_end_tc_SUITE.erl new file mode 100644 index 0000000000..a16138ce6f --- /dev/null +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_update_result_post_end_tc_SUITE.erl @@ -0,0 +1,101 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2017. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(ct_cth_update_result_post_end_tc_SUITE). + +-compile(export_all). + +-include("ct.hrl"). + +suite() -> + [{timetrap,{seconds,3}}]. + +init_per_suite(Config) -> + Config. + +end_per_suite(Config) -> + ok. + +init_per_group(_,Config) -> + Config. + +end_per_group(_,_) -> + ok. + +init_per_testcase(_,Config) -> + Config. + +end_per_testcase(EndTimetrap,_) when EndTimetrap==end_timetrap_to_fail; + EndTimetrap==end_timetrap_to_skip-> + timer:sleep(10000); +end_per_testcase(EndFail,_) when EndFail==end_fail_to_fail; + EndFail==end_fail_to_skip-> + ct:fail("change result when end fails"); +end_per_testcase(_,_) -> + ok. + +all() -> + [tc_ok_to_fail, + tc_ok_to_skip, + tc_fail_to_ok, + tc_fail_to_skip, + tc_timetrap_to_ok, + tc_timetrap_to_skip, + tc_skip_to_fail, + end_fail_to_fail, + end_fail_to_skip, + end_timetrap_to_fail, + end_timetrap_to_skip]. + +%% Test cases starts here. +tc_ok_to_fail(_Config) -> + ok. + +tc_ok_to_skip(_Config) -> + ok. + +tc_fail_to_ok(_Config) -> + ct:fail("should be changed to ok"). + +tc_fail_to_skip(_Config) -> + ct:fail("should be changed to skip"). + +tc_timetrap_to_ok(_Config) -> + timer:sleep(10000), % will time out after 3 sek + ok. + +tc_timetrap_to_skip(_Config) -> + timer:sleep(10000), % will time out after 3 sek + ok. + +tc_skip_to_fail(_Config) -> + {skip,"should be changed to fail"}. + +end_fail_to_fail(_Config) -> + ok. + +end_fail_to_skip(_Config) -> + ok. + +end_timetrap_to_fail(_Config) -> + ok. + +end_timetrap_to_skip(_Config) -> + ok. diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_result_post_end_tc_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_result_post_end_tc_cth.erl new file mode 100644 index 0000000000..7afb3d8781 --- /dev/null +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_result_post_end_tc_cth.erl @@ -0,0 +1,98 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2017. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + + +-module(update_result_post_end_tc_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-compile(export_all). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State). + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State). + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State). + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Suite,Group,Config,State) -> + empty_cth:pre_init_per_group(Suite,Group,Config,State). + +post_init_per_group(Suite,Group,Config,Return,State) -> + empty_cth:post_init_per_group(Suite,Group,Config,Return,State). + +pre_end_per_group(Suite,Group,Config,State) -> + empty_cth:pre_end_per_group(Suite,Group,Config,State). + +post_end_per_group(Suite,Group,Config,Return,State) -> + empty_cth:post_end_per_group(Suite,Group,Config,Return,State). + +pre_init_per_testcase(Suite,TC,Config,State) -> + empty_cth:pre_init_per_testcase(Suite,TC,Config,State). + +post_end_per_testcase(Suite,TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State), + change_result(TC,Config,State). + +on_tc_fail(Suite,TC, Reason, State) -> + empty_cth:on_tc_fail(Suite,TC,Reason,State). + +on_tc_skip(Suite,TC, Reason, State) -> + empty_cth:on_tc_skip(Suite,TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). + +%%%----------------------------------------------------------------- +%%% +change_result(tc_ok_to_fail,_Config,State) -> + {{fail, "Test failure"}, State}; +change_result(tc_ok_to_skip,_Config,State) -> + {{skip, "Test skipped"}, State}; +change_result(tc_fail_to_ok,Config,State) -> + {lists:keydelete(tc_status,1,Config),State}; +change_result(tc_fail_to_skip,Config,State) -> + {{skip,"Test skipped"},State}; +change_result(tc_timetrap_to_ok,Config,State) -> + {lists:keydelete(tc_status,1,Config),State}; +change_result(tc_timetrap_to_skip,Config,State) -> + {{skip,"Test skipped"},State}; +change_result(tc_skip_to_fail,_Config,State) -> + {{fail, "Test failure"}, State}; +change_result(end_fail_to_fail,_Config,State) -> + {{fail, "Test failure"}, State}; +change_result(end_fail_to_skip,_Config,State) -> + {{skip, "Test skipped"}, State}; +change_result(end_timetrap_to_fail,_Config,State) -> + {{fail, "Test failure"}, State}; +change_result(end_timetrap_to_skip,_Config,State) -> + {{skip, "Test skipped"}, State}. diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl index a2fa099a8c..0d17481e95 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl @@ -440,6 +440,12 @@ edit_config(Config) -> ?ok = ct_netconfc:edit_config(Client,running, {server,[{xmlns,"myns"}], [{name,["myserver"]}]}), + ?NS:expect_reply('edit-config',ok), + ?ok = ct_netconfc:edit_config(Client,running, + [{server,[{xmlns,"myns"}], + [{name,["server1"]}]}, + {server,[{xmlns,"myns"}], + [{name,["server2"]}]}]), ?NS:expect_do_reply('close-session',close,ok), ?ok = ct_netconfc:close_session(Client), ok. diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl index a0089c9bc9..f71b7c370f 100644 --- a/lib/common_test/test/ct_telnet_SUITE.erl +++ b/lib/common_test/test/ct_telnet_SUITE.erl @@ -50,10 +50,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. groups() -> - [{legacy, [], [unix_telnet,own_server,timetrap]}, - {raw, [], [unix_telnet,own_server,timetrap]}, - {html, [], [unix_telnet,own_server]}, - {silent, [], [unix_telnet,own_server]}]. + [{legacy, [], [unix_telnet,own_server,faulty_regexp,timetrap]}, + {raw, [], [unix_telnet,own_server,faulty_regexp,timetrap]}, + {html, [], [unix_telnet,own_server,faulty_regexp]}, + {silent, [], [unix_telnet,own_server,faulty_regexp]}]. all() -> [ @@ -119,6 +119,12 @@ own_server(Config) -> all_tests_in_suite(own_server,"ct_telnet_own_server_SUITE", CfgFile,Config). +faulty_regexp(Config) -> + CfgFile = "telnet.faulty_regexp." ++ + atom_to_list(groupname(Config)) ++ ".cfg", + all_tests_in_suite(faulty_regexp,"ct_telnet_faulty_regexp_SUITE", + CfgFile,Config). + timetrap(Config) -> CfgFile = "telnet.timetrap." ++ atom_to_list(groupname(Config)) ++ ".cfg", @@ -225,6 +231,31 @@ events_to_check(unix_telnet,Config) -> all_cases(ct_telnet_basic_SUITE,Config); events_to_check(own_server,Config) -> all_cases(ct_telnet_own_server_SUITE,Config); +events_to_check(faulty_regexp,_Config) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,tc_done, + {ct_telnet_faulty_regexp_SUITE,expect_pattern, + {failed, + {error,{{bad_pattern,"invalid(pattern",{"missing )",15}}, + {ct_telnet,expect,3}}}}}}, + {?eh,tc_done, + {ct_telnet_faulty_regexp_SUITE,expect_pattern_no_string, + {failed, + {error,{{bad_pattern,invalid_pattern}, + {ct_telnet,expect,3}}}}}}, + {?eh,tc_done, + {ct_telnet_faulty_regexp_SUITE,expect_tag_pattern, + {failed, + {error,{{bad_pattern,{tag,"invalid(pattern"},{"missing )",15}}, + {ct_telnet,expect,3}}}}}}, + {?eh,tc_done, + {ct_telnet_faulty_regexp_SUITE,expect_tag_pattern_no_string, + {failed, + {error,{{bad_pattern,{tag,invalid_pattern}}, + {ct_telnet,expect,3}}}}}}, + {?eh,tc_done,{ct_telnet_faulty_regexp_SUITE,expect_pattern_unicode,ok}}, + {?eh,tc_done,{ct_telnet_faulty_regexp_SUITE,expect_tag_pattern_unicode,ok}}, + {?eh,stop_logging,[]}]; events_to_check(timetrap,_Config) -> [{?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,tc_done,{ct_telnet_timetrap_SUITE,expect_timetrap, diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl new file mode 100644 index 0000000000..a5c9451a9c --- /dev/null +++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl @@ -0,0 +1,79 @@ +-module(ct_telnet_faulty_regexp_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +-define(name, telnet_server_conn1). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +suite() -> [{require,?name,{unix,[telnet]}}, + {require,ct_conn_log}, + {ct_hooks, [{cth_conn_log,[]}]}]. + +all() -> + [expect_pattern, + expect_pattern_no_string, + expect_tag_pattern, + expect_tag_pattern_no_string, + expect_pattern_unicode, + expect_tag_pattern_unicode]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +init_per_testcase(_,Config) -> + ct:log("init_per_testcase: opening telnet connection...",[]), + {ok,_} = ct_telnet:open(?name), + ct:log("...done",[]), + Config. + +end_per_testcase(_,_Config) -> + ct:log("end_per_testcase: closing telnet connection...",[]), + _ = ct_telnet:close(?name), + ct:log("...done",[]), + ok. + +expect_pattern(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + ok = ct_telnet:expect(?name, "invalid(pattern"). + +expect_pattern_no_string(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + ok = ct_telnet:expect(?name, invalid_pattern). + +expect_tag_pattern(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + ok = ct_telnet:expect(?name, {tag,"invalid(pattern"}). + +expect_tag_pattern_no_string(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + ok = ct_telnet:expect(?name, {tag,invalid_pattern}). + +%% Test that a unicode pattern can be given without the testcase +%% failing. Do however notice that there is no real unicode support +%% in ct_telnet yet, that is, the telnet binary mode is not supported. +expect_pattern_unicode(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + {error,{prompt,_}} = ct_telnet:expect(?name, "pattern_with_unicode_αβ"), + ok. + +expect_tag_pattern_unicode(_) -> + ok = ct_telnet:send(?name, "echo ayt"), + {error,{prompt,_}} = ct_telnet:expect(?name, "pattern_with_unicode_αβ"), + ok. diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl index 985fa40ad2..34df57027e 100644 --- a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl +++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl @@ -58,7 +58,8 @@ all() -> server_speaks, server_disconnects, newline_ayt, - newline_break + newline_break, + newline_string ]. groups() -> @@ -393,3 +394,11 @@ newline_break(_) -> "> " = lists:flatten(R), ok = ct_telnet:close(Handle), ok. + +%% Test option {newline,String} to specify an own newline, e.g. "\r\n" +newline_string(_) -> + {ok, Handle} = ct_telnet:open(telnet_server_conn1), + ok = ct_telnet:send(Handle, "echo hello-", [{newline,"own_nl\n"}]), + {ok,["hello-own_nl"]} = ct_telnet:expect(Handle, ["hello-own_nl"]), + ok = ct_telnet:close(Handle), + ok. diff --git a/lib/common_test/test_server/ts_erl_config.erl b/lib/common_test/test_server/ts_erl_config.erl index 537628e39a..f3972bea4e 100644 --- a/lib/common_test/test_server/ts_erl_config.erl +++ b/lib/common_test/test_server/ts_erl_config.erl @@ -208,7 +208,11 @@ erl_interface(Vars,OsType) -> {filename:join(Dir, "lib"), filename:join([Dir, "src", "eidefs.mk"])}; {srctree, _Root, Target} -> - {filename:join([Dir, "obj", Target]), + Obj = case is_debug_build() of + true -> "obj.debug"; + false -> "obj" + end, + {filename:join([Dir, Obj, Target]), filename:join([Dir, "src", Target, "eidefs.mk"])} end} end, diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml index cfbd4c7fda..7f3d6aa60e 100644 --- a/lib/compiler/doc/src/compile.xml +++ b/lib/compiler/doc/src/compile.xml @@ -29,7 +29,7 @@ <rev>A</rev> <file>compile.sgml</file> </header> - <module>compile</module> + <module since="">compile</module> <modulesummary>Erlang Compiler</modulesummary> <description> <p>This module provides an interface to the standard Erlang @@ -40,7 +40,7 @@ <funcs> <func> - <name>env_compiler_options()</name> + <name since="OTP 19.0">env_compiler_options()</name> <fsummary> Compiler options defined via the environment variable <c>ERL_COMPILER_OPTIONS</c> @@ -53,7 +53,7 @@ </desc> </func> <func> - <name>file(File)</name> + <name since="">file(File)</name> <fsummary>Compiles a file.</fsummary> <desc> <p>Is the same as @@ -63,7 +63,7 @@ </func> <func> - <name>file(File, Options) -> CompRet</name> + <name since="">file(File, Options) -> CompRet</name> <fsummary>Compiles a file.</fsummary> <type> <v>CompRet = ModRet | BinRet | ErrRet</v> @@ -718,7 +718,7 @@ module.beam: module.erl \ </func> <func> - <name>forms(Forms)</name> + <name since="">forms(Forms)</name> <fsummary>Compiles a list of forms.</fsummary> <desc> <p>Is the same as @@ -728,7 +728,7 @@ module.beam: module.erl \ </func> <func> - <name>forms(Forms, Options) -> CompRet</name> + <name since="">forms(Forms, Options) -> CompRet</name> <fsummary>Compiles a list of forms.</fsummary> <type> <v>Forms = [Form]</v> @@ -749,7 +749,7 @@ module.beam: module.erl \ </func> <func> - <name>format_error(ErrorDescriptor) -> chars()</name> + <name since="">format_error(ErrorDescriptor) -> chars()</name> <fsummary>Formats an error descriptor.</fsummary> <type> <v>ErrorDescriptor = errordesc()</v> @@ -764,7 +764,7 @@ module.beam: module.erl \ </func> <func> - <name>output_generated(Options) -> true | false</name> + <name since="">output_generated(Options) -> true | false</name> <fsummary>Determines whether the compiler generates an output file.</fsummary> <type> <v>Options = [term()]</v> @@ -779,7 +779,7 @@ module.beam: module.erl \ </func> <func> - <name>noenv_file(File, Options) -> CompRet</name> + <name since="">noenv_file(File, Options) -> CompRet</name> <fsummary>Compiles a file (ignoring <c>ERL_COMPILER_OPTIONS)</c>.</fsummary> <desc> <p>Works like <seealso marker="#file/2">file/2</seealso>, @@ -789,7 +789,7 @@ module.beam: module.erl \ </func> <func> - <name>noenv_forms(Forms, Options) -> CompRet</name> + <name since="">noenv_forms(Forms, Options) -> CompRet</name> <fsummary>Compiles a list of forms (ignoring <c>ERL_COMPILER_OPTIONS)</c>.</fsummary> <desc> <p>Works like <seealso marker="#forms/2">forms/2</seealso>, @@ -799,7 +799,7 @@ module.beam: module.erl \ </func> <func> - <name>noenv_output_generated(Options) -> true | false</name> + <name since="">noenv_output_generated(Options) -> true | false</name> <fsummary>Determines whether the compiler generates an output file (ignoring <c>ERL_COMPILER_OPTIONS)</c>.</fsummary> <type> diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml index 7addadf82c..02e6203137 100644 --- a/lib/compiler/doc/src/notes.xml +++ b/lib/compiler/doc/src/notes.xml @@ -32,6 +32,26 @@ <p>This document describes the changes made to the Compiler application.</p> +<section><title>Compiler 7.3.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>An optimization that avoided allocation of a stack + frame for some <c>case</c> expressions was introduced in + OTP 21. (ERL-504/OTP-14808) It turns out that in rare + circumstances, this optimization is not safe. Therefore, + this optimization has been disabled.</p> + <p>A similar optimization will be included in OTP 22 in a + safe way.</p> + <p> + Own Id: OTP-15501 Aux Id: ERL-807, ERL-514, OTP-14808 </p> + </item> + </list> + </section> + +</section> + <section><title>Compiler 7.3</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl index b5c979e529..a1e9eff8f3 100644 --- a/lib/compiler/src/beam_type.erl +++ b/lib/compiler/src/beam_type.erl @@ -1114,4 +1114,5 @@ verified_type(nonempty_list=T) -> T; verified_type({tuple,_,Sz,[]}=T) when is_integer(Sz) -> T; verified_type({tuple,_,Sz,[_]}=T) when is_integer(Sz) -> T; verified_type({tuple_element,_,_}=T) -> T; -verified_type(float=T) -> T. +verified_type(float=T) -> T; +verified_type(none=T) -> T. diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl index e9152ba88f..d7a7778740 100644 --- a/lib/compiler/src/v3_codegen.erl +++ b/lib/compiler/src/v3_codegen.erl @@ -79,13 +79,9 @@ function(#k_fdef{anno=#k{a=Anno},func=Name,arity=Arity, try #k_match{} = Kb, %Assertion. - %% Try to suppress the stack frame unless it is - %% really needed. - Body0 = avoid_stack_frame(Kb), - %% Annotate kernel records with variable usage. Vdb0 = init_vars(As), - {Body,_,Vdb} = body(Body0, 1, Vdb0), + {Body,_,Vdb} = body(Kb, 1, Vdb0), %% Generate the BEAM assembly code. {Asm,EntryLabel,St} = cg_fun(Body, As, Vdb, AtomMod, @@ -98,136 +94,6 @@ function(#k_fdef{anno=#k{a=Anno},func=Name,arity=Arity, erlang:raise(Class, Error, Stack) end. - -%% avoid_stack_frame(Kernel) -> Kernel' -%% If possible, avoid setting up a stack frame. Functions -%% that only do matching, calls to guard BIFs, and tail-recursive -%% calls don't need a stack frame. - -avoid_stack_frame(#k_match{body=Body}=M) -> - try - M#k_match{body=avoid_stack_frame_1(Body)} - catch - impossible -> - M - end. - -avoid_stack_frame_1(#k_alt{first=First0,then=Then0}=Alt) -> - First = avoid_stack_frame_1(First0), - Then = avoid_stack_frame_1(Then0), - Alt#k_alt{first=First,then=Then}; -avoid_stack_frame_1(#k_bif{op=Op}=Bif) -> - case Op of - #k_internal{} -> - %% Most internal BIFs clobber the X registers. - throw(impossible); - _ -> - Bif - end; -avoid_stack_frame_1(#k_break{anno=Anno,args=Args}) -> - #k_guard_break{anno=Anno,args=Args}; -avoid_stack_frame_1(#k_guard_break{}=Break) -> - Break; -avoid_stack_frame_1(#k_enter{}=Enter) -> - %% Tail-recursive calls don't need a stack frame. - Enter; -avoid_stack_frame_1(#k_guard{clauses=Cs0}=Guard) -> - Cs = avoid_stack_frame_list(Cs0), - Guard#k_guard{clauses=Cs}; -avoid_stack_frame_1(#k_guard_clause{guard=G0,body=B0}=C) -> - G = avoid_stack_frame_1(G0), - B = avoid_stack_frame_1(B0), - C#k_guard_clause{guard=G,body=B}; -avoid_stack_frame_1(#k_match{anno=A,vars=Vs,body=B0,ret=Ret}) -> - %% Use #k_guard_match{} instead to avoid saving the X registers - %% to the stack before matching. - B = avoid_stack_frame_1(B0), - #k_guard_match{anno=A,vars=Vs,body=B,ret=Ret}; -avoid_stack_frame_1(#k_guard_match{body=B0}=M) -> - B = avoid_stack_frame_1(B0), - M#k_guard_match{body=B}; -avoid_stack_frame_1(#k_protected{arg=Arg0}=Prot) -> - Arg = avoid_stack_frame_1(Arg0), - Prot#k_protected{arg=Arg}; -avoid_stack_frame_1(#k_put{}=Put) -> - Put; -avoid_stack_frame_1(#k_return{}=Ret) -> - Ret; -avoid_stack_frame_1(#k_select{var=#k_var{anno=Vanno},types=Types0}=Select) -> - case member(reuse_for_context, Vanno) of - false -> - Types = avoid_stack_frame_list(Types0), - Select#k_select{types=Types}; - true -> - %% Including binary patterns that overwrite the register containing - %% the binary with the match context may not be safe. For example, - %% bs_match_SUITE:bin_tail_e/1 with inlining will be rejected by - %% beam_validator. - %% - %% Essentially the following code is produced: - %% - %% bs_match {x,0} => {x,0} - %% ... - %% bs_match {x,0} => {x,1} %% ILLEGAL - %% - %% A bs_match instruction will only accept a match context as the - %% source operand if the source and destination registers are the - %% the same (as in the first bs_match instruction above). - %% The second bs_match instruction is therefore illegal. - %% - %% This situation is avoided if there is a stack frame: - %% - %% move {x,0} => {y,0} - %% bs_match {x,0} => {x,0} - %% ... - %% bs_match {y,0} => {x,1} %% LEGAL - %% - throw(impossible) - end; -avoid_stack_frame_1(#k_seq{arg=#k_call{anno=Anno,op=Op}=Call, - body=#k_break{args=BrArgs0}}=Seq) -> - case Op of - #k_remote{mod=#k_atom{val=Mod}, - name=#k_atom{val=Name}, - arity=Arity} -> - case erl_bifs:is_exit_bif(Mod, Name, Arity) of - false -> - %% Will clobber X registers. Must have a stack frame. - throw(impossible); - true -> - %% The call to this BIF will never return. It is safe - %% to suppress the stack frame. - Bif = #k_bif{anno=Anno, - op=#k_internal{name=guard_error,arity=1}, - args=[Call],ret=[]}, - BrArgs = lists:duplicate(length(BrArgs0), #k_nil{}), - GB = #k_guard_break{anno=#k{us=[],ns=[],a=[]},args=BrArgs}, - Seq#k_seq{arg=Bif,body=GB} - end; - _ -> - %% Will clobber X registers. Must have a stack frame. - throw(impossible) - end; -avoid_stack_frame_1(#k_seq{arg=A0,body=B0}=Seq) -> - A = avoid_stack_frame_1(A0), - B = avoid_stack_frame_1(B0), - Seq#k_seq{arg=A,body=B}; -avoid_stack_frame_1(#k_test{}=Test) -> - Test; -avoid_stack_frame_1(#k_type_clause{values=Values0}=TC) -> - Values = avoid_stack_frame_list(Values0), - TC#k_type_clause{values=Values}; -avoid_stack_frame_1(#k_val_clause{body=B0}=VC) -> - B = avoid_stack_frame_1(B0), - VC#k_val_clause{body=B}; -avoid_stack_frame_1(_Body) -> - throw(impossible). - -avoid_stack_frame_list([H|T]) -> - [avoid_stack_frame_1(H)|avoid_stack_frame_list(T)]; -avoid_stack_frame_list([]) -> []. - - %% This pass creates beam format annotated with variable lifetime %% information. Each thing is given an index and for each variable we %% store the first and last index for its occurrence. The variable diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index c9517c3e51..66e578b776 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -766,14 +766,16 @@ expr({op,_,'++',{lc,Llc,E,Qs0},More}, St0) -> {Qs,St2} = preprocess_quals(Llc, Qs0, St1), {Y,Yps,St} = lc_tq(Llc, E, Qs, Mc, St2), {Y,Mps++Yps,St}; -expr({op,L,'andalso',E1,E2}, St0) -> +expr({op,_,'andalso',_,_}=E0, St0) -> + {op,L,'andalso',E1,E2} = right_assoc(E0, 'andalso', St0), Anno = lineno_anno(L, St0), {#c_var{name=V0},St} = new_var(Anno, St0), V = {var,L,V0}, False = {atom,L,false}, E = make_bool_switch(L, E1, V, E2, False, St0), expr(E, St); -expr({op,L,'orelse',E1,E2}, St0) -> +expr({op,_,'orelse',_,_}=E0, St0) -> + {op,L,'orelse',E1,E2} = right_assoc(E0, 'orelse', St0), Anno = lineno_anno(L, St0), {#c_var{name=V0},St} = new_var(Anno, St0), V = {var,L,V0}, @@ -2626,7 +2628,8 @@ cfun(#ifun{anno=A,id=Id,vars=Args,clauses=Lcs,fc=Lfc}, _As, St0) -> [],A#a.us,St2}. c_call_erl(Fun, Args) -> - cerl:c_call(cerl:c_atom(erlang), cerl:c_atom(Fun), Args). + As = [compiler_generated], + cerl:ann_c_call(As, cerl:c_atom(erlang), cerl:c_atom(Fun), Args). %% lit_vars(Literal) -> [Var]. diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl index 061076b3ff..9f691716e3 100644 --- a/lib/compiler/test/beam_type_SUITE.erl +++ b/lib/compiler/test/beam_type_SUITE.erl @@ -157,6 +157,10 @@ coverage(Config) -> [_|_] -> ok end, + + %% Cover beam_type:verified_type(none). + {'EXIT',{badarith,_}} = (catch (id(2) / id(1)) band 16#ff), + ok. booleans(_Config) -> diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl index e3f842b668..72e5356a8d 100644 --- a/lib/compiler/test/match_SUITE.erl +++ b/lib/compiler/test/match_SUITE.erl @@ -378,6 +378,13 @@ untuplify(Config) when is_list(Config) -> %% We do this to cover sys_core_fold:unalias_pat/1. {1,2,3,4,alias,{[1,2],{3,4},alias}} = untuplify_1([1,2], {3,4}, alias), error = untuplify_1([1,2], {3,4}, 42), + + %% Test that a previous bug in v3_codegen is gone. (The sinking of + %% stack frames into only the case arms that needed them was not always + %% safe.) + [33, -1, -33, 1] = untuplify_2(32, 65), + {33, 1, -33, -1} = untuplify_2(65, 32), + ok. untuplify_1(A, B, C) -> @@ -390,6 +397,21 @@ untuplify_1(A, B, C) -> error end. +untuplify_2(V1, V2) -> + {D1,D2,D3,D4} = + if V1 > V2 -> + %% The 1 value was overwritten by the value of V2-V1. + {V1-V2, 1, V2-V1, -1}; + true -> + {V2-V1, -1, V1-V2, 1} + end, + if + D2 > D4 -> + {D1, D2, D3, D4}; + true -> + [D1, D2, D3, D4] + end. + %% Coverage of beam_dead:shortcut_boolean_label/4. shortcut_boolean(Config) when is_list(Config) -> false = shortcut_boolean_1([0]), diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl index 33d55996ad..1c23eba06d 100644 --- a/lib/compiler/test/warnings_SUITE.erl +++ b/lib/compiler/test/warnings_SUITE.erl @@ -42,7 +42,7 @@ comprehensions/1,maps/1,maps_bin_opt_info/1, redundant_boolean_clauses/1, latin1_fallback/1,underscore/1,no_warnings/1, - bit_syntax/1,inlining/1]). + bit_syntax/1,inlining/1,tuple_calls/1]). init_per_testcase(_Case, Config) -> Config. @@ -64,7 +64,8 @@ groups() -> bin_opt_info,bin_construction,comprehensions,maps, maps_bin_opt_info, redundant_boolean_clauses,latin1_fallback, - underscore,no_warnings,bit_syntax,inlining]}]. + underscore,no_warnings,bit_syntax,inlining, + tuple_calls]}]. init_per_suite(Config) -> test_lib:recompile(?MODULE), @@ -952,6 +953,20 @@ inlining(Config) -> run(Config, Ts), ok. +tuple_calls(Config) -> + %% Make sure that no spurious warnings are generated. + Ts = [{inlining_1, + <<"-compile(tuple_calls). + dispatch(X) -> + (list_to_atom(\"prefix_\" ++ + atom_to_list(suffix))):doit(X). + ">>, + [], + []} + ], + run(Config, Ts), + ok. + %%% %%% End of test cases. %%% diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk index 97179b7fc4..efedb414ad 100644 --- a/lib/compiler/vsn.mk +++ b/lib/compiler/vsn.mk @@ -1 +1 @@ -COMPILER_VSN = 7.3 +COMPILER_VSN = 7.3.1 diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index b33db0d6e4..5c1909fc7f 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -23,7 +23,7 @@ <title>crypto</title> </header> - <module>crypto</module> + <module since="">crypto</module> <modulesummary>Crypto Functions</modulesummary> <description> <p>This module provides a set of cryptographic functions. @@ -524,7 +524,7 @@ <!--================ FUNCTIONS ================--> <funcs> <func> - <name name="block_encrypt" arity="3"/> + <name name="block_encrypt" arity="3" since="OTP 18.0"/> <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary> <desc> <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.</p> @@ -537,7 +537,7 @@ </func> <func> - <name name="block_decrypt" arity="3"/> + <name name="block_decrypt" arity="3" since="OTP 18.0"/> <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary> <desc> <p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.</p> @@ -550,9 +550,9 @@ </func> <func> - <name>block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name> - <name>block_encrypt(AeadType, Key, Ivec, {AAD, PlainText}) -> {CipherText, CipherTag}</name> - <name>block_encrypt(aes_gcm | aes_ccm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag}</name> + <name since="OTP R16B01">block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name> + <name since="OTP R16B01">block_encrypt(AeadType, Key, Ivec, {AAD, PlainText}) -> {CipherText, CipherTag}</name> + <name since="OTP R16B01">block_encrypt(aes_gcm | aes_ccm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag}</name> <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary> <type> <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v> @@ -577,8 +577,8 @@ </func> <func> - <name>block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name> - <name>block_decrypt(AeadType, Key, Ivec, {AAD, CipherText, CipherTag}) -> PlainText | error</name> + <name since="OTP R16B01">block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name> + <name since="OTP R16B01">block_decrypt(AeadType, Key, Ivec, {AAD, CipherText, CipherTag}) -> PlainText | error</name> <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary> <type> <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v> @@ -603,7 +603,7 @@ </func> <func> - <name name="bytes_to_integer" arity="1"/> + <name name="bytes_to_integer" arity="1" since="OTP R16B01"/> <fsummary>Convert binary representation, of an integer, to an Erlang integer.</fsummary> <desc> <p>Convert binary representation, of an integer, to an Erlang integer. @@ -612,7 +612,7 @@ </func> <func> - <name name="compute_key" arity="4"/> + <name name="compute_key" arity="4" since="OTP R16B01"/> <fsummary>Computes the shared secret</fsummary> <desc> <p>Computes the shared secret from the private key and the other party's public key. @@ -622,7 +622,7 @@ </func> <func> - <name name="exor" arity="2"/> + <name name="exor" arity="2" since=""/> <fsummary>XOR data</fsummary> <desc> <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p> @@ -631,8 +631,8 @@ <func> - <name name="generate_key" arity="2"/> - <name name="generate_key" arity="3"/> + <name name="generate_key" arity="2" since="OTP R16B01"/> + <name name="generate_key" arity="3" since="OTP R16B01"/> <fsummary>Generates a public key of type <c>Type</c></fsummary> <desc> <p>Generates a public key of type <c>Type</c>. @@ -653,7 +653,7 @@ </func> <func> - <name name="hash" arity="2"/> + <name name="hash" arity="2" since="OTP R15B02"/> <fsummary></fsummary> <desc> <p>Computes a message digest of type <c>Type</c> from <c>Data</c>.</p> @@ -663,7 +663,7 @@ </func> <func> - <name name="hash_init" arity="1"/> + <name name="hash_init" arity="1" since="OTP R15B02"/> <fsummary></fsummary> <desc> <p>Initializes the context for streaming hash operations. <c>Type</c> determines @@ -675,7 +675,7 @@ </func> <func> - <name name="hash_update" arity="2"/> + <name name="hash_update" arity="2" since="OTP R15B02"/> <fsummary></fsummary> <desc> <p>Updates the digest represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c> @@ -687,7 +687,7 @@ </func> <func> - <name name="hash_final" arity="1"/> + <name name="hash_final" arity="1" since="OTP R15B02"/> <fsummary></fsummary> <desc> <p>Finalizes the hash operation referenced by <c>Context</c> returned @@ -698,8 +698,8 @@ </func> <func> - <name name="hmac" arity="3"/> - <name name="hmac" arity="4"/> + <name name="hmac" arity="3" since="OTP R16B"/> + <name name="hmac" arity="4" since="OTP R16B"/> <fsummary></fsummary> <desc> <p>Computes a HMAC of type <c>Type</c> from <c>Data</c> using @@ -709,7 +709,7 @@ </func> <func> - <name name="hmac_init" arity="2"/> + <name name="hmac_init" arity="2" since="OTP R14B03"/> <fsummary></fsummary> <desc> <p>Initializes the context for streaming HMAC operations. <c>Type</c> determines @@ -719,7 +719,7 @@ </func> <func> - <name name="hmac_update" arity="2"/> + <name name="hmac_update" arity="2" since="OTP R14B03"/> <fsummary></fsummary> <desc> <p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c> @@ -738,7 +738,7 @@ </func> <func> - <name name="hmac_final" arity="1"/> + <name name="hmac_final" arity="1" since="OTP R14B03"/> <fsummary></fsummary> <desc> <p>Finalizes the HMAC operation referenced by <c>Context</c>. The size of the resultant MAC is @@ -747,7 +747,7 @@ </func> <func> - <name name="hmac_final_n" arity="2"/> + <name name="hmac_final_n" arity="2" since="OTP R14B03"/> <fsummary></fsummary> <desc> <p>Finalizes the HMAC operation referenced by <c>Context</c>. <c>HashLen</c> must be greater than @@ -756,8 +756,8 @@ </func> <func> - <name name="cmac" arity="3"/> - <name name="cmac" arity="4"/> + <name name="cmac" arity="3" since="OTP 20.0"/> + <name name="cmac" arity="4" since="OTP 20.0"/> <fsummary>Calculates the Cipher-based Message Authentication Code.</fsummary> <desc> <p>Computes a CMAC of type <c>Type</c> from <c>Data</c> using @@ -767,7 +767,7 @@ </func> <func> - <name name="info_fips" arity="0"/> + <name name="info_fips" arity="0" since="OTP 20.0"/> <fsummary>Provides information about the FIPS operating status.</fsummary> <desc> <p>Provides information about the FIPS operating status of @@ -790,7 +790,7 @@ </func> <func> - <name name="enable_fips_mode" arity="1"/> + <name name="enable_fips_mode" arity="1" since="OTP 21.1"/> <fsummary>Change FIPS mode.</fsummary> <desc> <p>Enables (<c>Enable = true</c>) or disables (<c>Enable = false</c>) FIPS mode. Returns <c>true</c> if @@ -805,7 +805,7 @@ </func> <func> - <name name="info_lib" arity="0"/> + <name name="info_lib" arity="0" since=""/> <fsummary>Provides information about the libraries used by crypto.</fsummary> <desc> <p>Provides the name and version of the libraries used by crypto.</p> @@ -826,7 +826,7 @@ </func> <func> - <name name="mod_pow" arity="3"/> + <name name="mod_pow" arity="3" since="OTP R16B01"/> <fsummary>Computes the function: N^P mod M</fsummary> <desc> <p>Computes the function <c>N^P mod M</c>.</p> @@ -834,8 +834,8 @@ </func> <func> - <name name="next_iv" arity="2"/> - <name name="next_iv" arity="3"/> + <name name="next_iv" arity="2" since="OTP R16B01"/> + <name name="next_iv" arity="3" since="OTP R16B01"/> <fsummary></fsummary> <desc> <p>Returns the initialization vector to be used in the next @@ -847,7 +847,7 @@ </func> <func> - <name name="poly1305" arity="2"/> + <name name="poly1305" arity="2" since="OTP 21.1"/> <fsummary></fsummary> <desc> <p>Computes a POLY1305 message authentication code (<c>Mac</c>) from <c>Data</c> using @@ -856,7 +856,7 @@ </func> <func> - <name name="private_decrypt" arity="4"/> + <name name="private_decrypt" arity="4" since="OTP R16B01"/> <fsummary>Decrypts CipherText using the private Key.</fsummary> <desc> <p>Decrypts the <c>CipherText</c>, encrypted with @@ -870,7 +870,7 @@ </func> <func> - <name name="private_encrypt" arity="4"/> + <name name="private_encrypt" arity="4" since="OTP R16B01"/> <fsummary>Encrypts PlainText using the private Key.</fsummary> <desc> <p>Encrypts the <c>PlainText</c> using the <c>PrivateKey</c> @@ -883,7 +883,7 @@ </func> <func> - <name name="public_decrypt" arity="4"/> + <name name="public_decrypt" arity="4" since="OTP R16B01"/> <fsummary>Decrypts CipherText using the public Key.</fsummary> <desc> <p>Decrypts the <c>CipherText</c>, encrypted with @@ -897,7 +897,7 @@ </func> <func> - <name name="public_encrypt" arity="4"/> + <name name="public_encrypt" arity="4" since="OTP R16B01"/> <fsummary>Encrypts PlainText using the public Key.</fsummary> <desc> <p>Encrypts the <c>PlainText</c> (message digest) using the <c>PublicKey</c> @@ -909,7 +909,7 @@ </func> <func> - <name name="rand_seed" arity="1"/> + <name name="rand_seed" arity="1" since="OTP 17.0"/> <fsummary>Set the seed for random bytes generation</fsummary> <desc> <p>Set the seed for PRNG to the given binary. This calls the @@ -922,7 +922,7 @@ </func> <func> - <name>rand_uniform(Lo, Hi) -> N</name> + <name since="">rand_uniform(Lo, Hi) -> N</name> <fsummary>Generate a random number</fsummary> <type> <v>Lo, Hi, N = integer()</v> @@ -935,7 +935,7 @@ </func> <func> - <name name="start" arity="0"/> + <name name="start" arity="0" since=""/> <fsummary> Equivalent to application:start(crypto). </fsummary> <desc> <p> Equivalent to application:start(crypto).</p> @@ -943,7 +943,7 @@ </func> <func> - <name name="stop" arity="0"/> + <name name="stop" arity="0" since=""/> <fsummary> Equivalent to application:stop(crypto).</fsummary> <desc> <p> Equivalent to application:stop(crypto).</p> @@ -951,7 +951,7 @@ </func> <func> - <name name="strong_rand_bytes" arity="1"/> + <name name="strong_rand_bytes" arity="1" since="OTP R14B03"/> <fsummary>Generate a binary of random bytes</fsummary> <desc> <p>Generates N bytes randomly uniform 0..255, and returns the @@ -964,7 +964,7 @@ </func> <func> - <name name="rand_seed" arity="0"/> + <name name="rand_seed" arity="0" since="OTP 20.0"/> <fsummary>Strong random number generation plugin state</fsummary> <desc> <p> @@ -992,7 +992,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="rand_seed_s" arity="0"/> + <name name="rand_seed_s" arity="0" since="OTP 20.0"/> <fsummary>Strong random number generation plugin state</fsummary> <desc> <p> @@ -1027,7 +1027,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name>rand_seed_alg(Alg) -> rand:state()</name> + <name since="OTP 21.0">rand_seed_alg(Alg) -> rand:state()</name> <fsummary>Strong random number generation plugin state</fsummary> <type> <v>Alg = crypto | crypto_cache</v> @@ -1063,7 +1063,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name>rand_seed_alg_s(Alg) -> rand:state()</name> + <name since="OTP 21.0">rand_seed_alg_s(Alg) -> rand:state()</name> <fsummary>Strong random number generation plugin state</fsummary> <type> <v>Alg = crypto | crypto_cache</v> @@ -1121,7 +1121,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="stream_init" arity="2"/> + <name name="stream_init" arity="2" since="OTP R16B01"/> <fsummary></fsummary> <desc> <p>Initializes the state for use in RC4 stream encryption @@ -1134,7 +1134,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="stream_init" arity="3"/> + <name name="stream_init" arity="3" since="OTP R16B01"/> <fsummary></fsummary> <desc> <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR). @@ -1149,7 +1149,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="stream_encrypt" arity="2"/> + <name name="stream_encrypt" arity="2" since="OTP R16B01"/> <fsummary></fsummary> <desc> <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3. @@ -1160,7 +1160,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="stream_decrypt" arity="2"/> + <name name="stream_decrypt" arity="2" since="OTP R16B01"/> <fsummary></fsummary> <desc> <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3. @@ -1171,7 +1171,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="supports" arity="0"/> + <name name="supports" arity="0" since="OTP R16B01"/> <fsummary>Provide a list of available crypto algorithms.</fsummary> <desc> <p> Can be used to determine which crypto algorithms that are supported @@ -1183,7 +1183,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="ec_curves" arity="0"/> + <name name="ec_curves" arity="0" since="OTP 17.0"/> <fsummary>Provide a list of available named elliptic curves.</fsummary> <desc> <p>Can be used to determine which named elliptic curves are supported.</p> @@ -1191,7 +1191,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="ec_curve" arity="1"/> + <name name="ec_curve" arity="1" since="OTP 17.0"/> <fsummary>Get the defining parameters of a elliptic curve.</fsummary> <desc> <p>Return the defining parameters of a elliptic curve.</p> @@ -1199,8 +1199,8 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="sign" arity="4"/> - <name name="sign" arity="5"/> + <name name="sign" arity="4" since="OTP R16B01"/> + <name name="sign" arity="5" since="OTP 20.1"/> <fsummary> Create digital signature.</fsummary> <desc> <p>Creates a digital signature.</p> @@ -1214,8 +1214,8 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="verify" arity="5"/> - <name name="verify" arity="6"/> + <name name="verify" arity="5" since="OTP R16B01"/> + <name name="verify" arity="6" since="OTP 20.1"/> <fsummary>Verifies a digital signature.</fsummary> <desc> <p>Verifies a digital signature</p> @@ -1231,7 +1231,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> <!-- Engine functions --> <func> - <name name="privkey_to_pubkey" arity="2"/> + <name name="privkey_to_pubkey" arity="2" since="OTP 20.2"/> <fsummary>Fetches a public key from an Engine stored private key.</fsummary> <desc> <p>Fetches the corresponding public key from a private key stored in an Engine. @@ -1241,7 +1241,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_get_all_methods" arity="0"/> + <name name="engine_get_all_methods" arity="0" since="OTP 20.2"/> <fsummary>Return list of all possible engine methods</fsummary> <desc> <p> @@ -1259,7 +1259,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_load" arity="3"/> + <name name="engine_load" arity="3" since="OTP 20.2"/> <fsummary>Dynamical load an encryption engine</fsummary> <desc> <p> @@ -1281,7 +1281,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_load" arity="4"/> + <name name="engine_load" arity="4" since="OTP 20.2"/> <fsummary>Dynamical load an encryption engine</fsummary> <desc> <p> @@ -1301,7 +1301,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_unload" arity="1"/> + <name name="engine_unload" arity="1" since="OTP 20.2"/> <fsummary>Dynamical load an encryption engine</fsummary> <desc> <p> @@ -1321,7 +1321,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_by_id" arity="1"/> + <name name="engine_by_id" arity="1" since="OTP 21.0.6"/> <fsummary>Get a reference to an already loaded engine</fsummary> <desc> <p> @@ -1341,7 +1341,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_ctrl_cmd_string" arity="3"/> + <name name="engine_ctrl_cmd_string" arity="3" since="OTP 20.2"/> <fsummary>Sends ctrl commands to an OpenSSL engine</fsummary> <desc> <p> @@ -1358,7 +1358,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_ctrl_cmd_string" arity="4"/> + <name name="engine_ctrl_cmd_string" arity="4" since="OTP 20.2"/> <fsummary>Sends ctrl commands to an OpenSSL engine</fsummary> <desc> <p> @@ -1379,7 +1379,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_add" arity="1"/> + <name name="engine_add" arity="1" since="OTP 21.0.6"/> <fsummary>Add engine to OpenSSL internal list</fsummary> <desc> <p>Add the engine to OpenSSL's internal list.</p> @@ -1392,7 +1392,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_remove" arity="1"/> + <name name="engine_remove" arity="1" since="OTP 21.0.6"/> <fsummary>Remove engine to OpenSSL internal list</fsummary> <desc> <p>Remove the engine from OpenSSL's internal list.</p> @@ -1405,7 +1405,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_get_id" arity="1"/> + <name name="engine_get_id" arity="1" since="OTP 21.0.6"/> <fsummary>Fetch engine ID</fsummary> <desc> <p>Return the ID for the engine, or an empty binary if there is no id set.</p> @@ -1418,7 +1418,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_get_name" arity="1"/> + <name name="engine_get_name" arity="1" since="OTP 21.0.6"/> <fsummary>Fetch engine name</fsummary> <desc> <p>Return the name (eg a description) for the engine, or an empty binary if there is no name set.</p> @@ -1431,7 +1431,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="engine_list" arity="0"/> + <name name="engine_list" arity="0" since="OTP 20.2"/> <fsummary>List the known engine ids</fsummary> <desc> <p>List the id's of all engines in OpenSSL's internal list.</p> @@ -1451,7 +1451,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="ensure_engine_loaded" arity="2"/> + <name name="ensure_engine_loaded" arity="2" since="OTP 21.0.6"/> <fsummary>Ensure encryption engine just loaded once</fsummary> <desc> <p> @@ -1473,7 +1473,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="ensure_engine_loaded" arity="3"/> + <name name="ensure_engine_loaded" arity="3" since="OTP 21.0.6"/> <fsummary>Ensure encryption engine just loaded once</fsummary> <desc> <p> @@ -1496,7 +1496,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="ensure_engine_unloaded" arity="1"/> + <name name="ensure_engine_unloaded" arity="1" since="OTP 21.0.6"/> <fsummary>Unload an engine loaded with the ensure function</fsummary> <desc> <p> @@ -1519,7 +1519,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre> </func> <func> - <name name="ensure_engine_unloaded" arity="2"/> + <name name="ensure_engine_unloaded" arity="2" since="OTP 21.0.6"/> <fsummary>Unload an engine loaded with the ensure function</fsummary> <desc> <p> diff --git a/lib/crypto/doc/src/engine_keys.xml b/lib/crypto/doc/src/engine_keys.xml index feeb353d1e..5ac690eb90 100644 --- a/lib/crypto/doc/src/engine_keys.xml +++ b/lib/crypto/doc/src/engine_keys.xml @@ -51,7 +51,7 @@ <p> OTP/Crypto requires that the user provides two or three items of information about the key. The application used by the user is usually on a higher level, for example in - <seealso marker="ssl:ssl#key_option_def">SSL</seealso>. If using + <seealso marker="ssl:ssl#type-key">SSL</seealso>. If using the crypto application directly, it is required that: </p> <list> diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile index e046a25338..8b320e01a9 100644 --- a/lib/crypto/test/Makefile +++ b/lib/crypto/test/Makefile @@ -6,6 +6,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # ---------------------------------------------------- MODULES = \ + crypto_bench_SUITE \ blowfish_SUITE \ crypto_SUITE \ engine_SUITE @@ -77,7 +78,7 @@ release_spec: release_tests_spec: $(TEST_TARGET) $(INSTALL_DIR) "$(RELSYSDIR)" - $(INSTALL_DATA) crypto.spec crypto.cover $(RELTEST_FILES) "$(RELSYSDIR)" + $(INSTALL_DATA) crypto.spec crypto_bench.spec crypto.cover $(RELTEST_FILES) "$(RELSYSDIR)" @tar cfh - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -) chmod -R u+w "$(RELSYSDIR)" diff --git a/lib/crypto/test/crypto.spec b/lib/crypto/test/crypto.spec index cc09970cb3..4a95275687 100644 --- a/lib/crypto/test/crypto.spec +++ b/lib/crypto/test/crypto.spec @@ -1 +1,6 @@ {suites,"../crypto_test",all}. + +{skip_suites, "../crypto_test", [crypto_bench_SUITE + ], + "Benchmarks run separately"}. + diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 6c6188f775..98de1d7700 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -156,7 +156,7 @@ groups() -> ]}, {dh, [], [generate_compute, compute_bug]}, - {ecdh, [], [generate_all_supported, compute, generate]}, + {ecdh, [], [use_all_elliptic_curves, compute, generate]}, {srp, [], [generate_compute]}, {des_cbc, [], [block]}, {des_cfb, [], [block]}, @@ -563,32 +563,43 @@ compute(Config) when is_list(Config) -> Gen = proplists:get_value(compute, Config), lists:foreach(fun do_compute/1, Gen). %%-------------------------------------------------------------------- -generate_all_supported() -> - [{doc, " Test that all curves from crypto:ec_curves/0 returns two binaries"}]. -generate_all_supported(_Config) -> +use_all_elliptic_curves() -> + [{doc, " Test that all curves from crypto:ec_curves/0"}]. +use_all_elliptic_curves(_Config) -> + Msg = <<"hello world!">>, + Sups = crypto:supports(), + Curves = proplists:get_value(curves, Sups), + Hashs = proplists:get_value(hashs, Sups), + ct:log("Lib: ~p~nFIPS: ~p~nCurves:~n~p~nHashs: ~p", [crypto:info_lib(), + crypto:info_fips(), + Curves, + Hashs]), Results = - [try - crypto:generate_key(ecdh, C) - of - {B1,B2} when is_binary(B1) and is_binary(B2) -> - %% That is, seems like it works as expected. - {ok,C}; - Err -> - ct:log("ERROR: Curve ~p generated ~p", [C,Err]), - {error,{C,Err}} - catch - Cls:Err:Stack -> - ct:log("ERROR: Curve ~p exception ~p:~p~n~p", [C,Cls,Err,Stack]), - {error,{C,{Cls,Err}}} - end - || C <- crypto:ec_curves(), - not lists:member(C, [ed25519, ed448]) + [{{Curve,Hash}, + try + {Pub,Priv} = crypto:generate_key(ecdh, Curve), + true = is_binary(Pub), + true = is_binary(Priv), + Sig = crypto:sign(ecdsa, Hash, Msg, [Priv, Curve]), + crypto:verify(ecdsa, Hash, Msg, Sig, [Pub, Curve]) + catch + C:E -> + {C,E} + end} + || Curve <- Curves -- [ed25519, ed448, x25519, x448, ipsec3, ipsec4], + Hash <- Hashs -- [md4, md5, ripemd160, sha3_224, sha3_256, sha3_384, sha3_512] ], - OK = [C || {ok,C} <- Results], - ct:log("Ok (len=~p): ~p", [length(OK), OK]), - false = lists:any(fun({error,_}) -> true; - (_) -> false - end, Results). + Fails = + lists:filter(fun({_,true}) -> false; + (_) -> true + end, Results), + case Fails of + [] -> + ok; + _ -> + ct:log("Fails:~n~p",[Fails]), + ct:fail("Bad curve(s)",[]) + end. %%-------------------------------------------------------------------- generate() -> diff --git a/lib/crypto/test/crypto_bench.spec b/lib/crypto/test/crypto_bench.spec new file mode 100644 index 0000000000..b9a26d94db --- /dev/null +++ b/lib/crypto/test/crypto_bench.spec @@ -0,0 +1,3 @@ +{suites, "../crypto_test", [ + crypto_bench_SUITE + ]}. diff --git a/lib/crypto/test/crypto_bench_SUITE.erl b/lib/crypto/test/crypto_bench_SUITE.erl new file mode 100644 index 0000000000..c66a27f0c8 --- /dev/null +++ b/lib/crypto/test/crypto_bench_SUITE.erl @@ -0,0 +1,400 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-2018. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(crypto_bench_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct_event.hrl"). +-include_lib("common_test/include/ct.hrl"). + +suite() -> [%%{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}, + {timetrap,{minutes,2}} + ]. + +all() -> + [ + {group, textblock_256} + ]. + +groups() -> + [ + {textblock_256, [], [ + {group, ciphers_128}, + {group, ciphers_256} + ]}, + + {ciphers_128, [{repeat, 5}], [ + block, + stream + ]}, + + {ciphers_256, [{repeat, 5}], [ + block, + stream, + chacha + ]} + ]. + +%%%---------------------------------------------------------------- +%%% +init_per_suite(Config0) -> + try crypto:start() of + _ -> + [{_,_,Info}] = crypto:info_lib(), + ct:comment("~s",[Info]), + ct:pal("Crypto version: ~p~n~n~p",[Info,crypto:supports()]), + Config1 = measure_openssl_aes_cbc([128,256], Config0), + calibrate([{sec_goal,10} | Config1]) + + catch _:_ -> + {fail, "Crypto did not start"} + end. + +end_per_suite(_Config) -> + application:stop(crypto). + +%%%---------------------------------------------------------------- +%%% +init_per_group(Group, Config) -> + case atom_to_list(Group) of + "ciphers_"++KeySizeStr -> + KeySize = list_to_integer(KeySizeStr), + [{key_size,KeySize} | Config]; + + "textblock_"++BlockSizeStr -> + BlockSize = list_to_integer(BlockSizeStr), + [{block_size,BlockSize} | Config]; + + _ -> + Config + end. + +end_per_group(_Group, Config) -> + Config. + + +measure_openssl_aes_cbc(KeySizes, Config) -> + BLno_acc = [baseline(aes_cbc, KeySize, false) || KeySize <- KeySizes], + ct:pal("Non-accelerated baseline encryption time [µs/block]:~n~p", [BLno_acc]), + BLacc = [baseline(aes_cbc, KeySize, true) || KeySize <- KeySizes], + ct:pal("Possibly accelerated baseline encryption time [µs/block]:~n~p", [BLacc]), + [{acc,BLacc}, + {no_acc,BLno_acc} | Config]. + +calibrate(Config) -> + Secs = proplists:get_value(sec_goal, Config, 10), + {_,Empty} = data(empty, 0, 0), + {Ne,Te} = run1(Secs*3000, Empty), + report(["Overhead"], Te/Ne), + [{overhead,Te/Ne} | Config]. + +%%%================================================================ +%%% +%%% +block(Config) -> + run_cryptos([aes_cbc, aes_gcm, aes_ccm], + Config). + +stream(Config) -> + run_cryptos([aes_ctr], + Config). + +chacha(Config) -> + run_cryptos([chacha20, chacha20_poly1305], + Config). + + +%%%================================================================ +%%% +%%% + +run_cryptos(Cryptos, Config) -> + KeySize = proplists:get_value(key_size, Config), + BlockSize = proplists:get_value(block_size, Config), + MilliSecGoal = 1000*proplists:get_value(sec_goal,Config), + OverHead = proplists:get_value(overhead, Config, 0), + [try + TimePerOpBrutto = run(Crypto,KeySize,BlockSize,MilliSecGoal), + %% ct:pal("Brutto: ~p Overhead: ~p (~.2f %) Netto: ~p", + %% [TimePerOpBrutto, OverHead, 100*OverHead/TimePerOpBrutto,TimePerOpBrutto - OverHead]), + TimePerOpBrutto - OverHead + of + TimePerOp -> % µs + %% First, Report speed of encrypting blocks of 1000. [blocks/sec] + ReportUnit = 1000, + Label = [fmt(Crypto)," key:",KeySize," block:",BlockSize], + report(Label, + (BlockSize/ReportUnit)*1000000/TimePerOp + ), + + EffCrypto = case Crypto of + X -> X + end, + %% Percent of accelerated speed + case find_value([acc,{EffCrypto,KeySize},BlockSize], Config) of + undefined -> + ok; + TimePerOpBaseAcc -> + report(["Percent of acc OpenSSL "|Label], + 100*TimePerOpBaseAcc/TimePerOp % Percent of base *speed* + ) + end, + + %% Percent of non-accelerated speed + case find_value([no_acc,{EffCrypto,KeySize},BlockSize], Config) of + undefined -> + ok; + TimePerOpBaseNoAcc -> + report(["Percent of noacc OpenSSL "|Label], + 100*TimePerOpBaseNoAcc/TimePerOp % Percent of base *speed* + ) + end + catch + _:_ -> + ct:pal("~p unsupported",[{Crypto,KeySize,BlockSize}]) + end + || Crypto <- Cryptos, + supported(Crypto) + ]. + + +run(Crypto, KeySize, BlockSize, MilliSecGoal) -> + {_Type, Funs} = data(Crypto, KeySize, BlockSize), + {Nc,Tc} = run1(MilliSecGoal, Funs), + Tc/Nc. + +fmt(X) -> X. + + +find_value(KeyPath, PropList, Default) -> + try find_value(KeyPath, PropList) + of + undefined -> Default + catch + error:function_clause -> Default + end. + +find_value(KeyPath, PropList) -> + lists:foldl(fun(K, L) when is_list(L) -> proplists:get_value(K,L); + (_, _) -> undefined + end, PropList, KeyPath). + +%%%================================================================ +%%% +%%% +funs({block, {Type, Key, IV, Block}}) -> + {fun() -> ok end, + fun(_) -> crypto:block_encrypt(Type, Key, IV, Block) end, + fun(_) -> ok end}; + +funs({stream, {Type, Key, IV, Block}}) -> + {fun() -> {crypto:stream_init(Type, Key, IV),ok} end, + fun({Ctx,_}) -> crypto:stream_encrypt(Ctx, Block) end, + fun(_) -> ok end}. + + +data(aes_cbc, KeySize, BlockSize) -> + Type = case KeySize of + 128 -> aes_cbc128; + 256 -> aes_cbc256 + end, + Key = mk_bin(KeySize div 8), + IV = mk_bin(16), + Block = mk_bin(BlockSize), + {Type, funs({block, {Type, Key, IV, Block}})}; + +data(aes_gcm, KeySize, BlockSize) -> + Type = aes_gcm, + Key = mk_bin(KeySize div 8), + IV = mk_bin(12), + Block = mk_bin(BlockSize), + AAD = <<01,02,03,04>>, + {Type, funs({block, {Type, Key, IV, {AAD,Block,16}}})}; + +data(aes_ccm, KeySize, BlockSize) -> + Type = aes_ccm, + Key = mk_bin(KeySize div 8), + IV = mk_bin(12), + Block = mk_bin(BlockSize), + AAD = <<01,02,03,04>>, + {Type, funs({block, {Type, Key, IV, {AAD,Block,12}}})}; + +data(aes_ctr, KeySize, BlockSize) -> + Type = aes_ctr, + Key = mk_bin(KeySize div 8), + IV = mk_bin(16), + Block = mk_bin(BlockSize), + {Type, funs({stream, {Type, Key, IV, Block}})}; + +data(chacha20_poly1305, 256=KeySize, BlockSize) -> + Type = chacha20_poly1305, + Key = mk_bin(KeySize div 8), + IV = mk_bin(16), + AAD = <<01,02,03,04>>, + Block = mk_bin(BlockSize), + {Type, funs({block, {Type, Key, IV, {AAD,Block}}})}; + +data(chacha20, 256=KeySize, BlockSize) -> + Type = chacha20, + Key = mk_bin(KeySize div 8), + IV = mk_bin(16), + Block = mk_bin(BlockSize), + {Type, funs({stream, {Type, Key, IV, Block}})}; + +data(empty, 0, 0) -> + {undefined, + {fun() -> ok end, + fun(X) -> X end, + fun(_) -> ok end}}. + +%%%================================================================ +%%% +%%% +run1(MilliSecGoal, Funs) -> + Parent = self(), + Pid = spawn(fun() -> + {Fi,Fu,Ff} = Funs, + Ctx0 = Fi(), + erlang:garbage_collect(), + T0 = start_time(), + {N,Ctx} = loop(Fu, Ctx0, 0), + T = elapsed_time(T0), + Ff(Ctx), + Parent ! {result,N,microseconds(T)} + end), + Pid ! go, + receive + after MilliSecGoal -> + Pid ! stop + end, + receive + {result,N,MicroSecs} -> + {N,MicroSecs} + end. + + +loop(F, Ctx, N) -> + receive + stop -> + {N, Ctx} + after 0 -> + loop(F, F(Ctx), N+1) + end. + +%%%---------------------------------------------------------------- +report(LabelList, Value) -> + Label = report_chars(lists:concat(LabelList)), + ct:pal("ct_event:notify ~p: ~p", [Label, Value]), + ct_event:notify( + #event{name = benchmark_data, + data = [{name, Label}, + {value,Value}]}). + +report_chars(Cs) -> + [case C of + $- -> $_; + _ -> C + end || C <- Cs]. + +%%%---------------------------------------------------------------- +supported(Algorithm) -> + lists:member(Algorithm, + [A || {_,As} <- crypto:supports(), A <- As] + ). + +%%%---------------------------------------------------------------- +start_time() -> + erlang:system_time(). + +elapsed_time(StartTime) -> + erlang:system_time() - StartTime. + +microseconds(Time) -> + erlang:convert_time_unit(Time, native, microsecond). + +%%%---------------------------------------------------------------- + +%% Example output: +%% +DT:aes-128-cbc:3:16 +%% +R:135704772:aes-128-cbc:2.980000 +%% +DT:aes-128-cbc:3:64 +%% +R:36835089:aes-128-cbc:3.000000 +%% +DT:aes-128-cbc:3:256 +%% +R:9398616:aes-128-cbc:3.000000 +%% +DT:aes-128-cbc:3:1024 +%% +R:2355683:aes-128-cbc:2.990000 +%% +DT:aes-128-cbc:3:8192 +%% +R:294508:aes-128-cbc:2.990000 +%% +H:16:64:256:1024:8192 +%% +F:22:aes-128-cbc:728616225.50:785815232.00:802015232.00:806762338.46:806892821.40 + +baseline(Crypto, KeySize, EVP) -> + Spec= + case {Crypto,KeySize} of + {aes_cbc, 128} -> "aes-128-cbc"; + {aes_cbc, 256} -> "aes-256-cbc" + end, + {{Crypto,KeySize}, baseline(Spec, EVP)}. + +baseline(Spec, EVP) -> + Cmd = + case EVP of + true -> "openssl speed -mr -evp " ++ Spec; + false-> "openssl speed -mr " ++ Spec + end, + get_base_values(string:tokens(os:cmd(Cmd),"\n"), Spec, []). + + +get_base_values(["+DT:"++Sdt, + "+R:"++Sr + |T], Crypto, Acc) -> + [Crypto0,_GoalSecs0,BlockSize0] = string:tokens(Sdt, ":"), + [Nblocks0,Crypto0,RealSecs0] = string:tokens(Sr, ":"), + Crypto = fix_possible_space_bug(Crypto0), + RealSecs = list_to_float(RealSecs0), + BlockSize = list_to_integer(BlockSize0), + Nblocks = list_to_integer(Nblocks0), + get_base_values(T, Crypto, [{BlockSize, 1000000*RealSecs/Nblocks} | Acc]); + +get_base_values([_|T], Crypto, Acc) -> + get_base_values(T, Crypto, Acc); + +get_base_values([], _, Acc) -> + lists:sort(Acc). + +fix_possible_space_bug(S) -> lists:concat(lists:join("-",string:tokens(S,"- "))). + +%%%---------------------------------------------------------------- +mk_bin(Size) when Size =< 256 -> + list_to_binary(lists:seq(0,Size-1)); + +mk_bin(Size) when 1024 =< Size -> + B = mk_bin(Size div 4), + Brest = mk_bin(Size rem 4), + <<B/binary, B/binary, B/binary, B/binary, Brest/binary>>; + +mk_bin(Size) when 256 < Size -> + B = mk_bin(Size div 2), + Brest = mk_bin(Size rem 2), + <<B/binary, B/binary, Brest/binary>>. + diff --git a/lib/crypto/test/engine_SUITE.erl b/lib/crypto/test/engine_SUITE.erl index 8a45fc9076..869db516b4 100644 --- a/lib/crypto/test/engine_SUITE.erl +++ b/lib/crypto/test/engine_SUITE.erl @@ -345,13 +345,13 @@ engine_list(Config) when is_list(Config) -> {skip, "OTP Test engine not found"}; {ok, Engine} -> try - EngineList0 = crypto:engine_list(), case crypto:engine_load(<<"dynamic">>, [{<<"SO_PATH">>, Engine}, <<"LOAD">>], []) of {ok, E} -> EngineList0 = crypto:engine_list(), + false = lists:member(<<"MD5">>, EngineList0), ok = crypto:engine_add(E), [<<"MD5">>] = lists:subtract(crypto:engine_list(), EngineList0), ok = crypto:engine_remove(E), diff --git a/lib/debugger/doc/src/debugger.xml b/lib/debugger/doc/src/debugger.xml index 1ecdbcd064..77285095e7 100644 --- a/lib/debugger/doc/src/debugger.xml +++ b/lib/debugger/doc/src/debugger.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>debugger</module> + <module since="">debugger</module> <modulesummary>Erlang Debugger.</modulesummary> <description> <p>Erlang Debugger for debugging and testing of Erlang programs.</p> @@ -36,10 +36,10 @@ <funcs> <func> - <name>start()</name> - <name>start(File)</name> - <name>start(Mode)</name> - <name>start(Mode, File)</name> + <name since="">start()</name> + <name since="">start(File)</name> + <name since="">start(Mode)</name> + <name since="">start(Mode, File)</name> <fsummary>Start Debugger.</fsummary> <type> <v>Mode = local | global</v> @@ -60,7 +60,7 @@ </func> <func> - <name>quick(Module, Name, Args)</name> + <name since="">quick(Module, Name, Args)</name> <fsummary>Debug a process.</fsummary> <type> <v>Module = Name = atom()</v> diff --git a/lib/debugger/doc/src/i.xml b/lib/debugger/doc/src/i.xml index 628b91e9e4..06b0eb876a 100644 --- a/lib/debugger/doc/src/i.xml +++ b/lib/debugger/doc/src/i.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>i</module> + <module since="">i</module> <modulesummary>Debugger/Interpreter Interface.</modulesummary> <description> <p>The <c>i</c> module provides short forms for some of @@ -51,7 +51,7 @@ <funcs> <func> - <name>im() -> pid()</name> + <name since="">im() -> pid()</name> <fsummary>Start a graphical monitor.</fsummary> <desc> <p>Starts a new graphical monitor. This is the Monitor window, @@ -63,10 +63,10 @@ </func> <func> - <name>ii(AbsModules) -> ok</name> - <name>ii(AbsModule) -> {module, Module} | error</name> - <name>ini(AbsModules) -> ok</name> - <name>ini(AbsModule) -> {module, Module} | error</name> + <name since="">ii(AbsModules) -> ok</name> + <name since="">ii(AbsModule) -> {module, Module} | error</name> + <name since="">ini(AbsModules) -> ok</name> + <name since="">ini(AbsModule) -> {module, Module} | error</name> <fsummary>Interpret a module.</fsummary> <type> <v>AbsModules = [AbsModule]</v> @@ -84,8 +84,8 @@ </func> <func> - <name>iq(AbsModule) -> ok</name> - <name>inq(AbsModule) -> ok</name> + <name since="">iq(AbsModule) -> ok</name> + <name since="">inq(AbsModule) -> ok</name> <fsummary>Stop interpreting a module.</fsummary> <type> <v>AbsModule = Module | File</v> @@ -100,7 +100,7 @@ </func> <func> - <name>il() -> ok</name> + <name since="">il() -> ok</name> <fsummary>Make a printout of all interpreted modules</fsummary> <desc> <p>Makes a printout of all interpreted modules. @@ -110,7 +110,7 @@ </func> <func> - <name>ip() -> ok</name> + <name since="">ip() -> ok</name> <fsummary>Print the current status of all interpreted processes.</fsummary> <desc> @@ -119,7 +119,7 @@ </func> <func> - <name>ic() -> ok</name> + <name since="">ic() -> ok</name> <fsummary>Clear information about processes executing interpreted code.</fsummary> <desc> @@ -129,8 +129,8 @@ </func> <func> - <name>iaa(Flags) -> true</name> - <name>iaa(Flags, Function) -> true</name> + <name since="">iaa(Flags) -> true</name> + <name since="">iaa(Flags, Function) -> true</name> <fsummary>Set when and how to attach to a process.</fsummary> <type> <v>Flags = [init | break | exit]</v> @@ -148,7 +148,7 @@ </func> <func> - <name>ist(Flag) -> true</name> + <name since="">ist(Flag) -> true</name> <fsummary>Set how to save call frames.</fsummary> <type> <v>Flag = all | no_tail | false</v> @@ -160,7 +160,7 @@ </func> <func> - <name>ia(Pid) -> ok | no_proc</name> + <name since="">ia(Pid) -> ok | no_proc</name> <fsummary>Attache to a process.</fsummary> <type> <v>Pid = pid()</v> @@ -172,7 +172,7 @@ </func> <func> - <name>ia(X,Y,Z) -> ok | no_proc</name> + <name since="">ia(X,Y,Z) -> ok | no_proc</name> <fsummary>Attache to a process.</fsummary> <type> <v>X = Y = Z = int()</v> @@ -184,7 +184,7 @@ </func> <func> - <name>ia(Pid, Function) -> ok | no_proc</name> + <name since="">ia(Pid, Function) -> ok | no_proc</name> <fsummary>Attache to a process.</fsummary> <type> <v>Pid = pid()</v> @@ -199,7 +199,7 @@ </func> <func> - <name>ia(X,Y,Z, Function) -> ok | no_proc</name> + <name since="">ia(X,Y,Z, Function) -> ok | no_proc</name> <fsummary>Attache to a process.</fsummary> <type> <v>X = Y = Z = int()</v> @@ -217,7 +217,7 @@ </func> <func> - <name>ib(Module, Line) -> ok | {error, break_exists}</name> + <name since="">ib(Module, Line) -> ok | {error, break_exists}</name> <fsummary>Create a breakpoint.</fsummary> <type> <v>Module = atom()</v> @@ -229,7 +229,7 @@ </func> <func> - <name>ib(Module, Name, Arity) -> ok | {error, function_not_found} + <name since="">ib(Module, Name, Arity) -> ok | {error, function_not_found} </name> <fsummary>Create breakpoints in the specified function.</fsummary> <type> @@ -243,7 +243,7 @@ </func> <func> - <name>ir() -> ok</name> + <name since="">ir() -> ok</name> <fsummary>Delete all breakpoints.</fsummary> <desc> <p>Deletes all breakpoints.</p> @@ -251,7 +251,7 @@ </func> <func> - <name>ir(Module) -> ok</name> + <name since="">ir(Module) -> ok</name> <fsummary>Delete all breakpoints in a module.</fsummary> <type> <v>Module = atom()</v> @@ -262,7 +262,7 @@ </func> <func> - <name>ir(Module, Line) -> ok</name> + <name since="">ir(Module, Line) -> ok</name> <fsummary>Delete a breakpoint.</fsummary> <type> <v>Module = atom()</v> @@ -274,7 +274,7 @@ </func> <func> - <name>ir(Module, Name, Arity) -> ok | {error, function_not_found} + <name since="">ir(Module, Name, Arity) -> ok | {error, function_not_found} </name> <fsummary>Delete breakpoints from the specified function.</fsummary> <type> @@ -288,7 +288,7 @@ </func> <func> - <name>ibd(Module, Line) -> ok</name> + <name since="">ibd(Module, Line) -> ok</name> <fsummary>Make a breakpoint inactive.</fsummary> <type> <v>Module = atom()</v> @@ -300,7 +300,7 @@ </func> <func> - <name>ibe(Module, Line) -> ok</name> + <name since="">ibe(Module, Line) -> ok</name> <fsummary>Make a breakpoint active.</fsummary> <type> <v>Module = atom()</v> @@ -312,7 +312,7 @@ </func> <func> - <name>iba(Module, Line, Action) -> ok</name> + <name since="">iba(Module, Line, Action) -> ok</name> <fsummary>Set the trigger action of a breakpoint.</fsummary> <type> <v>Module = atom()</v> @@ -326,7 +326,7 @@ </func> <func> - <name>ibc(Module, Line, Function) -> ok</name> + <name since="">ibc(Module, Line, Function) -> ok</name> <fsummary>Set the conditional test of a breakpoint.</fsummary> <type> <v>Module = atom()</v> @@ -348,7 +348,7 @@ </func> <func> - <name>ipb() -> ok</name> + <name since="">ipb() -> ok</name> <fsummary>Print all existing breakpoints.</fsummary> <desc> <p>Prints all existing breakpoints.</p> @@ -356,7 +356,7 @@ </func> <func> - <name>ipb(Module) -> ok</name> + <name since="">ipb(Module) -> ok</name> <fsummary>Print all existing breakpoints in a module.</fsummary> <type> <v>Module = atom()</v> @@ -367,7 +367,7 @@ </func> <func> - <name>iv() -> atom()</name> + <name since="">iv() -> atom()</name> <fsummary>Return the current version number of the interpreter. </fsummary> <desc> @@ -377,7 +377,7 @@ </func> <func> - <name>help() -> ok</name> + <name since="">help() -> ok</name> <fsummary>Print help text.</fsummary> <desc> <p>Prints help text.</p> diff --git a/lib/debugger/doc/src/int.xml b/lib/debugger/doc/src/int.xml index 31e9dfe923..a0078714e6 100644 --- a/lib/debugger/doc/src/int.xml +++ b/lib/debugger/doc/src/int.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>int</module> + <module since="">int</module> <modulesummary>Interpreter Interface.</modulesummary> <description> <p>The Erlang interpreter provides mechanisms for breakpoints and @@ -94,10 +94,10 @@ <funcs> <func> - <name>i(AbsModule) -> {module,Module} | error</name> - <name>i(AbsModules) -> ok</name> - <name>ni(AbsModule) -> {module,Module} | error</name> - <name>ni(AbsModules) -> ok</name> + <name since="">i(AbsModule) -> {module,Module} | error</name> + <name since="">i(AbsModules) -> ok</name> + <name since="">ni(AbsModule) -> {module,Module} | error</name> + <name since="">ni(AbsModules) -> ok</name> <fsummary>Interpret a module.</fsummary> <type> <v>AbsModules = [AbsModule]</v> @@ -144,8 +144,8 @@ </func> <func> - <name>n(AbsModule) -> ok</name> - <name>nn(AbsModule) -> ok</name> + <name since="">n(AbsModule) -> ok</name> + <name since="">nn(AbsModule) -> ok</name> <fsummary>Stop interpreting a module.</fsummary> <type> <v>AbsModule = Module | File | [Module | File]</v> @@ -163,7 +163,7 @@ </func> <func> - <name>interpreted() -> [Module]</name> + <name since="">interpreted() -> [Module]</name> <fsummary>Get all interpreted modules.</fsummary> <type> <v>Module = atom()</v> @@ -174,7 +174,7 @@ </func> <func> - <name>file(Module) -> File | {error,not_loaded}</name> + <name since="">file(Module) -> File | {error,not_loaded}</name> <fsummary>Get the filename for an interpreted module.</fsummary> <type> <v>Module = atom()</v> @@ -187,7 +187,7 @@ </func> <func> - <name>interpretable(AbsModule) -> true | {error,Reason}</name> + <name since="">interpretable(AbsModule) -> true | {error,Reason}</name> <fsummary>Check if a module can be interpreted.</fsummary> <type> <v>AbsModule = Module | File</v> @@ -255,9 +255,9 @@ </func> <func> - <name>auto_attach() -> false | {Flags,Function}</name> - <name>auto_attach(false)</name> - <name>auto_attach(Flags, Function)</name> + <name since="">auto_attach() -> false | {Flags,Function}</name> + <name since="">auto_attach(false)</name> + <name since="">auto_attach(Flags, Function)</name> <fsummary>Get and set when and how to attach to a process.</fsummary> <type> <v>Flags = [init | break | exit]</v> @@ -290,8 +290,8 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>stack_trace() -> Flag</name> - <name>stack_trace(Flag)</name> + <name since="">stack_trace() -> Flag</name> + <name since="">stack_trace(Flag)</name> <fsummary>Get and set if and how to save call frames.</fsummary> <type> <v>Flag = all | no_tail | false</v> @@ -322,7 +322,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>break(Module, Line) -> ok | {error,break_exists}</name> + <name since="">break(Module, Line) -> ok | {error,break_exists}</name> <fsummary>Create a breakpoint.</fsummary> <type> <v>Module = atom()</v> @@ -334,7 +334,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>delete_break(Module, Line) -> ok</name> + <name since="">delete_break(Module, Line) -> ok</name> <fsummary>Delete a breakpoint.</fsummary> <type> <v>Module = atom()</v> @@ -346,7 +346,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>break_in(Module, Name, Arity) -> ok + <name since="">break_in(Module, Name, Arity) -> ok | {error,function_not_found}</name> <fsummary>Create breakpoints in the specified function.</fsummary> <type> @@ -360,7 +360,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>del_break_in(Module, Name, Arity) -> ok + <name since="">del_break_in(Module, Name, Arity) -> ok | {error,function_not_found}</name> <fsummary>Delete breakpoints from the specified function.</fsummary> <type> @@ -374,8 +374,8 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>no_break() -> ok</name> - <name>no_break(Module) -> ok</name> + <name since="">no_break() -> ok</name> + <name since="">no_break(Module) -> ok</name> <fsummary>Delete all breakpoints.</fsummary> <desc> <p>Deletes all breakpoints, or all breakpoints in <c>Module</c>.</p> @@ -383,7 +383,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>disable_break(Module, Line) -> ok</name> + <name since="">disable_break(Module, Line) -> ok</name> <fsummary>Make a breakpoint inactive.</fsummary> <type> <v>Module = atom()</v> @@ -395,7 +395,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>enable_break(Module, Line) -> ok</name> + <name since="">enable_break(Module, Line) -> ok</name> <fsummary>Make a breakpoint active.</fsummary> <type> <v>Module = atom()</v> @@ -407,7 +407,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>action_at_break(Module, Line, Action) -> ok</name> + <name since="">action_at_break(Module, Line, Action) -> ok</name> <fsummary>Set the trigger action of a breakpoint.</fsummary> <type> <v>Module = atom()</v> @@ -421,7 +421,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>test_at_break(Module, Line, Function) -> ok</name> + <name since="">test_at_break(Module, Line, Function) -> ok</name> <fsummary>Set the conditional test of a breakpoint.</fsummary> <type> <v>Module = atom()</v> @@ -438,7 +438,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>get_binding(Var, Bindings) -> {value,Value} | unbound</name> + <name since="">get_binding(Var, Bindings) -> {value,Value} | unbound</name> <fsummary>Retrieve a variable binding.</fsummary> <type> <v>Var = atom()</v> @@ -453,8 +453,8 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>all_breaks() -> [Break]</name> - <name>all_breaks(Module) -> [Break]</name> + <name since="">all_breaks() -> [Break]</name> + <name since="">all_breaks(Module) -> [Break]</name> <fsummary>Get all breakpoints.</fsummary> <type> <v>Break = {Point,Options}</v> @@ -474,7 +474,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>snapshot() -> [Snapshot]</name> + <name since="">snapshot() -> [Snapshot]</name> <fsummary>Get information about all processes executing interpreted code.</fsummary> <type> @@ -519,7 +519,7 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>clear() -> ok</name> + <name since="">clear() -> ok</name> <fsummary>Clear information about processes executing interpreted code.</fsummary> <desc> @@ -529,8 +529,8 @@ spawn(Module, Name, [Pid | Args])</pre> </func> <func> - <name>continue(Pid) -> ok | {error,not_interpreted}</name> - <name>continue(X,Y,Z) -> ok | {error,not_interpreted}</name> + <name since="">continue(Pid) -> ok | {error,not_interpreted}</name> + <name since="">continue(X,Y,Z) -> ok | {error,not_interpreted}</name> <fsummary>Resume process execution.</fsummary> <type> <v>Pid = pid()</v> diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml index e34ffd6def..f5e8337eb1 100644 --- a/lib/dialyzer/doc/src/dialyzer.xml +++ b/lib/dialyzer/doc/src/dialyzer.xml @@ -29,7 +29,7 @@ <rev></rev> <file>dialyzer.xml</file> </header> - <module>dialyzer</module> + <module since="">dialyzer</module> <modulesummary>Dialyzer, a DIscrepancy AnaLYZer for ERlang programs. </modulesummary> <description> @@ -472,7 +472,7 @@ dialyzer --plts plt_1 ... plt_n -- files_to_analyze</code> <funcs> <func> - <name>format_warning(Msg) -> string()</name> + <name since="">format_warning(Msg) -> string()</name> <fsummary>Get the string version of a warning message.</fsummary> <type> <v>Msg = {Tag, Id, msg()}</v> @@ -485,8 +485,8 @@ dialyzer --plts plt_1 ... plt_n -- files_to_analyze</code> </func> <func> - <name>gui() -> ok | {error, Msg}</name> - <name>gui(OptList) -> ok | {error, Msg}</name> + <name since="">gui() -> ok | {error, Msg}</name> + <name since="">gui(OptList) -> ok | {error, Msg}</name> <fsummary>Dialyzer GUI version.</fsummary> <type> <v>OptList</v> @@ -539,7 +539,7 @@ WarnOpts :: error_handling </func> <func> - <name>plt_info(string()) -> {'ok', [{atom(), any()}]} | {'error', atom()}</name> + <name since="">plt_info(string()) -> {'ok', [{atom(), any()}]} | {'error', atom()}</name> <fsummary>Return information about the specified PLT.</fsummary> <desc> <p>Returns information about the specified PLT.</p> @@ -547,7 +547,7 @@ WarnOpts :: error_handling </func> <func> - <name>run(OptList) -> Warnings</name> + <name since="">run(OptList) -> Warnings</name> <fsummary>Dialyzer command-line version.</fsummary> <type> <v>OptList</v> diff --git a/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl b/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl new file mode 100644 index 0000000000..d7cbc27a4d --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl @@ -0,0 +1,19 @@ +-module(lists_key_bug). + +%% OTP-15570 + +-export([t/1]). + +t(V) -> + K = key(V), + case lists:keyfind(K, 1, [{<<"foo">>, bar}]) of + false -> + a; + {_, _} -> + b + end. + +key(1) -> + 3; +key(2) -> + <<"foo">>. diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index dfa4c803ed..0a0194af2d 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -55,7 +55,7 @@ limitations under the License. <!-- ===================================================================== --> <!-- ===================================================================== --> -<module>diameter</module> +<module since="OTP R14B03">diameter</module> <modulesummary>Main API of the diameter application.</modulesummary> <description> @@ -1574,7 +1574,7 @@ identifies the configuration.</p> <!-- ===================================================================== --> <func> -<name>add_transport(SvcName, {connect|listen, [Opt]}) +<name since="OTP R14B03">add_transport(SvcName, {connect|listen, [Opt]}) -> {ok, Ref} | {error, Reason}</name> <fsummary>Add transport capability to a service.</fsummary> <type> @@ -1624,7 +1624,7 @@ its transports.</p> <!-- ===================================================================== --> <func> -<name>call(SvcName, App, Request, [Opt]) -> Answer | ok | {error, Reason}</name> +<name since="OTP R14B03">call(SvcName, App, Request, [Opt]) -> Answer | ok | {error, Reason}</name> <fsummary>Send a Diameter request message.</fsummary> <type> <v>SvcName = &service_name;</v> @@ -1730,7 +1730,7 @@ transport connection.</p> <!-- ===================================================================== --> <func> -<name>origin_state_id() -> &dict_Unsigned32;</name> +<name since="OTP R14B03">origin_state_id() -> &dict_Unsigned32;</name> <fsummary>Returns a reasonable Origin-State-Id.</fsummary> <desc> <p> @@ -1748,7 +1748,7 @@ at the time the diameter application was started.</p> <!-- ===================================================================== --> <func> -<name>remove_transport(SvcName, Pred) -> ok | {error, Reason}</name> +<name since="OTP R14B03">remove_transport(SvcName, Pred) -> ok | {error, Reason}</name> <fsummary>Remove previously added transports.</fsummary> <type> <v>SvcName = &service_name;</v> @@ -1795,7 +1795,7 @@ configured on the transport.</p> <!-- ===================================================================== --> <func> -<name>service_info(SvcName, Info) -> term()</name> +<name since="OTP R14B03">service_info(SvcName, Info) -> term()</name> <fsummary>Return information about a started service.</fsummary> <type> <v>SvcName = &service_name;</v> @@ -2114,7 +2114,7 @@ For example:</p> <!-- ===================================================================== --> <func> -<name>services() -> [SvcName]</name> +<name since="OTP R14B03">services() -> [SvcName]</name> <fsummary>Return the list of started services.</fsummary> <type> <v>SvcName = &service_name;</v> @@ -2129,7 +2129,7 @@ Return the list of started services.</p> <!-- ===================================================================== --> <func> -<name>session_id(Ident) -> &dict_OctetString;</name> +<name since="OTP R14B03">session_id(Ident) -> &dict_OctetString;</name> <fsummary>Return a value for a Session-Id AVP.</fsummary> <type> <v>Ident = &dict_DiameterIdentity;</v> @@ -2148,7 +2148,7 @@ the message containing the returned value will be sent.</p> <!-- ===================================================================== --> <func> -<name>start() -> ok | {error, Reason}</name> +<name since="OTP R14B03">start() -> ok | {error, Reason}</name> <fsummary>Start the diameter application.</fsummary> <desc> <p> @@ -2164,7 +2164,7 @@ file, not by calling <c>start/0</c> explicitly.</p> <!-- ===================================================================== --> <func> -<name>start_service(SvcName, Options) -> ok | {error, Reason}</name> +<name since="OTP R14B03">start_service(SvcName, Options) -> ok | {error, Reason}</name> <fsummary>Start a Diameter service.</fsummary> <type> <v>SvcName = &service_name;</v> @@ -2194,7 +2194,7 @@ necessarily the case.</p> <!-- ===================================================================== --> <func> -<name>stop() -> ok | {error, Reason}</name> +<name since="OTP R14B03">stop() -> ok | {error, Reason}</name> <fsummary>Stop the diameter application.</fsummary> <desc> <p> @@ -2208,7 +2208,7 @@ Stop the diameter application.</p> <!-- ===================================================================== --> <func> -<name>stop_service(SvcName) -> ok | {error, Reason}</name> +<name since="OTP R14B03">stop_service(SvcName) -> ok | {error, Reason}</name> <fsummary>Stop a Diameter service.</fsummary> <type> <v>SvcName = &service_name;</v> @@ -2236,7 +2236,7 @@ be called to remove transport configuration.</p> <!-- ===================================================================== --> <func> -<name>subscribe(SvcName) -> true</name> +<name since="OTP R14B03">subscribe(SvcName) -> true</name> <fsummary>Subscribe to event messages.</fsummary> <type> <v>SvcName = &service_name;</v> @@ -2258,7 +2258,7 @@ reception of all transport-related events.</p> <!-- ===================================================================== --> <func> -<name>unsubscribe(SvcName) -> true</name> +<name since="OTP R14B03">unsubscribe(SvcName) -> true</name> <fsummary>Unsubscribe to event messages.</fsummary> <type> <v>SvcName = &service_name;</v> diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml index aa334beb21..82e3d449ef 100644 --- a/lib/diameter/doc/src/diameter_app.xml +++ b/lib/diameter/doc/src/diameter_app.xml @@ -44,7 +44,7 @@ limitations under the License. </header> -<module>diameter_app</module> +<module since="OTP R14B03">diameter_app</module> <modulesummary> Callback module of a Diameter application.</modulesummary> @@ -180,7 +180,7 @@ process.</p> <funcs> <func> -<name>Mod:peer_up(SvcName, Peer, State) -> NewState</name> +<name since="OTP R14B03">Mod:peer_up(SvcName, Peer, State) -> NewState</name> <fsummary>Invoked when a transport connection has been established</fsummary> <type> <v>SvcName = &mod_service_name;</v> @@ -215,7 +215,7 @@ handled independently of &peer_up; and &peer_down;.</p> </func> <func> -<name>Mod:peer_down(SvcName, Peer, State) -> NewState</name> +<name since="OTP R14B03">Mod:peer_down(SvcName, Peer, State) -> NewState</name> <fsummary>Invoked when a transport connection has been lost.</fsummary> <type> <v>SvcName = &mod_service_name;</v> @@ -234,7 +234,7 @@ candidate in &pick_peer; callbacks.</p> </func> <func> -<name>Mod:pick_peer(LocalCandidates, RemoteCandidates, SvcName, State) +<name since="OTP R14B03">Mod:pick_peer(LocalCandidates, RemoteCandidates, SvcName, State) -> Selection | false</name> <fsummary>Select a target peer for an outgoing request.</fsummary> <type> @@ -311,7 +311,7 @@ or &peer_down; callback.</p> </func> <func> -<name>Mod:prepare_request(Packet, SvcName, Peer) -> Action</name> +<name since="OTP R14B03">Mod:prepare_request(Packet, SvcName, Peer) -> Action</name> <fsummary>Return a request for encoding and transport.</fsummary> <type> <v>Packet = &packet;</v> @@ -363,7 +363,7 @@ discarded}</c>.</p> </func> <func> -<name>Mod:prepare_retransmit(Packet, SvcName, Peer) -> Action</name> +<name since="OTP R14B03">Mod:prepare_retransmit(Packet, SvcName, Peer) -> Action</name> <fsummary>Return a request for encoding and retransmission.</fsummary> <type> <v>Packet = &packet;</v> @@ -393,7 +393,7 @@ discarded}</c>.</p> </func> <func> -<name>Mod:handle_answer(Packet, Request, SvcName, Peer) -> Result</name> +<name since="OTP R14B03">Mod:handle_answer(Packet, Request, SvcName, Peer) -> Result</name> <fsummary>Receive an answer message from a peer.</fsummary> <type> <v>Packet = &packet;</v> @@ -437,7 +437,7 @@ The &mod_application_opt; </func> <func> -<name>Mod:handle_error(Reason, Request, SvcName, Peer) -> Result</name> +<name since="OTP R14B03">Mod:handle_error(Reason, Request, SvcName, Peer) -> Result</name> <fsummary>Return an error from a outgoing request.</fsummary> <type> <v>Reason = timeout | failover | term()</v> @@ -465,7 +465,7 @@ not selected.</p> </func> <func> -<name>Mod:handle_request(Packet, SvcName, Peer) -> Action</name> +<name since="OTP R14B03">Mod:handle_request(Packet, SvcName, Peer) -> Action</name> <fsummary>Receive an incoming request.</fsummary> <type> <v>Packet = &packet;</v> diff --git a/lib/diameter/doc/src/diameter_codec.xml b/lib/diameter/doc/src/diameter_codec.xml index 0a34dd7ec7..0384ad2913 100644 --- a/lib/diameter/doc/src/diameter_codec.xml +++ b/lib/diameter/doc/src/diameter_codec.xml @@ -46,7 +46,7 @@ limitations under the License. <file>diameter_codec.xml</file> </header> -<module>diameter_codec</module> +<module since="OTP R15B03">diameter_codec</module> <modulesummary>Decode and encode of Diameter messages.</modulesummary> <description> @@ -346,7 +346,7 @@ question, as documented in &man_transport;.</p> <funcs> <func> -<name>decode(Mod, Bin) -> Pkt</name> +<name since="OTP R15B03">decode(Mod, Bin) -> Pkt</name> <fsummary>Decode a Diameter message.</fsummary> <type> <v>Mod = &dictionary;</v> @@ -362,7 +362,7 @@ Decode a Diameter message.</p> </func> <func> -<name>encode(Mod, Msg) -> Pkt</name> +<name since="OTP R15B03">encode(Mod, Msg) -> Pkt</name> <fsummary>Encode a Diameter message.</fsummary> <type> <v>Mod = &dictionary;</v> diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml index 112355816f..57e83bbca1 100644 --- a/lib/diameter/doc/src/diameter_make.xml +++ b/lib/diameter/doc/src/diameter_make.xml @@ -45,7 +45,7 @@ limitations under the License. <file>diameter_make.xml</file> </header> -<module>diameter_make</module> +<module since="OTP R14B03">diameter_make</module> <modulesummary>Diameter dictionary compilation.</modulesummary> <description> @@ -67,7 +67,7 @@ interface.</p> <funcs> <func> -<name>codec(File :: iolist() | binary(), [Opt]) -> ok +<name since="OTP R15B">codec(File :: iolist() | binary(), [Opt]) -> ok | {ok, [Out]} | {error, Reason}</name> <fsummary>Compile a dictionary file into Erlang source.</fsummary> @@ -186,7 +186,7 @@ A returned error reason can be converted into a readable string using <!-- ===================================================================== --> <func> -<name>format(Parsed) -> iolist()</name> +<name since="OTP R16B03">format(Parsed) -> iolist()</name> <fsummary>Format a parsed dictionary.</fsummary> <desc> <p> @@ -198,7 +198,7 @@ dictionary format.</p> <!-- ===================================================================== --> <func> -<name>flatten(Parsed) -> term()</name> +<name since="OTP R16B03">flatten(Parsed) -> term()</name> <fsummary>Flatten a parsed dictionary.</fsummary> <desc> @@ -214,7 +214,7 @@ The return value is also a parsed dictionary.</p> <!-- ===================================================================== --> <func> -<name>format_error(Reason) -> string()</name> +<name since="OTP 17.0">format_error(Reason) -> string()</name> <fsummary>Turn an error reason into a readable string.</fsummary> <desc> diff --git a/lib/diameter/doc/src/diameter_sctp.xml b/lib/diameter/doc/src/diameter_sctp.xml index 62e958870e..2cf924ee6b 100644 --- a/lib/diameter/doc/src/diameter_sctp.xml +++ b/lib/diameter/doc/src/diameter_sctp.xml @@ -47,7 +47,7 @@ limitations under the License. <file>diameter_sctp.xml</file> </header> -<module>diameter_sctp</module> +<module since="OTP R14B03">diameter_sctp</module> <modulesummary>Diameter transport over SCTP.</modulesummary> <description> @@ -67,7 +67,7 @@ and implements the behaviour documented in <funcs> <func> -<name>start({Type, Ref}, Svc, [Opt]) +<name since="OTP R14B03">start({Type, Ref}, Svc, [Opt]) -> {ok, Pid, [LAddr]} | {error, Reason}</name> <fsummary>Start a transport process.</fsummary> <type> diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml index 9f84eeb9fd..fe0cb2d067 100644 --- a/lib/diameter/doc/src/diameter_tcp.xml +++ b/lib/diameter/doc/src/diameter_tcp.xml @@ -57,7 +57,7 @@ limitations under the License. <file>diameter_tcp.xml</file> </header> -<module>diameter_tcp</module> +<module since="OTP R14B03">diameter_tcp</module> <modulesummary>Diameter transport over TCP.</modulesummary> <description> @@ -83,7 +83,7 @@ before configuring TLS capability on diameter transports.</p> <funcs> <func> -<name>start({Type, Ref}, Svc, [Opt]) +<name since="OTP R14B03">start({Type, Ref}, Svc, [Opt]) -> {ok, Pid} | {ok, Pid, [LAddr]} | {error, Reason}</name> diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml index 294e8a8864..67fd54bc56 100644 --- a/lib/diameter/doc/src/diameter_transport.xml +++ b/lib/diameter/doc/src/diameter_transport.xml @@ -43,7 +43,7 @@ limitations under the License. <file>diameter_transport.xml</file> </header> -<module>diameter_transport</module> +<module since="OTP R14B03">diameter_transport</module> <modulesummary>Diameter transport interface.</modulesummary> <description> @@ -94,7 +94,7 @@ and has the binary() to send in its <c>bin</c> field.</p> <funcs> <func> -<name>Mod:start({Type, Ref}, Svc, Config) +<name since="OTP R14B03">Mod:start({Type, Ref}, Svc, Config) -> {ok, Pid} | {ok, Pid, LAddrs} | {error, Reason}</name> diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml index 4bfc98de40..cc92bd99f0 100644 --- a/lib/diameter/doc/src/notes.xml +++ b/lib/diameter/doc/src/notes.xml @@ -78,6 +78,24 @@ first.</p> </section> +<section><title>diameter 2.1.4.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix failure of incoming answer message with faulty + Experimental-Result-Code. Failure to decode the AVP + resulted in an uncaught exception, with no no + handle_answer/error callback as a consequence.</p> + <p> + Own Id: OTP-15569 Aux Id: ERIERL-302 </p> + </item> + </list> + </section> + +</section> + <section><title>diameter 2.1.4</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index d110a3015e..564448de48 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2018. All Rights Reserved. +%% Copyright Ericsson AB 2010-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. diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index d2856ae530..2d3e4a2ac9 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -1925,6 +1925,8 @@ get_avp(Dict, Name, [#diameter_header{} | Avps]) -> A = find_avp(Code, Vid, Avps), avp_decode(Dict, Name, ungroup(A)) catch + {diameter_gen, _} -> %% faulty Grouped AVP + undefined; error: _ -> undefined end; diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src index 51830f5276..4e6b983bac 100644 --- a/lib/diameter/src/diameter.appup.src +++ b/lib/diameter/src/diameter.appup.src @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2018. All Rights Reserved. +%% Copyright Ericsson AB 2010-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. @@ -59,6 +59,7 @@ {"2.1.2", [{restart_application, diameter}]}, %% 20.1.3 {"2.1.3", [{restart_application, diameter}]}, %% 20.2 {"2.1.4", [{restart_application, diameter}]}, %% 20.3 + {"2.1.4.1", [{restart_application, diameter}]}, %% 20.3.8.19 {"2.1.5", [{update, diameter_peer_fsm}]} %% 21.0 ], [ @@ -100,6 +101,7 @@ {"2.1.2", [{restart_application, diameter}]}, {"2.1.3", [{restart_application, diameter}]}, {"2.1.4", [{restart_application, diameter}]}, + {"2.1.4.1", [{restart_application, diameter}]}, {"2.1.5", [{update, diameter_peer_fsm}]} ] }. diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml index f2c7889e58..790a2f4e26 100644 --- a/lib/eldap/doc/src/eldap.xml +++ b/lib/eldap/doc/src/eldap.xml @@ -28,7 +28,7 @@ <date>2000-06-20</date> <rev>B</rev> </header> - <module>eldap</module> + <module since="OTP R15B01">eldap</module> <modulesummary>LDAP Client</modulesummary> <description> <p>This module provides a client api to the Lightweight Directory Access Protocol (LDAP). @@ -103,7 +103,7 @@ <funcs> <func> - <name>open([Host]) -> {ok, Handle} | {error, Reason}</name> + <name since="OTP R15B01">open([Host]) -> {ok, Handle} | {error, Reason}</name> <fsummary>Open a connection to an LDAP server.</fsummary> <type> <v>Handle = handle()</v> @@ -113,7 +113,7 @@ </desc> </func> <func> - <name>open([Host], [Option]) -> {ok, Handle} | {error, Reason}</name> + <name since="OTP R15B01">open([Host], [Option]) -> {ok, Handle} | {error, Reason}</name> <fsummary>Open a connection to an LDAP server.</fsummary> <type> <v>Handle = handle()</v> @@ -129,7 +129,7 @@ </desc> </func> <func> - <name>close(Handle) -> ok</name> + <name since="OTP R15B01">close(Handle) -> ok</name> <fsummary>Shutdown the connection.</fsummary> <type> <v>Handle = handle()</v> @@ -140,14 +140,14 @@ </desc> </func> <func> - <name>start_tls(Handle, Options) -> return_value()</name> + <name since="OTP R16B03">start_tls(Handle, Options) -> return_value()</name> <fsummary>Upgrade a connection to TLS.</fsummary> <desc> <p>Same as start_tls(Handle, Options, infinity)</p> </desc> </func> <func> - <name>start_tls(Handle, Options, Timeout) -> return_value()</name> + <name since="OTP R16B03">start_tls(Handle, Options, Timeout) -> return_value()</name> <fsummary>Upgrade a connection to TLS.</fsummary> <type> <v>Handle = handle()</v> @@ -176,7 +176,7 @@ </desc> </func> <func> - <name>simple_bind(Handle, Dn, Password) -> return_value()</name> + <name since="OTP R15B01">simple_bind(Handle, Dn, Password) -> return_value()</name> <fsummary>Authenticate the connection.</fsummary> <type> <v>Handle = handle()</v> @@ -188,7 +188,7 @@ </desc> </func> <func> - <name>add(Handle, Dn, [Attribute]) -> return_value()</name> + <name since="OTP R15B01">add(Handle, Dn, [Attribute]) -> return_value()</name> <fsummary>Add an entry.</fsummary> <type> <v>Handle = handle()</v> @@ -209,7 +209,7 @@ </desc> </func> <func> - <name>delete(Handle, Dn) -> return_value()</name> + <name since="OTP R15B01">delete(Handle, Dn) -> return_value()</name> <fsummary>Delete an entry.</fsummary> <type> <v>Dn = string()</v> @@ -223,7 +223,7 @@ </func> <func> - <name>mod_add(Type, [Value]) -> modify_op()</name> + <name since="OTP R15B01">mod_add(Type, [Value]) -> modify_op()</name> <fsummary>Create a modification operation.</fsummary> <type> <v>Type = string()</v> @@ -232,7 +232,7 @@ <desc> <p> Create an add modification operation.</p> </desc> </func> <func> - <name>mod_delete(Type, [Value]) -> modify_op()</name> + <name since="OTP R15B01">mod_delete(Type, [Value]) -> modify_op()</name> <fsummary>Create a modification operation.</fsummary> <type> <v>Type = string()</v> @@ -241,7 +241,7 @@ <desc> <p> Create a delete modification operation.</p> </desc> </func> <func> - <name>mod_replace(Type, [Value]) -> modify_op()</name> + <name since="OTP R15B01">mod_replace(Type, [Value]) -> modify_op()</name> <fsummary>Create a modification operation.</fsummary> <type> <v>Type = string()</v> @@ -251,7 +251,7 @@ </func> <func> - <name>modify(Handle, Dn, [ModifyOp]) -> return_value()</name> + <name since="OTP R15B01">modify(Handle, Dn, [ModifyOp]) -> return_value()</name> <fsummary>Modify an entry.</fsummary> <type> <v>Dn = string()</v> @@ -267,7 +267,7 @@ </desc> </func> <func> - <name>modify_password(Handle, Dn, NewPasswd) -> return_value() | {ok, GenPasswd}</name> + <name since="OTP 18.0">modify_password(Handle, Dn, NewPasswd) -> return_value() | {ok, GenPasswd}</name> <fsummary>Modify the password of a user.</fsummary> <type> <v>Dn = string()</v> @@ -278,7 +278,7 @@ </desc> </func> <func> - <name>modify_password(Handle, Dn, NewPasswd, OldPasswd) -> return_value() | {ok, GenPasswd}</name> + <name since="OTP 18.0">modify_password(Handle, Dn, NewPasswd, OldPasswd) -> return_value() | {ok, GenPasswd}</name> <fsummary>Modify the password of a user.</fsummary> <type> <v>Dn = string()</v> @@ -307,7 +307,7 @@ </desc> </func> <func> - <name>modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> return_value()</name> + <name since="OTP R15B01">modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> return_value()</name> <fsummary>Modify the DN of an entry.</fsummary> <type> <v>Dn = string()</v> @@ -327,7 +327,7 @@ </desc> </func> <func> - <name>search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {ok, {referral,referrals()}} | {error, Reason}</name> + <name since="OTP R15B01">search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {ok, {referral,referrals()}} | {error, Reason}</name> <fsummary>Search the Directory</fsummary> <type> <v>SearchOptions = #eldap_search{} | [SearchOption]</v> @@ -354,44 +354,44 @@ </func> <func> - <name>baseObject() -> scope()</name> + <name since="OTP R15B01">baseObject() -> scope()</name> <fsummary>Create search scope.</fsummary> <desc> <p> Search baseobject only.</p> </desc> </func> <func> - <name>singleLevel() -> scope()</name> + <name since="OTP R15B01">singleLevel() -> scope()</name> <fsummary>Create search scope.</fsummary> <desc> <p> Search the specified level only, i.e. do not recurse.</p> </desc> </func> <func> - <name>wholeSubtree() -> scope()</name> + <name since="OTP R15B01">wholeSubtree() -> scope()</name> <fsummary>Create search scope.</fsummary> <desc> <p> Search the entire subtree.</p> </desc> </func> <func> - <name>neverDerefAliases() -> dereference()</name> + <name since="OTP R15B01">neverDerefAliases() -> dereference()</name> <fsummary>Create search option.</fsummary> <desc> <p>Never derefrence aliases, treat aliases as entries.</p> </desc> </func> <func> - <name>derefAlways() -> dereference()</name> + <name since="OTP R15B01">derefAlways() -> dereference()</name> <fsummary>Create search option.</fsummary> <desc> <p>Always derefrence aliases.</p> </desc> </func> <func> - <name>derefInSearching() -> dereference()</name> + <name since="OTP R15B01">derefInSearching() -> dereference()</name> <fsummary>Create search option.</fsummary> <desc> <p>Derefrence aliases only when searching.</p> </desc> </func> <func> - <name>derefFindingBaseObj() -> dereference()</name> + <name since="OTP R15B01">derefFindingBaseObj() -> dereference()</name> <fsummary>Create search option.</fsummary> <desc> <p>Derefrence aliases only in finding the base.</p> </desc> </func> <func> - <name>present(Type) -> filter()</name> + <name since="OTP R15B01">present(Type) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>Type = string()</v> @@ -399,7 +399,7 @@ <desc> <p>Create a filter which filters on attribute type presence.</p> </desc> </func> <func> - <name>substrings(Type, [SubString]) -> filter()</name> + <name since="OTP R15B01">substrings(Type, [SubString]) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>Type = string()</v> @@ -409,7 +409,7 @@ <desc> <p>Create a filter which filters on substrings.</p> </desc> </func> <func> - <name>equalityMatch(Type, Value) -> filter()</name> + <name since="OTP R15B01">equalityMatch(Type, Value) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>Type = string()</v> @@ -418,7 +418,7 @@ <desc> <p>Create a equality filter.</p> </desc> </func> <func> - <name>greaterOrEqual(Type, Value) -> filter()</name> + <name since="OTP R15B01">greaterOrEqual(Type, Value) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>Type = string()</v> @@ -427,7 +427,7 @@ <desc> <p>Create a greater or equal filter.</p> </desc> </func> <func> - <name>lessOrEqual(Type, Value) -> filter()</name> + <name since="OTP R15B01">lessOrEqual(Type, Value) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>Type = string()</v> @@ -436,7 +436,7 @@ <desc> <p>Create a less or equal filter.</p> </desc> </func> <func> - <name>approxMatch(Type, Value) -> filter()</name> + <name since="OTP R15B01">approxMatch(Type, Value) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>Type = string()</v> @@ -445,7 +445,7 @@ <desc> <p>Create a approximation match filter.</p> </desc> </func> <func> - <name>extensibleMatch(MatchValue, OptionalAttrs) -> filter()</name> + <name since="OTP 17.4">extensibleMatch(MatchValue, OptionalAttrs) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>MatchValue = string()</v> @@ -459,7 +459,7 @@ <p>creates a filter which performs a <c>caseExactMatch</c> on the attribute <c>sn</c> and matches with the value <c>"Bar"</c>. The default value of <c>dnAttributes</c> is <c>false</c>.</p> </desc> </func> <func> - <name>'and'([Filter]) -> filter()</name> + <name since="OTP R15B01">'and'([Filter]) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>Filter = filter()</v> @@ -467,7 +467,7 @@ <desc> <p>Creates a filter where all <c>Filter</c> must be true.</p> </desc> </func> <func> - <name>'or'([Filter]) -> filter()</name> + <name since="OTP R15B01">'or'([Filter]) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>Filter = filter()</v> @@ -475,7 +475,7 @@ <desc> <p>Create a filter where at least one of the <c>Filter</c> must be true.</p> </desc> </func> <func> - <name>'not'(Filter) -> filter()</name> + <name since="OTP R15B01">'not'(Filter) -> filter()</name> <fsummary>Create search filter option.</fsummary> <type> <v>Filter = filter()</v> diff --git a/lib/erl_docgen/doc/src/docgen_xml_check.xml b/lib/erl_docgen/doc/src/docgen_xml_check.xml index 68253edef7..8d6dceef43 100644 --- a/lib/erl_docgen/doc/src/docgen_xml_check.xml +++ b/lib/erl_docgen/doc/src/docgen_xml_check.xml @@ -30,7 +30,7 @@ <date></date> <rev></rev> </header> - <module>docgen_xml_check</module> + <module since="OTP R15B">docgen_xml_check</module> <modulesummary>Validate XML documentation source code</modulesummary> <description> <p><c>docgen_xml_check</c> contains functions for validating XML @@ -39,7 +39,7 @@ <funcs> <func> - <name>validate(File) -> ok | error | {error, badfile}</name> + <name since="OTP R15B">validate(File) -> ok | error | {error, badfile}</name> <fsummary>Validate XML source code.</fsummary> <type> <v>File = string()</v> diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css index 34c6befb0e..89b278215c 100644 --- a/lib/erl_docgen/priv/css/otp_doc.css +++ b/lib/erl_docgen/priv/css/otp_doc.css @@ -71,6 +71,33 @@ a:visited { color: #1b6ec2; text-decoration: none } } .bold_code { font-family: mono, Courier, monospace; font-weight: bold } + +/* Invisible table for function specs, + * just to get since-version out in right margin */ +.func-table, .func-tr, .func-td, .func-since-td { + width: 200%; + border: 0; + padding: 0; + margin: 0; +} + +.func-tr:nth-child(n) { + background: inherit /* turn off zebra striped rows */ +} + +.func-td { + width: 50% +} + +.func-since-td { + width: 50%; + padding-left: 1em +} + +.func-td:hover { + background-color: #f5f5f5; +} + .code { font-family: mono, Courier, monospace; font-weight: normal; @@ -283,3 +310,9 @@ a > .code { .func-types-title{ font-size: 1em; } + +.since{ + color: gray; + font-weight: normal; + font-size: small; +}
\ No newline at end of file diff --git a/lib/erl_docgen/priv/dtd/cref.dtd b/lib/erl_docgen/priv/dtd/cref.dtd index 5ccd98ed89..d392081807 100644 --- a/lib/erl_docgen/priv/dtd/cref.dtd +++ b/lib/erl_docgen/priv/dtd/cref.dtd @@ -30,6 +30,8 @@ <!-- `name' is used in common.refs.dtd and must therefore be defined in each *ref. dtd --> <!ELEMENT name (ret,nametext) > +<!ATTLIST name since CDATA #IMPLIED> + <!ELEMENT ret (#PCDATA) > <!ELEMENT nametext (#PCDATA) > diff --git a/lib/erl_docgen/priv/dtd/erlref.dtd b/lib/erl_docgen/priv/dtd/erlref.dtd index 78d6771f52..8202ea5a4d 100644 --- a/lib/erl_docgen/priv/dtd/erlref.dtd +++ b/lib/erl_docgen/priv/dtd/erlref.dtd @@ -25,6 +25,7 @@ <!ELEMENT erlref (header,module,modulesummary,description, (section|funcs|datatypes)*,authors?) > <!ELEMENT module (#PCDATA) > +<!ATTLIST module since CDATA #IMPLIED> <!ELEMENT modulesummary (#PCDATA) > <!-- `name' is used in common.refs.dtd and must therefore @@ -34,4 +35,5 @@ arity CDATA #IMPLIED clause_i CDATA #IMPLIED anchor CDATA #IMPLIED + since CDATA #IMPLIED n_vars CDATA #IMPLIED> diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index a0a922216b..c5150d447c 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -191,6 +191,7 @@ <xsl:variable name="name" select="@name"/> <xsl:variable name="arity" select="@arity"/> <xsl:variable name="anchor" select="@anchor"/> + <xsl:variable name="since" select="@since"/> <xsl:variable name="spec0"> <xsl:call-template name="find_spec"/> </xsl:variable> @@ -225,11 +226,12 @@ <xsl:variable name="global_types" select="ancestor::erlref/datatypes"/> <xsl:variable name="local_types" select="../type[string-length(@name) > 0]"/> - <xsl:apply-templates select="$spec/contract/clause/head"> + <xsl:apply-templates select="$spec/contract/clause/head"> <xsl:with-param name="ghlink" select="ancestor-or-self::*[@ghlink]/@ghlink"/> <xsl:with-param name="local_types" select="$local_types"/> <xsl:with-param name="global_types" select="$global_types"/> - </xsl:apply-templates> + <xsl:with-param name="since" select="$since"/> + </xsl:apply-templates> </xsl:when> </xsl:choose> </xsl:template> @@ -238,19 +240,32 @@ <xsl:param name="ghlink"/> <xsl:param name="local_types"/> <xsl:param name="global_types"/> + <xsl:param name="since"/> <xsl:variable name="id" select="concat(concat(concat(concat(../../../name,'-'),../../../arity),'-'),generate-id(.))"/> - <div class="bold_code func-head" - onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';" - onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';"> - <xsl:call-template name="ghlink"> - <xsl:with-param name="ghlink" select="$ghlink"/> - <xsl:with-param name="id" select="$id"/> - </xsl:call-template> - <xsl:apply-templates mode="local_type"> - <xsl:with-param name="local_types" select="$local_types"/> - <xsl:with-param name="global_types" select="$global_types"/> - </xsl:apply-templates> - </div> + <table class="func-table"> + <tr class="func-tr"> + <td class="func-td"> + <div class="bold_code func-head" + onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';" + onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';"> + <xsl:call-template name="ghlink"> + <xsl:with-param name="ghlink" select="$ghlink"/> + <xsl:with-param name="id" select="$id"/> + </xsl:call-template> + <xsl:apply-templates mode="local_type"> + <xsl:with-param name="local_types" select="$local_types"/> + <xsl:with-param name="global_types" select="$global_types"/> + </xsl:apply-templates> + </div> + </td> + <td class="func-since-td"> + <xsl:if test="string-length($since) > 0"> + <span class="since"><xsl:value-of select="$since"/> + </span> + </xsl:if> + </td> + </tr> + </table> </xsl:template> <!-- The *last* <name name="..." arity=".."/> --> @@ -1884,6 +1899,16 @@ <xsl:with-param name="partnum" select="$partnum"/> </xsl:apply-templates> </div> + <!-- Since --> + <xsl:if test="string-length(../module/@since) > 0"> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Since</xsl:with-param> + </xsl:call-template> + <div class="REFBODY module-since"> + Module <xsl:value-of select="../module"/> was introduced in + <xsl:value-of select="../module/@since"/>. + </div> + </xsl:if> </xsl:template> <!-- Lib --> @@ -2030,11 +2055,10 @@ <xsl:template match="func"> <xsl:param name="partnum"/> - <p><xsl:apply-templates select="name"/> - <xsl:apply-templates - select="name[string-length(@arity) > 0 and position()=last()]" - mode="types"/> - </p> + <xsl:apply-templates select="name"/> + <xsl:apply-templates + select="name[string-length(@arity) > 0 and position()=last()]" + mode="types"/> <xsl:apply-templates select="fsummary|type|desc"> <xsl:with-param name="partnum" select="$partnum"/> @@ -2093,19 +2117,29 @@ <xsl:choose> <xsl:when test="ancestor::cref"> - <span class="bold_code bc-7"> - <xsl:call-template name="title_link"> - <xsl:with-param name="link" select="substring-before(nametext, '(')"/> - <xsl:with-param name="title"> - <xsl:value-of select="ret"/> - <xsl:call-template name="maybe-space-after-ret"> - <xsl:with-param name="s" select="ret"/> - </xsl:call-template> - <xsl:value-of select="nametext"/> - </xsl:with-param> - </xsl:call-template> - </span> - <br/> + <table class="func-table"> + <tr class="func-tr"> + <td class="func-td"> + <span class="bold_code bc-7"> + <xsl:call-template name="title_link"> + <xsl:with-param name="link" select="substring-before(nametext, '(')"/> + <xsl:with-param name="title"> + <xsl:value-of select="ret"/> + <xsl:call-template name="maybe-space-after-ret"> + <xsl:with-param name="s" select="ret"/> + </xsl:call-template> + <xsl:value-of select="nametext"/> + </xsl:with-param> + </xsl:call-template> + </span> + </td> + <td class="func-since-td"> + <xsl:if test="string-length(@since) > 0"> + <span class="since"><xsl:value-of select="@since"/></span> + </xsl:if> + </td> + </tr> + </table> </xsl:when> <xsl:when test="ancestor::erlref"> <xsl:variable name="fname"> @@ -2136,14 +2170,25 @@ </div> </xsl:when> <xsl:otherwise> - <div class="bold_code fun-type"> - <xsl:call-template name="title_link"> - <xsl:with-param name="link" select="concat(concat($fname,'-'),$arity)"/> - <xsl:with-param name="title"> - <xsl:apply-templates/> - </xsl:with-param> - </xsl:call-template> - </div> + <table class="func-table"> + <tr class="func-tr"> + <td class="func-td"> + <div class="bold_code fun-type"> + <xsl:call-template name="title_link"> + <xsl:with-param name="link" select="concat(concat($fname,'-'),$arity)"/> + <xsl:with-param name="title"> + <xsl:apply-templates/> + </xsl:with-param> + </xsl:call-template> + </div> + </td> + <td class="func-since-td"> + <xsl:if test="string-length(@since) > 0"> + <span class="since"><xsl:value-of select="@since"/></span> + </xsl:if> + </td> + </tr> + </table> </xsl:otherwise> </xsl:choose> </xsl:when> diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in index a155ceef7e..747750c1fb 100644 --- a/lib/erl_interface/configure.in +++ b/lib/erl_interface/configure.in @@ -82,6 +82,15 @@ AC_ARG_ENABLE(threads, esac ], [ threads_disabled=maybe ]) +AC_ARG_ENABLE(mask-real-errno, +[ --disable-mask-real-errno do not mask real 'errno'], +[ case "$enableval" in + no) mask_real_errno=no ;; + *) mask_real_errno=yes ;; + esac ], +[ mask_real_errno=yes ]) + + dnl ---------------------------------------------------------------------- dnl Checks for programs dnl ---------------------------------------------------------------------- @@ -100,6 +109,10 @@ AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(void *) AC_CHECK_SIZEOF(long long) +if test $mask_real_errno = yes; then + AC_DEFINE(EI_HIDE_REAL_ERRNO, 1, [Define if 'errno' should not be exposed as is in 'erl_errno']) +fi + dnl We set EI_64BIT mode when long is 8 bytes, this makes things dnl work on windows and unix correctly if test $ac_cv_sizeof_long = 8; then @@ -158,7 +171,7 @@ AC_CHECK_LIB([socket], [getpeername]) # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/param.h sys/socket.h sys/select.h sys/time.h unistd.h sys/types.h]) +AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/param.h sys/socket.h sys/select.h sys/time.h unistd.h sys/types.h sys/uio.h]) # Checks for typedefs, structures, and compiler characteristics. # fixme AC_C_CONST & AC_C_VOLATILE needed for Windows? @@ -193,7 +206,7 @@ AC_CHECK_FUNCS([dup2 gethostbyaddr gethostbyname \ gethostbyaddr_r \ gethostbyname_r gethostname writev \ gethrtime gettimeofday inet_ntoa memchr memmove memset select \ - socket strchr strerror strrchr strstr uname]) + socket strchr strerror strrchr strstr uname sysconf]) AC_CHECK_FUNC(res_gethostbyname, [], AC_CHECK_LIB(resolv, res_gethostbyname) ) @@ -255,6 +268,7 @@ AC_SUBST(EI_THREADS) case "$threads_disabled" in no|maybe) LM_CHECK_THR_LIB + ETHR_CHK_GCC_ATOMIC_OPS([]) case "$THR_LIB_NAME" in "") @@ -268,7 +282,7 @@ case "$threads_disabled" in EI_THREADS="true" THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600" ;; - pthread) + pthread) EI_THREADS="true" ;; *) diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml index 9502fb1ee7..ae322255ad 100644 --- a/lib/erl_interface/doc/src/ei.xml +++ b/lib/erl_interface/doc/src/ei.xml @@ -124,7 +124,7 @@ typedef enum { <funcs> <func> - <name><ret>int</ret><nametext>ei_decode_atom(const char *buf, int *index, char *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_atom(const char *buf, int *index, char *p)</nametext></name> <fsummary>Decode an atom.</fsummary> <desc> <p>Decodes an atom from the binary format. The <c>NULL</c>-terminated @@ -134,7 +134,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_atom_as(const char *buf, int *index, char *p, int plen, erlang_char_encoding want, erlang_char_encoding* was, erlang_char_encoding* result)</nametext></name> + <name since="OTP R16B"><ret>int</ret><nametext>ei_decode_atom_as(const char *buf, int *index, char *p, int plen, erlang_char_encoding want, erlang_char_encoding* was, erlang_char_encoding* result)</nametext></name> <fsummary>Decode an atom.</fsummary> <desc> <p>Decodes an atom from the binary format. The <c>NULL</c>-terminated @@ -158,7 +158,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_bignum(const char *buf, int *index, mpz_t obj)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_bignum(const char *buf, int *index, mpz_t obj)</nametext></name> <fsummary>Decode a GMP arbitrary precision integer.</fsummary> <desc> <p>Decodes an integer in the binary format to a GMP @@ -168,7 +168,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_binary(const char *buf, int *index, void *p, long *len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_binary(const char *buf, int *index, void *p, long *len)</nametext></name> <fsummary>Decode a binary.</fsummary> <desc> <p>Decodes a binary from the binary format. Parameter @@ -180,7 +180,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_boolean(const char *buf, int *index, int *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_boolean(const char *buf, int *index, int *p)</nametext></name> <fsummary>Decode a boolean.</fsummary> <desc> <p>Decodes a boolean value from the binary format. @@ -190,7 +190,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_char(const char *buf, int *index, char *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_char(const char *buf, int *index, char *p)</nametext></name> <fsummary>Decode an 8-bit integer between 0-255.</fsummary> <desc> <p>Decodes a char (8-bit) integer between 0-255 from the binary format. @@ -203,7 +203,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_double(const char *buf, int *index, double *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_double(const char *buf, int *index, double *p)</nametext></name> <fsummary>Decode a double.</fsummary> <desc> <p>Decodes a double-precision (64-bit) floating @@ -212,7 +212,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_ei_term(const char* buf, int* index, ei_term* term)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_ei_term(const char* buf, int* index, ei_term* term)</nametext></name> <fsummary>Decode a term, without previous knowledge of type.</fsummary> <desc> <p>Decodes any term, or at least tries to. If the term @@ -233,8 +233,8 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_fun(const char *buf, int *index, erlang_fun *p)</nametext></name> - <name><ret>void</ret><nametext>free_fun(erlang_fun* f)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_fun(const char *buf, int *index, erlang_fun *p)</nametext></name> + <name since=""><ret>void</ret><nametext>free_fun(erlang_fun* f)</nametext></name> <fsummary>Decode a fun.</fsummary> <desc> <p>Decodes a fun from the binary format. Parameter @@ -248,7 +248,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_list_header(const char *buf, int *index, int *arity)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_list_header(const char *buf, int *index, int *arity)</nametext></name> <fsummary>Decode a list.</fsummary> <desc> <p>Decodes a list header from the binary @@ -265,7 +265,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_long(const char *buf, int *index, long *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_long(const char *buf, int *index, long *p)</nametext></name> <fsummary>Decode integer.</fsummary> <desc> <p>Decodes a long integer from the binary format. @@ -275,7 +275,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_longlong(const char *buf, int *index, long long *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_longlong(const char *buf, int *index, long long *p)</nametext></name> <fsummary>Decode integer.</fsummary> <desc> <p>Decodes a GCC <c>long long</c> or Visual C++ @@ -286,7 +286,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_map_header(const char *buf, int *index, int *arity)</nametext></name> + <name since="OTP 17.0"><ret>int</ret><nametext>ei_decode_map_header(const char *buf, int *index, int *arity)</nametext></name> <fsummary>Decode a map.</fsummary> <desc> <p>Decodes a map header from the binary @@ -299,7 +299,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_pid(const char *buf, int *index, erlang_pid *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_pid(const char *buf, int *index, erlang_pid *p)</nametext></name> <fsummary>Decode a <c>pid</c>.</fsummary> <desc> <p>Decodes a process identifier (pid) from the binary format.</p> @@ -307,7 +307,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_port(const char *buf, int *index, erlang_port *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_port(const char *buf, int *index, erlang_port *p)</nametext></name> <fsummary>Decode a port.</fsummary> <desc> <p>Decodes a port identifier from the binary format.</p> @@ -315,7 +315,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_ref(const char *buf, int *index, erlang_ref *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_ref(const char *buf, int *index, erlang_ref *p)</nametext></name> <fsummary>Decode a reference.</fsummary> <desc> <p>Decodes a reference from the binary format.</p> @@ -323,7 +323,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_string(const char *buf, int *index, char *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_string(const char *buf, int *index, char *p)</nametext></name> <fsummary>Decode a string.</fsummary> <desc> <p>Decodes a string from the binary format. A @@ -338,7 +338,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_term(const char *buf, int *index, void *t)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_term(const char *buf, int *index, void *t)</nametext></name> <fsummary>Decode a <c>ETERM</c>.</fsummary> <desc> <p>Decodes a term from the binary format. The term @@ -352,7 +352,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_trace(const char *buf, int *index, erlang_trace *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_trace(const char *buf, int *index, erlang_trace *p)</nametext></name> <fsummary>Decode a trace token.</fsummary> <desc> <p>Decodes an Erlang trace token from the binary format.</p> @@ -360,7 +360,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_tuple_header(const char *buf, int *index, int *arity)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_tuple_header(const char *buf, int *index, int *arity)</nametext></name> <fsummary>Decode a tuple.</fsummary> <desc> <p>Decodes a tuple header, the number of elements @@ -370,7 +370,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_ulong(const char *buf, int *index, unsigned long *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_ulong(const char *buf, int *index, unsigned long *p)</nametext></name> <fsummary>Decode unsigned integer.</fsummary> <desc> <p>Decodes an unsigned long integer from the binary format. @@ -380,7 +380,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)</nametext></name> <fsummary>Decode unsigned integer.</fsummary> <desc> <p>Decodes a GCC <c>unsigned long long</c> or Visual C++ @@ -390,7 +390,7 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_decode_version(const char *buf, int *index, int *version)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_decode_version(const char *buf, int *index, int *version)</nametext></name> <fsummary>Decode an empty list (<c>nil</c>).</fsummary> <desc> <p>Decodes the version magic number for the @@ -400,10 +400,10 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_atom(char *buf, int *index, const char *p)</nametext></name> - <name><ret>int</ret><nametext>ei_encode_atom_len(char *buf, int *index, const char *p, int len)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_atom(ei_x_buff* x, const char *p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_atom_len(ei_x_buff* x, const char *p, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_atom(char *buf, int *index, const char *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_atom_len(char *buf, int *index, const char *p, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_atom(ei_x_buff* x, const char *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_atom_len(ei_x_buff* x, const char *p, int len)</nametext></name> <fsummary>Encode an atom.</fsummary> <desc> <p>Encodes an atom in the binary format. Parameter <c>p</c> @@ -415,10 +415,10 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_atom_as(char *buf, int *index, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name> - <name><ret>int</ret><nametext>ei_encode_atom_len_as(char *buf, int *index, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_atom_as(ei_x_buff* x, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_atom_len_as(ei_x_buff* x, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name> + <name since="OTP R16B"><ret>int</ret><nametext>ei_encode_atom_as(char *buf, int *index, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name> + <name since="OTP R16B"><ret>int</ret><nametext>ei_encode_atom_len_as(char *buf, int *index, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name> + <name since="OTP R16B"><ret>int</ret><nametext>ei_x_encode_atom_as(ei_x_buff* x, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name> + <name since="OTP R16B"><ret>int</ret><nametext>ei_x_encode_atom_len_as(ei_x_buff* x, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name> <fsummary>Encode an atom.</fsummary> <desc> <p>Encodes an atom in the binary format. Parameter <c>p</c> is the name of the atom with @@ -435,8 +435,8 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_bignum(char *buf, int *index, mpz_t obj)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_bignum(char *buf, int *index, mpz_t obj)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)</nametext></name> <fsummary>Encode an arbitrary precision integer.</fsummary> <desc> <p>Encodes a GMP <c>mpz_t</c> integer to binary format. @@ -446,8 +446,8 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_binary(char *buf, int *index, const void *p, long len)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_binary(ei_x_buff* x, const void *p, long len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_binary(char *buf, int *index, const void *p, long len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_binary(ei_x_buff* x, const void *p, long len)</nametext></name> <fsummary>Encode a binary.</fsummary> <desc> <p>Encodes a binary in the binary format. The data is at @@ -456,8 +456,8 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_boolean(char *buf, int *index, int p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_boolean(ei_x_buff* x, int p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_boolean(char *buf, int *index, int p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_boolean(ei_x_buff* x, int p)</nametext></name> <fsummary>Encode a boolean.</fsummary> <desc> <p>Encodes a boolean value as the atom <c>true</c> if @@ -467,8 +467,8 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_char(char *buf, int *index, char p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_char(ei_x_buff* x, char p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_char(char *buf, int *index, char p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_char(ei_x_buff* x, char p)</nametext></name> <fsummary>Encode an 8-bit integer between 0-255.</fsummary> <desc> <p>Encodes a char (8-bit) as an integer between 0-255 in the binary @@ -481,8 +481,8 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_double(char *buf, int *index, double p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_double(ei_x_buff* x, double p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_double(char *buf, int *index, double p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_double(ei_x_buff* x, double p)</nametext></name> <fsummary>Encode a double float.</fsummary> <desc> <p>Encodes a double-precision (64-bit) floating point number in @@ -493,8 +493,8 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_empty_list(char* buf, int* index)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_empty_list(ei_x_buff* x)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_empty_list(char* buf, int* index)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_empty_list(ei_x_buff* x)</nametext></name> <fsummary>Encode an empty list (<c>nil</c>).</fsummary> <desc> <p>Encodes an empty list. It is often used at the tail of a list.</p> @@ -502,8 +502,8 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_fun(char *buf, int *index, const erlang_fun *p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_fun(char *buf, int *index, const erlang_fun *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)</nametext></name> <fsummary>Encode a fun.</fsummary> <desc> <p>Encodes a fun in the binary format. Parameter <c>p</c> @@ -515,8 +515,8 @@ typedef enum { </func> <func> - <name><ret>int</ret><nametext>ei_encode_list_header(char *buf, int *index, int arity)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_list_header(ei_x_buff* x, int arity)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_list_header(char *buf, int *index, int arity)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_list_header(ei_x_buff* x, int arity)</nametext></name> <fsummary>Encode a list.</fsummary> <desc> <p>Encodes a list header, with a specified @@ -552,8 +552,8 @@ ei_x_encode_empty_list(&x);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_long(char *buf, int *index, long p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_long(ei_x_buff* x, long p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_long(char *buf, int *index, long p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_long(ei_x_buff* x, long p)</nametext></name> <fsummary>Encode integer.</fsummary> <desc> <p>Encodes a long integer in the binary format. @@ -563,8 +563,8 @@ ei_x_encode_empty_list(&x);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_longlong(char *buf, int *index, long long p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_longlong(ei_x_buff* x, long long p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_longlong(char *buf, int *index, long long p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_longlong(ei_x_buff* x, long long p)</nametext></name> <fsummary>Encode integer.</fsummary> <desc> <p>Encodes a GCC <c>long long</c> or Visual C++ @@ -574,8 +574,8 @@ ei_x_encode_empty_list(&x);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_map_header(char *buf, int *index, int arity)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_map_header(ei_x_buff* x, int arity)</nametext></name> + <name since="OTP 17.0"><ret>int</ret><nametext>ei_encode_map_header(char *buf, int *index, int arity)</nametext></name> + <name since="OTP 17.0"><ret>int</ret><nametext>ei_x_encode_map_header(ei_x_buff* x, int arity)</nametext></name> <fsummary>Encode a map.</fsummary> <desc> <p>Encodes a map header, with a specified arity. The next @@ -595,8 +595,8 @@ ei_x_encode_string(&x, "Banana");</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_pid(char *buf, int *index, const erlang_pid *p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_pid(char *buf, int *index, const erlang_pid *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)</nametext></name> <fsummary>Encode a pid.</fsummary> <desc> <p>Encodes an Erlang process identifier (pid) in the binary @@ -607,8 +607,8 @@ ei_x_encode_string(&x, "Banana");</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_port(char *buf, int *index, const erlang_port *p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_port(ei_x_buff* x, const erlang_port *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_port(char *buf, int *index, const erlang_port *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_port(ei_x_buff* x, const erlang_port *p)</nametext></name> <fsummary>Encode a port.</fsummary> <desc> <p>Encodes an Erlang port in the binary format. Parameter @@ -619,8 +619,8 @@ ei_x_encode_string(&x, "Banana");</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_ref(char *buf, int *index, const erlang_ref *p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_ref(char *buf, int *index, const erlang_ref *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p)</nametext></name> <fsummary>Encode a ref.</fsummary> <desc> <p>Encodes an Erlang reference in the binary format. Parameter @@ -631,10 +631,10 @@ ei_x_encode_string(&x, "Banana");</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_string(char *buf, int *index, const char *p)</nametext></name> - <name><ret>int</ret><nametext>ei_encode_string_len(char *buf, int *index, const char *p, int len)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_string(ei_x_buff* x, const char *p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_string(char *buf, int *index, const char *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_string_len(char *buf, int *index, const char *p, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_string(ei_x_buff* x, const char *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)</nametext></name> <fsummary>Encode a string.</fsummary> <desc> <p>Encodes a string in the binary format. (A string in Erlang @@ -645,8 +645,8 @@ ei_x_encode_string(&x, "Banana");</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_term(char *buf, int *index, void *t)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_term(ei_x_buff* x, void *t)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_term(char *buf, int *index, void *t)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_term(ei_x_buff* x, void *t)</nametext></name> <fsummary>Encode an <c>erl_interface</c> term.</fsummary> <desc> <p>Encodes an <c>ETERM</c>, as obtained from @@ -656,8 +656,8 @@ ei_x_encode_string(&x, "Banana");</pre> </desc> </func> <func> - <name><ret>int</ret><nametext>ei_encode_trace(char *buf, int *index, const erlang_trace *p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_trace(char *buf, int *index, const erlang_trace *p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p)</nametext></name> <fsummary>Encode a trace token.</fsummary> <desc> <p>Encodes an Erlang trace token in the binary format. @@ -668,8 +668,8 @@ ei_x_encode_string(&x, "Banana");</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_tuple_header(char *buf, int *index, int arity)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_tuple_header(ei_x_buff* x, int arity)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_tuple_header(char *buf, int *index, int arity)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_tuple_header(ei_x_buff* x, int arity)</nametext></name> <fsummary>Encode a tuple.</fsummary> <desc> <p>Encodes a tuple header, with a specified @@ -687,8 +687,8 @@ ei_encode_tuple_header(buf, &i, 0);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_ulong(char *buf, int *index, unsigned long p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_ulong(ei_x_buff* x, unsigned long p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_ulong(char *buf, int *index, unsigned long p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_ulong(ei_x_buff* x, unsigned long p)</nametext></name> <fsummary>Encode unsigned integer.</fsummary> <desc> <p>Encodes an unsigned long integer in the binary format. @@ -698,8 +698,8 @@ ei_encode_tuple_header(buf, &i, 0);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_ulonglong(char *buf, int *index, unsigned long long p)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_ulonglong(char *buf, int *index, unsigned long long p)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)</nametext></name> <fsummary>Encode unsigned integer.</fsummary> <desc> <p>Encodes a GCC <c>unsigned long long</c> or Visual C++ @@ -709,8 +709,8 @@ ei_encode_tuple_header(buf, &i, 0);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_encode_version(char *buf, int *index)</nametext></name> - <name><ret>int</ret><nametext>ei_x_encode_version(ei_x_buff* x)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_encode_version(char *buf, int *index)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_encode_version(ei_x_buff* x)</nametext></name> <fsummary>Encode version.</fsummary> <desc> <p>Encodes a version magic number for the binary format. Must @@ -719,7 +719,7 @@ ei_encode_tuple_header(buf, &i, 0);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_get_type(const char *buf, const int *index, int *type, int *size)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_get_type(const char *buf, const int *index, int *type, int *size)</nametext></name> <fsummary>Fetch the type and size of an encoded term.</fsummary> <desc> <p>Returns the type in <c>type</c> and size in @@ -733,8 +733,23 @@ ei_encode_tuple_header(buf, &i, 0);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_print_term(FILE* fp, const char* buf, int* index)</nametext></name> - <name><ret>int</ret><nametext>ei_s_print_term(char** s, const char* buf, int* index)</nametext></name> + <name since="OTP @OTP-15442@"><ret>int</ret><nametext>ei_init(void)</nametext></name> + <fsummary>Initialize the ei library.</fsummary> + <desc> + <p>Initialize the <c>ei</c> library. This function should be called once + (and only once) before calling any other functionality in the <c>ei</c> + library. However, note the exception below.</p> + <p>If the <c>ei</c> library is used together with the <c>erl_interface</c> + library, this function should <em>not</em> be called directly. It will be + called by the <c>erl_init()</c> function which should be used to initialize + the combination of the two libraries instead.</p> + <p>On success zero is returned. On failure a posix error code is returned.</p> + </desc> + </func> + + <func> + <name since=""><ret>int</ret><nametext>ei_print_term(FILE* fp, const char* buf, int* index)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_s_print_term(char** s, const char* buf, int* index)</nametext></name> <fsummary>Print a term in clear text.</fsummary> <desc> <p>Prints a term, in clear text, to the file @@ -759,7 +774,7 @@ ei_encode_tuple_header(buf, &i, 0);</pre> </func> <func> - <name><ret>void</ret><nametext>ei_set_compat_rel(release_number)</nametext></name> + <name since=""><ret>void</ret><nametext>ei_set_compat_rel(release_number)</nametext></name> <fsummary>Set the ei library in compatibility mode.</fsummary> <type> <v>unsigned release_number;</v> @@ -794,7 +809,7 @@ ei_encode_tuple_header(buf, &i, 0);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_skip_term(const char* buf, int* index)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_skip_term(const char* buf, int* index)</nametext></name> <fsummary>Skip a term.</fsummary> <desc> <p>Skips a term in the specified buffer; @@ -815,8 +830,8 @@ ei_encode_tuple_header(buf, &i, 0);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_x_append(ei_x_buff* x, const ei_x_buff* x2)</nametext></name> - <name><ret>int</ret><nametext>ei_x_append_buf(ei_x_buff* x, const char* buf, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_append(ei_x_buff* x, const ei_x_buff* x2)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_append_buf(ei_x_buff* x, const char* buf, int len)</nametext></name> <fsummary>Append a buffer at the end.</fsummary> <desc> <p>Appends data at the end of buffer <c>x</c>.</p> @@ -824,8 +839,8 @@ ei_encode_tuple_header(buf, &i, 0);</pre> </func> <func> - <name><ret>int</ret><nametext>ei_x_format(ei_x_buff* x, const char* fmt, ...)</nametext></name> - <name><ret>int</ret><nametext>ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... )</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_format(ei_x_buff* x, const char* fmt, ...)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... )</nametext></name> <fsummary>Format a term from a format string and parameters.</fsummary> <desc> <p>Formats a term, given as a string, to a buffer. @@ -853,7 +868,7 @@ encodes the tuple {numbers,12,3.14159}</pre> </func> <func> - <name><ret>int</ret><nametext>ei_x_free(ei_x_buff* x)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_free(ei_x_buff* x)</nametext></name> <fsummary>Free a buffer.</fsummary> <desc> <p>Frees an <c>ei_x_buff</c> buffer. @@ -862,8 +877,8 @@ encodes the tuple {numbers,12,3.14159}</pre> </func> <func> - <name><ret>int</ret><nametext>ei_x_new(ei_x_buff* x)</nametext></name> - <name><ret>int</ret><nametext>ei_x_new_with_version(ei_x_buff* x)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_new(ei_x_buff* x)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_x_new_with_version(ei_x_buff* x)</nametext></name> <fsummary>Allocate a new buffer.</fsummary> <desc> <p>Allocates a new <c>ei_x_buff</c> buffer. The diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml index 607a7cbff4..e318dd6664 100644 --- a/lib/erl_interface/doc/src/ei_connect.xml +++ b/lib/erl_interface/doc/src/ei_connect.xml @@ -85,20 +85,288 @@ the <c>_tmo</c> suffix.</p> </section> + <section> + <marker id="ussi"/> + <title>User Supplied Socket Implementation</title> + <p>By default <c>ei</c> supplies a TCP/IPv4 socket interface + that is used when communicating. The user can however plug in + his/her own IPv4 socket implementation. This, for example, in order + to communicate over TLS. A user supplied socket implementation + is plugged in by passing a + <seealso marker="#ei_socket_callbacks">callback structure</seealso> + to either + <seealso marker="#ei_connect_init"><c>ei_connect_init_ussi()</c></seealso> + or + <seealso marker="#ei_connect_init"><c>ei_connect_xinit_ussi()</c></seealso>.</p> + + <p>All callbacks in the <c>ei_socket_callbacks</c> structure + <em>should</em> return zero on success; and a posix error + code on failure.</p> + + <p>The <c>addr</c> argument of the <c>listen</c>, <c>accept</c>, + and <c>connect</c> callbacks refer to appropriate address + structure for currently used protocol. Currently <c>ei</c> + only supports IPv4. That is, at this time <c>addr</c> always + points to a <c>struct sockaddr_in</c> structure.</p> + + <p>The <c>ei_socket_callbacks</c> structure may be enlarged in + the future. All fields not set, <em>needs</em> to be zeroed out.</p> + + <marker id="ei_socket_callbacks"/> + <code type="none"><![CDATA[ +typedef struct { + int flags; + int (*socket)(void **ctx, void *setup_ctx); + int (*close)(void *ctx); + int (*listen)(void *ctx, void *addr, int *len, int backlog); + int (*accept)(void **ctx, void *addr, int *len, unsigned tmo); + int (*connect)(void *ctx, void *addr, int len, unsigned tmo); + int (*writev)(void *ctx, const void *iov, int iovcnt, ssize_t *len, unsigned tmo); + int (*write)(void *ctx, const char *buf, ssize_t *len, unsigned tmo); + int (*read)(void *ctx, char *buf, ssize_t *len, unsigned tmo); + int (*handshake_packet_header_size)(void *ctx, int *sz); + int (*connect_handshake_complete)(void *ctx); + int (*accept_handshake_complete)(void *ctx); + int (*get_fd)(void *ctx, int *fd); +} ei_socket_callbacks; + ]]></code> + + <taglist> + + <tag><c>flags</c></tag> + <item> + <p>Flags informing <c>ei</c> about the behaviour of the + callbacks. Flags should be bitwise or:ed together. If no flag, + is set, the <c>flags</c> field should contain <c>0</c>. Currently, + supported flags:</p> + <taglist> + <tag><c>EI_SCLBK_FLG_FULL_IMPL</c></tag> + <item> + <p> + If set, the <c>accept()</c>, <c>connect()</c>, + <c>writev()</c>, <c>write()</c>, and <c>read()</c> callbacks + implements timeouts. The timeout is passed in the <c>tmo</c> + argument and is given in milli seconds. Note that the + <c>tmo</c> argument to these callbacks differ from the + timeout arguments in the <c>ei</c> API. Zero means a zero + timeout. That is, poll and timeout immediately unless the + operation is successful. <c>EI_SCLBK_INF_TMO</c> + (max <c>unsigned</c>) means infinite timeout. The file + descriptor is in blocking mode when a callback is called, + and it must be in blocking mode when the callback returns. + </p> + <p> + If not set, <c>ei</c> will implement the timeout using + <c>select()</c> in order to determine when to call the + callbacks and when to time out. The <c>tmo</c> arguments + of the <c>accept()</c>, <c>connect()</c>, <c>writev()</c>, + <c>write()</c>, and <c>read()</c> callbacks should be + ignored. The callbacks may be called in non-blocking mode. + The callbacks are not allowed to change between blocking + and non-blocking mode. In order for this to work, + <c>select()</c> needs to interact with the socket primitives + used the same way as it interacts with the ordinary socket + primitives. If this is not the case, the callbacks + <em>need</em> to implement timeouts and this flag should + be set. + </p> + </item> + </taglist> + <p>More flags may be introduced in the future.</p> + </item> + + <tag><c>int (*socket)(void **ctx, void *setup_ctx)</c></tag> + <item> + <p>Create a socket and a context for the socket.</p> + + <p>On success it should set <c>*ctx</c> to point to a context for + the created socket. This context will be passed to all other + socket callbacks. This function will be passed the same + <c>setup_context</c> as passed to the preceeding + <seealso marker="#ei_connect_init"><c>ei_connect_init_ussi()</c></seealso> + or + <seealso marker="#ei_connect_init"><c>ei_connect_xinit_ussi()</c></seealso> + call.</p> + + <note><p>During the lifetime of a socket, the pointer <c>*ctx</c> + <em>has</em> to remain the same. That is, it cannot later be + relocated.</p></note> + + <p>This callback is mandatory.</p> + </item> + + <tag><c>int (*close)(void *ctx)</c></tag> + <item> + <p>Close the socket identified by <c>ctx</c> and destroy the context.</p> + + <p>This callback is mandatory.</p> + </item> + + <tag><c>int (*listen)(void *ctx, void *addr, int *len, int backlog)</c></tag> + <item> + <p>Bind the socket identified by <c>ctx</c> to a local interface + and then listen on it.</p> + + <p>The <c>addr</c> and <c>len</c> arguments are both input and output + arguments. When called <c>addr</c> points to an address structure of + lenght <c>*len</c> containing information on how to bind the socket. + Uppon return this callback should have updated the structure referred + by <c>addr</c> with information on how the socket actually was bound. + <c>*len</c> should be updated to reflect the size of <c>*addr</c> + updated. <c>backlog</c> identifies the size of the backlog for the + listen socket.</p> + + <p>This callback is mandatory.</p> + </item> + + <tag><c>int (*accept)(void **ctx, void *addr, int *len, unsigned tmo)</c></tag> + <item> + <p>Accept connections on the listen socket identified by + <c>*ctx</c>.</p> + + <p>When a connection is accepted, a new context for the accepted + connection should be created and <c>*ctx</c> should be updated + to point to the new context for the accepted connection. When + called <c>addr</c> points to an uninitialized address structure + of lenght <c>*len</c>. Uppon return this callback should have + updated this structure with information about the client address. + <c>*len</c> should be updated to reflect the size of <c>*addr</c> + updated. + </p> + + <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set, + <c>tmo</c> contains timeout time in milliseconds.</p> + + <note><p>During the lifetime of a socket, the pointer <c>*ctx</c> + <em>has</em> to remain the same. That is, it cannot later be + relocated.</p></note> + + <p>This callback is mandatory.</p> + </item> + + <tag><c>int (*connect)(void *ctx, void *addr, int len, unsigned tmo)</c></tag> + <item> + <p>Connect the socket identified by <c>ctx</c> to the address + identified by <c>addr</c>.</p> + + <p>When called <c>addr</c> points to an address structure of + lenght <c>len</c> containing information on where to connect.</p> + + <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set, + <c>tmo</c> contains timeout time in milliseconds.</p> + + <p>This callback is mandatory.</p> + </item> + + <tag><c>int (*writev)(void *ctx, const void *iov, long iovcnt, ssize_t *len, unsigned tmo)</c></tag> + <item> + <p>Write data on the connected socket identified by <c>ctx</c>.</p> + + <p><c>iov</c> points to an array of <c>struct iovec</c> structures of + length <c>iovcnt</c> containing data to write to the socket. On success, + this callback should set <c>*len</c> to the amount of bytes successfully + written on the socket.</p> + + <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set, + <c>tmo</c> contains timeout time in milliseconds.</p> + + <p>This callback is optional. Set the <c>writev</c> field + in the the <c>ei_socket_callbacks</c> structure to <c>NULL</c> if not + implemented.</p> + </item> + + <tag><c>int (*write)(void *ctx, const char *buf, ssize_t *len, unsigned tmo)</c></tag> + <item> + <p>Write data on the connected socket identified by <c>ctx</c>.</p> + + <p>When called <c>buf</c> points to a buffer of length <c>*len</c> + containing the data to write on the socket. On success, this callback + should set <c>*len</c> to the amount of bytes successfully written on + the socket.</p> + + <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set, + <c>tmo</c> contains timeout time in milliseconds.</p> + + <p>This callback is mandatory.</p> + </item> + + <tag><c>int (*read)(void *ctx, char *buf, ssize_t *len, unsigned tmo)</c></tag> + <item> + <p>Read data on the connected socket identified by <c>ctx</c>.</p> + + <p><c>buf</c> points to a buffer of length <c>*len</c> where the + read data should be placed. On success, this callback should update + <c>*len</c> to the amount of bytes successfully read on the socket.</p> + + <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set, + <c>tmo</c> contains timeout time in milliseconds.</p> + + <p>This callback is mandatory.</p> + </item> + + <tag><c>int (*handshake_packet_header_size)(void *ctx, int *sz)</c></tag> + <item> + <p>Inform about handshake packet header size to use during the Erlang + distribution handshake.</p> + + <p>On success, <c>*sz</c> should be set to the handshake packet header + size to use. Valid values are <c>2</c> and <c>4</c>. Erlang TCP + distribution use a handshake packet size of <c>2</c> and Erlang TLS + distribution use a handshake packet size of <c>4</c>.</p> + + <p>This callback is mandatory.</p> + </item> + + <tag><c>int (*connect_handshake_complete)(void *ctx)</c></tag> + <item> + <p>Called when a locally started handshake has completed successfully.</p> + + <p>This callback is optional. Set the <c>connect_handshake_complete</c> field + in the <c>ei_socket_callbacks</c> structure to <c>NULL</c> if not implemented.</p> + </item> + + <tag><c>int (*accept_handshake_complete)(void *ctx)</c></tag> + <item> + <p>Called when a remotely started handshake has completed successfully.</p> + + <p>This callback is optional. Set the <c>accept_handshake_complete</c> field in + the <c>ei_socket_callbacks</c> structure to <c>NULL</c> if not implemented.</p> + </item> + + <tag><c>int (*get_fd)(void *ctx, int *fd)</c></tag> + <item> + <p>Inform about file descriptor used by the socket which is identified + by <c>ctx</c>.</p> + + <note><p>During the lifetime of a socket, the file descriptor + <em>has</em> to remain the same. That is, repeated calls to this + callback with the same context <c>should</c> always report the same + file descriptor.</p> + <p>The file descriptor <em>has</em> to be a real file descriptor. + That is, no other operation should be able to get the same file + descriptor until it has been released by the <c>close()</c> + callback.</p> + </note> + + <p>This callback is mandatory.</p> + </item> + </taglist> + </section> <funcs> <func> - <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr(const char *addr, int len, int type)</nametext></name> - <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name> - <name><ret>struct hostent</ret><nametext>*ei_gethostbyname(const char *name)</nametext></name> - <name><ret>struct hostent</ret><nametext>*ei_gethostbyname_r(const char *name, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name> + <name since=""><ret>struct hostent *</ret><nametext>ei_gethostbyaddr(const char *addr, int len, int type)</nametext></name> + <name since=""><ret>struct hostent *</ret><nametext>ei_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name> + <name since=""><ret>struct hostent *</ret><nametext>ei_gethostbyname(const char *name)</nametext></name> + <name since=""><ret>struct hostent *</ret><nametext>ei_gethostbyname_r(const char *name, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name> <fsummary>Name lookup functions.</fsummary> <desc> <p>Convenience functions for some common name lookup functions.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>ei_accept(ei_cnode *ec, int listensock, ErlConnect *conp)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_accept(ei_cnode *ec, int listensock, ErlConnect *conp)</nametext></name> <fsummary>Accept a connection from another node.</fsummary> <desc> <p>Used by a server process to accept a @@ -130,7 +398,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>ei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms)</nametext></name> <fsummary>Accept a connection from another node with optional time-out.</fsummary> <desc> @@ -141,8 +409,16 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>ei_connect(ei_cnode* ec, char *nodename)</nametext></name> - <name><ret>int</ret><nametext>ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)</nametext></name> + <name since="OTP @OTP-15442@"><ret>int</ret><nametext>ei_close_connection(int fd)</nametext></name> + <fsummary>Close a connection.</fsummary> + <desc> + <p>Closes a previously opened connection or listen socket.</p> + </desc> + </func> + + <func> + <name since=""><ret>int</ret><nametext>ei_connect(ei_cnode* ec, char *nodename)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)</nametext></name> <fsummary>Establish a connection to an Erlang node.</fsummary> <desc> <p>Sets up a connection to an Erlang node.</p> @@ -192,8 +468,10 @@ fd = ei_xconnect(&ec, &addr, ALIVE); </func> <func> - <name><ret>int</ret><nametext>ei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation)</nametext></name> - <name><ret>int</ret><nametext>ei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation)</nametext></name> + <name since="OTP @OTP-15442@"><ret>int</ret><nametext>ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation, ei_socket_callbacks *cbs, int cbs_sz, void *setup_context)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation)</nametext></name> + <name since="OTP @OTP-15442@"><ret>int</ret><nametext>ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation, ei_socket_callbacks *cbs, int cbs_sz, void *setup_context)</nametext></name> <fsummary>Initialize for a connection.</fsummary> <desc> <p>Initializes the <c>ec</c> structure, to @@ -236,6 +514,21 @@ fd = ei_xconnect(&ec, &addr, ALIVE); <item> <p><c>thispaddr</c> if the IP address of the host.</p> </item> + <item> + <p><c>cbs</c> is a pointer to a + <seealso marker="#ei_socket_callbacks">callback structure</seealso> + implementing and alternative socket interface.</p> + </item> + <item> + <p><c>cbs_sz</c> is the size of the structure + pointed to by <c>cbs</c>.</p> + </item> + <item> + <p><c>setup_context</c> is a pointer to a structure that + will be passed as second argument to the <c>socket</c> callback + in the <c>cbs</c> structure.</p> + </item> + </list> <p>A C-node acting as a server is assigned a creation number when it calls <c>ei_publish()</c>.</p> @@ -273,8 +566,8 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { </func> <func> - <name><ret>int</ret><nametext>ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms)</nametext></name> - <name><ret>int</ret><nametext>ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms)</nametext></name> <fsummary>Establish a connection to an Erlang node with optional time-out.</fsummary> <desc> @@ -286,8 +579,8 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { </func> <func> - <name><ret>int</ret><nametext>ei_get_tracelevel(void)</nametext></name> - <name><ret>void</ret><nametext>ei_set_tracelevel(int level)</nametext></name> + <name since="OTP R13B04"><ret>int</ret><nametext>ei_get_tracelevel(void)</nametext></name> + <name since="OTP R13B04"><ret>void</ret><nametext>ei_set_tracelevel(int level)</nametext></name> <fsummary>Get and set functions for tracing.</fsummary> <desc> <p>Used to set tracing on the distribution. The levels are different @@ -299,7 +592,46 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { </func> <func> - <name><ret>int</ret><nametext>ei_publish(ei_cnode *ec, int port)</nametext></name> + <name since="OTP @OTP-15442@"><ret>int</ret><nametext>ei_listen(ei_cnode *ec, int *port, int backlog)</nametext></name> + <name since="OTP @OTP-15442@"><ret>int</ret><nametext>ei_xlisten(ei_cnode *ec, Erl_IpAddr adr, int *port, int backlog)</nametext></name> + <fsummary>Create a listen socket.</fsummary> + <desc> + <p>Used by a server process to setup a listen socket which + later can be used for accepting connections from client processes. + </p> + <list type="bulleted"> + <item> + <p><c>ec</c> is the C-node structure.</p> + </item> + <item> + <p><c>adr</c> is local interface to bind to.</p> + </item> + <item> + <p><c>port</c> is a pointer to an integer containing the + port number to bind to. If <c>*port</c> equals <c>0</c> + when calling <c>ei_listen()</c>, the socket will be bound to + an ephemeral port. On success, <c>ei_listen()</c> will update + the value of <c>*port</c> to the port actually bound to. + </p> + </item> + <item> + <p><c>backlog</c> is maximum backlog of pending connections.</p> + </item> + </list> + <p><c>ei_listen</c> will create a socket, bind to a port on the + local interface identified by <c>adr</c> (or all local interfaces if + <c>ei_listen()</c> is called), and mark the socket as a passive socket + (that is, a socket that will be used for accepting incoming connections). + </p> + <p> + On success, a file descriptor is returned which can be used in a call to + <c>ei_accept()</c>. On failure, <c>ERL_ERROR</c> is returned and + <c>erl_errno</c> is set to <c>EIO</c>.</p> + </desc> + </func> + + <func> + <name since=""><ret>int</ret><nametext>ei_publish(ei_cnode *ec, int port)</nametext></name> <fsummary>Publish a node name.</fsummary> <desc> <p>Used by a server process to register @@ -336,7 +668,7 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { </func> <func> - <name><ret>int</ret><nametext>ei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms)</nametext></name> <fsummary>Publish a node name with optional time-out.</fsummary> <desc> <p>Equivalent to @@ -346,7 +678,7 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { </func> <func> - <name><ret>int</ret><nametext>ei_receive(int fd, unsigned char* bufp, int bufsize)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_receive(int fd, unsigned char* bufp, int bufsize)</nametext></name> <fsummary>Receive a message.</fsummary> <desc> <p>Receives a message consisting of a sequence @@ -387,7 +719,7 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { </func> <func> - <name><ret>int</ret><nametext>ei_receive_encoded(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_receive_encoded(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen)</nametext></name> <fsummary>Obsolete function for receiving a message.</fsummary> <desc> <p>This function is retained for compatibility with code @@ -417,7 +749,7 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { </func> <func> - <name><ret>int</ret><nametext>ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned timeout_ms)</nametext></name> <fsummary>Obsolete function for receiving a message with time-out. </fsummary> <desc> @@ -428,8 +760,8 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { </func> <func> - <name><ret>int</ret><nametext>ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name> - <name><ret>int</ret><nametext>ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name> <fsummary>Receive a message.</fsummary> <desc> <p>Receives a message to the buffer in <c>x</c>. @@ -493,8 +825,8 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned imeout_ms)</nametext></name> - <name><ret>int</ret><nametext>ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned imeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned timeout_ms)</nametext></name> <fsummary>Receive a message with optional time-out.</fsummary> <desc> <p>Equivalent to <c>ei_receive_msg</c> and <c>ei_xreceive_msg</c> @@ -504,7 +836,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>ei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms)</nametext></name> <fsummary>Receive a message with optional time-out.</fsummary> <desc> <p>Equivalent to @@ -514,7 +846,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>ei_reg_send(ei_cnode* ec, int fd, char* server_name, char* buf, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_send(ei_cnode* ec, int fd, char* server_name, char* buf, int len)</nametext></name> <fsummary>Send a message to a registered name.</fsummary> <desc> <p>Sends an Erlang term to a registered process.</p> @@ -546,7 +878,7 @@ if (ei_reg_send(&ec, fd, x.buff, x.index) < 0) </func> <func> - <name><ret>int</ret><nametext>ei_reg_send_tmo(ei_cnode* ec, int fd, char* server_name, char* buf, int len, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_send_tmo(ei_cnode* ec, int fd, char* server_name, char* buf, int len, unsigned timeout_ms)</nametext></name> <fsummary>Send a message to a registered name with optional time-out </fsummary> <desc> @@ -557,9 +889,9 @@ if (ei_reg_send(&ec, fd, x.buff, x.index) < 0) </func> <func> - <name><ret>int</ret><nametext>ei_rpc(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen, ei_x_buff *x)</nametext></name> - <name><ret>int</ret><nametext>ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen)</nametext></name> - <name><ret>int</ret><nametext>ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_rpc(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen, ei_x_buff *x)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x)</nametext></name> <fsummary>Remote Procedure Call from C to Erlang.</fsummary> <desc> <p>Supports calling Erlang functions on remote nodes. @@ -658,7 +990,7 @@ if (ei_decode_version(result.buff, &index) < 0 </func> <func> - <name><ret>erlang_pid *</ret><nametext>ei_self(ei_cnode *ec)</nametext></name> + <name since=""><ret>erlang_pid *</ret><nametext>ei_self(ei_cnode *ec)</nametext></name> <fsummary>Retrieve the pid of the C-node.</fsummary> <desc> <p>Retrieves the pid of the C-node. Every C-node @@ -671,7 +1003,7 @@ if (ei_decode_version(result.buff, &index) < 0 </func> <func> - <name><ret>int</ret><nametext>ei_send(int fd, erlang_pid* to, char* buf, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_send(int fd, erlang_pid* to, char* buf, int len)</nametext></name> <fsummary>Send a message.</fsummary> <desc> <p>Sends an Erlang term to a process.</p> @@ -692,7 +1024,7 @@ if (ei_decode_version(result.buff, &index) < 0 </func> <func> - <name><ret>int</ret><nametext>ei_send_encoded(int fd, erlang_pid* to, char* buf, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_send_encoded(int fd, erlang_pid* to, char* buf, int len)</nametext></name> <fsummary>Obsolete function to send a message.</fsummary> <desc> <p>Works exactly as <c>ei_send</c>, the alternative name is retained for @@ -702,7 +1034,7 @@ if (ei_decode_version(result.buff, &index) < 0 </func> <func> - <name><ret>int</ret><nametext>ei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name> <fsummary>Obsolete function to send a message with optional time-out. </fsummary> <desc> @@ -713,7 +1045,7 @@ if (ei_decode_version(result.buff, &index) < 0 </func> <func> - <name><ret>int</ret><nametext>ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name> <fsummary>Obsolete function to send a message to a registered name. </fsummary> <desc> @@ -741,7 +1073,7 @@ self->num = fd; </func> <func> - <name><ret>int</ret><nametext>ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name> <fsummary>Obsolete function to send a message to a registered name with time-out.</fsummary> <desc> @@ -752,7 +1084,7 @@ self->num = fd; </func> <func> - <name><ret>int</ret><nametext>ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name> <fsummary>Send a message with optional time-out.</fsummary> <desc> <p>Equivalent to @@ -762,9 +1094,9 @@ self->num = fd; </func> <func> - <name><ret>const char *</ret><nametext>ei_thisnodename(ei_cnode *ec)</nametext></name> - <name><ret>const char *</ret><nametext>ei_thishostname(ei_cnode *ec)</nametext></name> - <name><ret>const char *</ret><nametext>ei_thisalivename(ei_cnode *ec)</nametext></name> + <name since=""><ret>const char *</ret><nametext>ei_thisnodename(ei_cnode *ec)</nametext></name> + <name since=""><ret>const char *</ret><nametext>ei_thishostname(ei_cnode *ec)</nametext></name> + <name since=""><ret>const char *</ret><nametext>ei_thisalivename(ei_cnode *ec)</nametext></name> <fsummary>Retrieve some values.</fsummary> <desc> <p>Can be used to retrieve information about @@ -779,7 +1111,7 @@ self->num = fd; </func> <func> - <name><ret>int</ret><nametext>ei_unpublish(ei_cnode *ec)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_unpublish(ei_cnode *ec)</nametext></name> <fsummary>Forcefully unpublish a node name.</fsummary> <desc> <p>Can be called by a process to unregister a @@ -802,7 +1134,7 @@ self->num = fd; </func> <func> - <name><ret>int</ret><nametext>ei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms)</nametext></name> <fsummary>Unpublish a node name with optional time-out.</fsummary> <desc> <p>Equivalent to diff --git a/lib/erl_interface/doc/src/ei_users_guide.xml b/lib/erl_interface/doc/src/ei_users_guide.xml index 0eed50b50b..2dfd99e35a 100644 --- a/lib/erl_interface/doc/src/ei_users_guide.xml +++ b/lib/erl_interface/doc/src/ei_users_guide.xml @@ -162,12 +162,20 @@ $ ld -L/usr/local/otp/lib/erl_interface-3.2.3/ </section> <section> - <title>Initializing the Erl_Interface Library</title> - <p>Before calling any of the other <c>Erl_Interface</c> functions, call - <c>erl_init()</c> exactly once to initialize the library. + <title>Initializing the Libraries</title> + <p> + Before calling any of the other functions in the <c>erl_interface</c> + and <c>ei</c> libraries, call <c>erl_init()</c> exactly once to initialize + both libraries. <c>erl_init()</c> takes two arguments. However, the arguments - are no longer used by <c>Erl_Interface</c> and are therefore to be - specified as <c>erl_init(NULL,0)</c>.</p> + are no longer used by <c>erl_interface</c> and are therefore to be + specified as <c>erl_init(NULL,0)</c>. + </p> + <p> + If you only use the <c>ei</c> library, instead initialize it by calling + <c>ei_init()</c> exactly once before calling any other functions in + the <c>ei</c> library. + </p> </section> <section> diff --git a/lib/erl_interface/doc/src/erl_connect.xml b/lib/erl_interface/doc/src/erl_connect.xml index 76ef6588c2..139ac9e2f0 100644 --- a/lib/erl_interface/doc/src/erl_connect.xml +++ b/lib/erl_interface/doc/src/erl_connect.xml @@ -49,7 +49,7 @@ <funcs> <func> - <name><ret>int</ret><nametext>erl_accept(listensock, conp)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_accept(listensock, conp)</nametext></name> <fsummary>Accept a connection.</fsummary> <type> <v>int listensock;</v> @@ -78,7 +78,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>erl_close_connection(fd)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_close_connection(fd)</nametext></name> <fsummary>Close a connection to an Erlang node.</fsummary> <type> <v>int fd;</v> @@ -95,8 +95,8 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>erl_connect(node)</nametext></name> - <name><ret>int</ret><nametext>erl_xconnect(addr, alive)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_connect(node)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_xconnect(addr, alive)</nametext></name> <fsummary>Establish a connection to an Erlang node.</fsummary> <type> <v>char *node, *alive;</v> @@ -149,8 +149,8 @@ erl_xconnect( &addr , ALIVE ); </func> <func> - <name><ret>int</ret><nametext>erl_connect_init(number, cookie, creation)</nametext></name> - <name><ret>int</ret><nametext>erl_connect_xinit(host, alive, node, addr, cookie, creation)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_connect_init(number, cookie, creation)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_connect_xinit(host, alive, node, addr, cookie, creation)</nametext></name> <fsummary>Initialize communication.</fsummary> <type> <v>int number;</v> @@ -246,7 +246,7 @@ if (!erl_connect_init(17, "samplecookiestring...", 0)) </func> <func> - <name><ret>int</ret><nametext>erl_publish(port)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_publish(port)</nametext></name> <fsummary>Publish a node name.</fsummary> <type> <v>int port;</v> @@ -277,7 +277,7 @@ if (!erl_connect_init(17, "samplecookiestring...", 0)) </func> <func> - <name><ret>int</ret><nametext>erl_receive(fd, bufp, bufsize)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_receive(fd, bufp, bufsize)</nametext></name> <fsummary>Receive a message.</fsummary> <type> <v>int fd;</v> @@ -316,7 +316,7 @@ if (!erl_connect_init(17, "samplecookiestring...", 0)) </func> <func> - <name><ret>int</ret><nametext>erl_receive_msg(fd, bufp, bufsize, emsg)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_receive_msg(fd, bufp, bufsize, emsg)</nametext></name> <fsummary>Receive and decode a message.</fsummary> <type> <v>int fd;</v> @@ -411,7 +411,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>erl_reg_send(fd, to, msg)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_reg_send(fd, to, msg)</nametext></name> <fsummary>Send a message to a registered name.</fsummary> <type> <v>int fd;</v> @@ -439,9 +439,9 @@ typedef struct { </func> <func> - <name><ret>ETERM *</ret><nametext>erl_rpc(fd, mod, fun, args)</nametext></name> - <name><ret>int</ret><nametext>erl_rpc_from(fd, timeout, emsg)</nametext></name> - <name><ret>int</ret><nametext>erl_rpc_to(fd, mod, fun, args)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_rpc(fd, mod, fun, args)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_rpc_from(fd, timeout, emsg)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_rpc_to(fd, mod, fun, args)</nametext></name> <fsummary>Remote Procedure Call.</fsummary> <type> <v>int fd, timeout;</v> @@ -511,7 +511,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>erl_send(fd, to, msg)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_send(fd, to, msg)</nametext></name> <fsummary>Send a message.</fsummary> <type> <v>int fd;</v> @@ -541,11 +541,11 @@ typedef struct { </func> <func> - <name><ret>const char *</ret><nametext>erl_thisalivename()</nametext></name> - <name><ret>const char *</ret><nametext>erl_thiscookie()</nametext></name> - <name><ret>short</ret><nametext>erl_thiscreation()</nametext></name> - <name><ret>const char *</ret><nametext>erl_thishostname()</nametext></name> - <name><ret>const char *</ret><nametext>erl_thisnodename()</nametext></name> + <name since=""><ret>const char *</ret><nametext>erl_thisalivename()</nametext></name> + <name since=""><ret>const char *</ret><nametext>erl_thiscookie()</nametext></name> + <name since=""><ret>short</ret><nametext>erl_thiscreation()</nametext></name> + <name since=""><ret>const char *</ret><nametext>erl_thishostname()</nametext></name> + <name since=""><ret>const char *</ret><nametext>erl_thisnodename()</nametext></name> <fsummary>Retrieve some values.</fsummary> <desc> <p>Retrieves information about @@ -556,7 +556,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>erl_unpublish(alive)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_unpublish(alive)</nametext></name> <fsummary>Forcefully unpublish a node name.</fsummary> <type> <v>char *alive;</v> @@ -583,7 +583,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>erl_xreceive_msg(fd, bufpp, bufsizep, emsg)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_xreceive_msg(fd, bufpp, bufsizep, emsg)</nametext></name> <fsummary>Receive and decode a message.</fsummary> <type> <v>int fd;</v> @@ -616,10 +616,10 @@ typedef struct { </func> <func> - <name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr(addr, length, type)</nametext></name> - <name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, h_errnop)</nametext></name> - <name><ret>struct hostent</ret><nametext>*erl_gethostbyname(name)</nametext></name> - <name><ret>struct hostent</ret><nametext>*erl_gethostbyname_r(name, hostp, buffer, buflen, h_errnop)</nametext></name> + <name since=""><ret>struct hostent *</ret><nametext>erl_gethostbyaddr(addr, length, type)</nametext></name> + <name since=""><ret>struct hostent *</ret><nametext>erl_gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, h_errnop)</nametext></name> + <name since=""><ret>struct hostent *</ret><nametext>erl_gethostbyname(name)</nametext></name> + <name since=""><ret>struct hostent *</ret><nametext>erl_gethostbyname_r(name, hostp, buffer, buflen, h_errnop)</nametext></name> <fsummary>Name lookup functions.</fsummary> <type> diff --git a/lib/erl_interface/doc/src/erl_error.xml b/lib/erl_interface/doc/src/erl_error.xml index 8139c9b343..6fac94e442 100644 --- a/lib/erl_interface/doc/src/erl_error.xml +++ b/lib/erl_interface/doc/src/erl_error.xml @@ -47,7 +47,7 @@ <funcs> <func> - <name><ret>void</ret><nametext>erl_err_msg(FormatStr, ... )</nametext></name> + <name since=""><ret>void</ret><nametext>erl_err_msg(FormatStr, ... )</nametext></name> <fsummary>Non-fatal error, and not system call error.</fsummary> <type> <v>const char *FormatStr;</v> @@ -59,7 +59,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_err_quit(FormatStr, ... )</nametext></name> + <name since=""><ret>void</ret><nametext>erl_err_quit(FormatStr, ... )</nametext></name> <fsummary>Fatal error, but not system call error.</fsummary> <type> <v>const char *FormatStr;</v> @@ -73,7 +73,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_err_ret(FormatStr, ... )</nametext></name> + <name since=""><ret>void</ret><nametext>erl_err_ret(FormatStr, ... )</nametext></name> <fsummary>Non-fatal system call error.</fsummary> <type> <v>const char *FormatStr;</v> @@ -86,7 +86,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_err_sys(FormatStr, ... )</nametext></name> + <name since=""><ret>void</ret><nametext>erl_err_sys(FormatStr, ... )</nametext></name> <fsummary>Fatal system call error.</fsummary> <type> <v>const char *FormatStr;</v> @@ -113,7 +113,7 @@ <funcs> <func> - <name><ret>volatile int</ret><nametext>erl_errno</nametext></name> + <name since=""><ret>volatile int</ret><nametext>erl_errno</nametext></name> <fsummary>Variable <c>erl_errno</c> contains the Erl_Interface error number. You can change the value if you wish. </fsummary> diff --git a/lib/erl_interface/doc/src/erl_eterm.xml b/lib/erl_interface/doc/src/erl_eterm.xml index 9a05196a70..070ed30dfe 100644 --- a/lib/erl_interface/doc/src/erl_eterm.xml +++ b/lib/erl_interface/doc/src/erl_eterm.xml @@ -142,7 +142,7 @@ <funcs> <func> - <name><ret>ETERM *</ret><nametext>erl_cons(head, tail)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_cons(head, tail)</nametext></name> <fsummary>Prepend a term to the head of a list.</fsummary> <type> <v>ETERM *head;</v> @@ -181,7 +181,7 @@ erl_free_compound(list); </func> <func> - <name><ret>ETERM *</ret><nametext>erl_copy_term(term)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_copy_term(term)</nametext></name> <fsummary>Create a copy of an Erlang term.</fsummary> <type> <v>ETERM *term;</v> @@ -193,7 +193,7 @@ erl_free_compound(list); </func> <func> - <name><ret>ETERM *</ret><nametext>erl_element(position, tuple)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_element(position, tuple)</nametext></name> <fsummary>Extract an element from an Erlang tuple.</fsummary> <type> <v>int position;</v> @@ -215,7 +215,7 @@ erl_free_compound(list); </func> <func> - <name><ret>ETERM *</ret><nametext>erl_hd(list)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_hd(list)</nametext></name> <fsummary>Extract the first element from a list.</fsummary> <type> <v>ETERM *list;</v> @@ -230,7 +230,7 @@ erl_free_compound(list); </func> <func> - <name><ret>void</ret><nametext>erl_init(NULL, 0)</nametext></name> + <name since=""><ret>void</ret><nametext>erl_init(NULL, 0)</nametext></name> <fsummary>Initialization routine.</fsummary> <type> <v>void *NULL;</v> @@ -245,7 +245,7 @@ erl_free_compound(list); </func> <func> - <name><ret>int</ret><nametext>erl_iolist_length(list)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_iolist_length(list)</nametext></name> <fsummary>Return the length of an I/O list.</fsummary> <type> <v>ETERM *list;</v> @@ -262,7 +262,7 @@ erl_free_compound(list); </func> <func> - <name><ret>ETERM *</ret><nametext>erl_iolist_to_binary(term)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_iolist_to_binary(term)</nametext></name> <fsummary>Convert an I/O list to a binary.</fsummary> <type> <v>ETERM *list;</v> @@ -289,7 +289,7 @@ iohead ::= Binary </func> <func> - <name><ret>char *</ret><nametext>erl_iolist_to_string(list)</nametext></name> + <name since=""><ret>char *</ret><nametext>erl_iolist_to_string(list)</nametext></name> <fsummary>Convert an I/O list to a <c>NULL</c>-terminated string.</fsummary> <type> <v>ETERM *list;</v> @@ -312,7 +312,7 @@ iohead ::= Binary </func> <func> - <name><ret>int</ret><nametext>erl_length(list)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_length(list)</nametext></name> <fsummary>Determine the length of a list.</fsummary> <type> <v>ETERM *list;</v> @@ -328,7 +328,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_atom(string)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_atom(string)</nametext></name> <fsummary>Create an atom.</fsummary> <type> <v>const char *string;</v> @@ -355,7 +355,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_binary(bptr, size)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_binary(bptr, size)</nametext></name> <fsummary>Create a binary object.</fsummary> <type> <v>char *bptr;</v> @@ -378,7 +378,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_empty_list()</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_empty_list()</nametext></name> <fsummary>Create an empty Erlang list.</fsummary> <desc> <p>Creates and returns an empty Erlang list. @@ -388,7 +388,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_estring(string, len)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_estring(string, len)</nametext></name> <fsummary>Create an Erlang string.</fsummary> <type> <v>char *string;</v> @@ -408,7 +408,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_float(f)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_float(f)</nametext></name> <fsummary>Create an Erlang float.</fsummary> <type> <v>double f;</v> @@ -426,7 +426,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_int(n)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_int(n)</nametext></name> <fsummary>Create an Erlang integer.</fsummary> <type> <v>int n;</v> @@ -443,7 +443,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_list(array, arrsize)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_list(array, arrsize)</nametext></name> <fsummary>Create a list from an array.</fsummary> <type> <v>ETERM **array;</v> @@ -465,7 +465,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_long_ref(node, n1, n2, n3, creation)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_long_ref(node, n1, n2, n3, creation)</nametext></name> <fsummary>Create an Erlang reference.</fsummary> <type> <v>const char *node;</v> @@ -495,7 +495,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_pid(node, number, serial, creation)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_pid(node, number, serial, creation)</nametext></name> <fsummary>Create a process identifier.</fsummary> <type> <v>const char *node;</v> @@ -525,7 +525,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_port(node, number, creation)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_port(node, number, creation)</nametext></name> <fsummary>Create a port identifier.</fsummary> <type> <v>const char *node;</v> @@ -550,7 +550,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_ref(node, number, creation)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_ref(node, number, creation)</nametext></name> <fsummary>Create an old Erlang reference.</fsummary> <type> <v>const char *node;</v> @@ -578,7 +578,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_string(string)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_string(string)</nametext></name> <fsummary>Create a string.</fsummary> <type> <v>char *string;</v> @@ -593,7 +593,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_tuple(array, arrsize)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_tuple(array, arrsize)</nametext></name> <fsummary>Create an Erlang tuple from an array.</fsummary> <type> <v>ETERM **array;</v> @@ -621,7 +621,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_uint(n)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_uint(n)</nametext></name> <fsummary>Create an unsigned integer.</fsummary> <type> <v>unsigned int n;</v> @@ -638,7 +638,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_mk_var(name)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_mk_var(name)</nametext></name> <fsummary>Create an Erlang variable.</fsummary> <type> <v>char *name;</v> @@ -653,7 +653,7 @@ iohead ::= Binary </func> <func> - <name><ret>int</ret><nametext>erl_print_term(stream, term)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_print_term(stream, term)</nametext></name> <fsummary>Print an Erlang term.</fsummary> <type> <v>FILE *stream;</v> @@ -672,7 +672,7 @@ iohead ::= Binary </func> <func> - <name><ret>void</ret><nametext>erl_set_compat_rel(release_number)</nametext></name> + <name since=""><ret>void</ret><nametext>erl_set_compat_rel(release_number)</nametext></name> <fsummary>Set the Erl_Interface library in compatibility mode.</fsummary> <type> <v>unsigned release_number;</v> @@ -706,7 +706,7 @@ iohead ::= Binary </func> <func> - <name><ret>int</ret><nametext>erl_size(term)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_size(term)</nametext></name> <fsummary>Return the arity of a tuple or binary.</fsummary> <type> <v>ETERM *term;</v> @@ -723,7 +723,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_tl(list)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_tl(list)</nametext></name> <fsummary>Extract the tail from a list.</fsummary> <type> <v>ETERM *list;</v> @@ -738,7 +738,7 @@ iohead ::= Binary </func> <func> - <name><ret>ETERM *</ret><nametext>erl_var_content(term, name)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_var_content(term, name)</nametext></name> <fsummary>Extract the content of a variable.</fsummary> <type> <v>ETERM *term;</v> diff --git a/lib/erl_interface/doc/src/erl_format.xml b/lib/erl_interface/doc/src/erl_format.xml index 5b8b7b5e78..b5e895c720 100644 --- a/lib/erl_interface/doc/src/erl_format.xml +++ b/lib/erl_interface/doc/src/erl_format.xml @@ -41,7 +41,7 @@ <funcs> <func> - <name><ret>ETERM *</ret><nametext>erl_format(FormatStr, ...)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_format(FormatStr, ...)</nametext></name> <fsummary>Create an Erlang term.</fsummary> <type> <v>char *FormatStr;</v> @@ -81,7 +81,7 @@ erl_format("[{name,~a},{age,~i},{data,~w}]", </func> <func> - <name><ret>int</ret><nametext>erl_match(Pattern, Term)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_match(Pattern, Term)</nametext></name> <fsummary>Perform pattern matching.</fsummary> <type> <v>ETERM *Pattern,*Term;</v> diff --git a/lib/erl_interface/doc/src/erl_global.xml b/lib/erl_interface/doc/src/erl_global.xml index 2fa0045adf..72d43e81d5 100644 --- a/lib/erl_interface/doc/src/erl_global.xml +++ b/lib/erl_interface/doc/src/erl_global.xml @@ -48,7 +48,7 @@ <funcs> <func> - <name><ret>char **</ret><nametext>erl_global_names(fd,count)</nametext></name> + <name since=""><ret>char **</ret><nametext>erl_global_names(fd,count)</nametext></name> <fsummary>Obtain list of global names.</fsummary> <type> <v>int fd;</v> @@ -79,7 +79,7 @@ </func> <func> - <name><ret>int</ret><nametext>erl_global_register(fd,name,pid)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_global_register(fd,name,pid)</nametext></name> <fsummary>Register a name in global.</fsummary> <type> <v>int fd;</v> @@ -103,7 +103,7 @@ </func> <func> - <name><ret>int</ret><nametext>erl_global_unregister(fd,name)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_global_unregister(fd,name)</nametext></name> <fsummary>Unregister a name from global.</fsummary> <type> <v>int fd;</v> @@ -122,7 +122,7 @@ </func> <func> - <name><ret>ETERM *</ret><nametext>erl_global_whereis(fd,name,node)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_global_whereis(fd,name,node)</nametext></name> <fsummary>Look up a name in global.</fsummary> <type> <v>int fd;</v> diff --git a/lib/erl_interface/doc/src/erl_malloc.xml b/lib/erl_interface/doc/src/erl_malloc.xml index c0eebc29e9..aae3b7e078 100644 --- a/lib/erl_interface/doc/src/erl_malloc.xml +++ b/lib/erl_interface/doc/src/erl_malloc.xml @@ -41,7 +41,7 @@ <funcs> <func> - <name><ret>ETERM *</ret><nametext>erl_alloc_eterm(etype)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_alloc_eterm(etype)</nametext></name> <fsummary>Allocate an ETERM structure.</fsummary> <type> <v>unsigned char etype;</v> @@ -89,7 +89,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_eterm_release(void)</nametext></name> + <name since=""><ret>void</ret><nametext>erl_eterm_release(void)</nametext></name> <fsummary>Clear the ETERM freelist.</fsummary> <desc> <p>Clears the freelist, where blocks are placed when they are @@ -99,7 +99,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_eterm_statistics(allocated, freed)</nametext></name> + <name since=""><ret>void</ret><nametext>erl_eterm_statistics(allocated, freed)</nametext></name> <fsummary>Report term allocation statistics.</fsummary> <type> <v>long *allocated;</v> @@ -127,7 +127,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_free(ptr)</nametext></name> + <name since=""><ret>void</ret><nametext>erl_free(ptr)</nametext></name> <fsummary>Free some memory.</fsummary> <type> <v>void *ptr;</v> @@ -139,7 +139,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_free_array(array, size)</nametext></name> + <name since=""><ret>void</ret><nametext>erl_free_array(array, size)</nametext></name> <fsummary>Free an array of ETERM structures.</fsummary> <type> <v>ETERM **array;</v> @@ -156,7 +156,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_free_compound(t)</nametext></name> + <name since=""><ret>void</ret><nametext>erl_free_compound(t)</nametext></name> <fsummary>Free an array of ETERM structures.</fsummary> <type> <v>ETERM *t;</v> @@ -179,7 +179,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_free_term(t)</nametext></name> + <name since=""><ret>void</ret><nametext>erl_free_term(t)</nametext></name> <fsummary>Free an ETERM structure.</fsummary> <type> <v>ETERM *t;</v> @@ -190,7 +190,7 @@ </func> <func> - <name><ret>void</ret><nametext>erl_malloc(size)</nametext></name> + <name since=""><ret>void</ret><nametext>erl_malloc(size)</nametext></name> <fsummary>Allocate some memory.</fsummary> <type> <v>long size;</v> diff --git a/lib/erl_interface/doc/src/erl_marshal.xml b/lib/erl_interface/doc/src/erl_marshal.xml index 2ad658f78b..1a6d3bb43c 100644 --- a/lib/erl_interface/doc/src/erl_marshal.xml +++ b/lib/erl_interface/doc/src/erl_marshal.xml @@ -42,7 +42,7 @@ <funcs> <func> - <name><ret>int</ret><nametext>erl_compare_ext(bufp1, bufp2)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_compare_ext(bufp1, bufp2)</nametext></name> <fsummary>Compare encoded byte sequences.</fsummary> <type> <v>unsigned char *bufp1,*bufp2;</v> @@ -62,8 +62,8 @@ </func> <func> - <name><ret>ETERM *</ret><nametext>erl_decode(bufp)</nametext></name> - <name><ret>ETERM *</ret><nametext>erl_decode_buf(bufpp)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_decode(bufp)</nametext></name> + <name since=""><ret>ETERM *</ret><nametext>erl_decode_buf(bufpp)</nametext></name> <fsummary>Convert a term from Erlang external format.</fsummary> <type> <v>unsigned char *bufp;</v> @@ -102,8 +102,8 @@ </func> <func> - <name><ret>int</ret><nametext>erl_encode(term, bufp)</nametext></name> - <name><ret>int</ret><nametext>erl_encode_buf(term, bufpp)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_encode(term, bufp)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_encode_buf(term, bufpp)</nametext></name> <fsummary>Convert a term into Erlang external format.</fsummary> <type> <v>ETERM *term;</v> @@ -179,7 +179,7 @@ </func> <func> - <name><ret>int</ret><nametext>erl_ext_size(bufp)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_ext_size(bufp)</nametext></name> <fsummary>Count elements in encoded term.</fsummary> <type> <v>unsigned char *bufp;</v> @@ -190,7 +190,7 @@ </func> <func> - <name><ret>unsigned char</ret><nametext>erl_ext_type(bufp)</nametext></name> + <name since=""><ret>unsigned char</ret><nametext>erl_ext_type(bufp)</nametext></name> <fsummary>Determine type of an encoded byte sequence.</fsummary> <type> <v>unsigned char *bufp;</v> @@ -228,7 +228,7 @@ </func> <func> - <name><ret>unsigned char *</ret><nametext>erl_peek_ext(bufp, pos)</nametext></name> + <name since=""><ret>unsigned char *</ret><nametext>erl_peek_ext(bufp, pos)</nametext></name> <fsummary>Step over encoded term.</fsummary> <type> <v>unsigned char *bufp;</v> @@ -252,7 +252,7 @@ </func> <func> - <name><ret>int</ret><nametext>erl_term_len(t)</nametext></name> + <name since=""><ret>int</ret><nametext>erl_term_len(t)</nametext></name> <fsummary>Determine encoded size of term.</fsummary> <type> <v>ETERM *t;</v> diff --git a/lib/erl_interface/doc/src/registry.xml b/lib/erl_interface/doc/src/registry.xml index 6d70fb3475..1c90c5c9dd 100644 --- a/lib/erl_interface/doc/src/registry.xml +++ b/lib/erl_interface/doc/src/registry.xml @@ -44,7 +44,7 @@ <funcs> <func> - <name><ret>int</ret><nametext>ei_reg_close(reg)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_close(reg)</nametext></name> <fsummary>Close a registry.</fsummary> <type> <v>ei_reg *reg;</v> @@ -59,7 +59,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_delete(reg,key)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_delete(reg,key)</nametext></name> <fsummary>Delete an object from the registry.</fsummary> <type> <v>ei_reg *reg;</v> @@ -85,7 +85,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_dump(fd,reg,mntab,flags)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_dump(fd,reg,mntab,flags)</nametext></name> <fsummary>Back up a registry to Mnesia.</fsummary> <type> <v>int fd;</v> @@ -125,7 +125,7 @@ </func> <func> - <name><ret>double</ret><nametext>ei_reg_getfval(reg,key)</nametext></name> + <name since=""><ret>double</ret><nametext>ei_reg_getfval(reg,key)</nametext></name> <fsummary>Get a floating point object.</fsummary> <type> <v>ei_reg *reg;</v> @@ -151,7 +151,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_getival(reg,key)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_getival(reg,key)</nametext></name> <fsummary>Get an integer object.</fsummary> <type> <v>ei_reg *reg;</v> @@ -177,7 +177,7 @@ </func> <func> - <name><ret>const void *</ret><nametext>ei_reg_getpval(reg,key,size)</nametext></name> + <name since=""><ret>const void *</ret><nametext>ei_reg_getpval(reg,key,size)</nametext></name> <fsummary>Get a binary object.</fsummary> <type> <v>ei_reg *reg;</v> @@ -207,7 +207,7 @@ </func> <func> - <name><ret>const char *</ret><nametext>ei_reg_getsval(reg,key)</nametext></name> + <name since=""><ret>const char *</ret><nametext>ei_reg_getsval(reg,key)</nametext></name> <fsummary>Get a string object.</fsummary> <type> <v>ei_reg *reg;</v> @@ -232,7 +232,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_getval(reg,key,flags,v,...)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_getval(reg,key,flags,v,...)</nametext></name> <fsummary>Get any object.</fsummary> <type> <v>ei_reg *reg;</v> @@ -278,7 +278,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_markdirty(reg,key)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_markdirty(reg,key)</nametext></name> <fsummary>Mark an object as dirty.</fsummary> <type> <v>ei_reg *reg;</v> @@ -305,7 +305,7 @@ </func> <func> - <name><ret>ei_reg *</ret><nametext>ei_reg_open(size)</nametext></name> + <name since=""><ret>ei_reg *</ret><nametext>ei_reg_open(size)</nametext></name> <fsummary>Create and open a registry.</fsummary> <type> <v>int size;</v> @@ -326,7 +326,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_purge(reg)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_purge(reg)</nametext></name> <fsummary>Remove deleted objects.</fsummary> <type> <v>ei_reg *reg;</v> @@ -346,7 +346,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_resize(reg,newsize)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_resize(reg,newsize)</nametext></name> <fsummary>Resize a registry.</fsummary> <type> <v>ei_reg *reg;</v> @@ -363,7 +363,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_restore(fd,reg,mntab)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_restore(fd,reg,mntab)</nametext></name> <fsummary>Restore a registry from Mnesia.</fsummary> <type> <v>int fd;</v> @@ -399,7 +399,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_setfval(reg,key,f)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_setfval(reg,key,f)</nametext></name> <fsummary>Assign a floating point object.</fsummary> <type> <v>ei_reg *reg;</v> @@ -424,7 +424,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_setival(reg,key,i)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_setival(reg,key,i)</nametext></name> <fsummary>Assign an integer object.</fsummary> <type> <v>ei_reg *reg;</v> @@ -448,7 +448,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_setpval(reg,key,p,size)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_setpval(reg,key,p,size)</nametext></name> <fsummary>Assign a binary object.</fsummary> <type> <v>ei_reg *reg;</v> @@ -479,7 +479,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_setsval(reg,key,s)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_setsval(reg,key,s)</nametext></name> <fsummary>Assign a string object.</fsummary> <type> <v>ei_reg *reg;</v> @@ -507,7 +507,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_setval(reg,key,flags,v,...)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_setval(reg,key,flags,v,...)</nametext></name> <fsummary>Assign a value to any object type.</fsummary> <type> <v>ei_reg *reg;</v> @@ -552,7 +552,7 @@ </func> <func> - <name><ret>int</ret><nametext>ei_reg_stat(reg,key,obuf)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_stat(reg,key,obuf)</nametext></name> <fsummary>Get object information.</fsummary> <type> <v>ei_reg *reg;</v> @@ -590,7 +590,7 @@ struct ei_reg_stat { </func> <func> - <name><ret>int</ret><nametext>ei_reg_tabstat(reg,obuf)</nametext></name> + <name since=""><ret>int</ret><nametext>ei_reg_tabstat(reg,obuf)</nametext></name> <fsummary>Get registry information.</fsummary> <type> <v>ei_reg *reg;</v> diff --git a/lib/erl_interface/include/ei.h b/lib/erl_interface/include/ei.h index 948f89be85..ca4960b252 100644 --- a/lib/erl_interface/include/ei.h +++ b/lib/erl_interface/include/ei.h @@ -35,6 +35,9 @@ #include <winsock2.h> #include <windows.h> #include <winbase.h> +typedef LONG_PTR ssize_t; /* Sigh... */ +#else +#include <sys/types.h> /* ssize_t */ #endif #include <stdio.h> /* Need type FILE */ @@ -286,6 +289,31 @@ typedef struct { char nodename[MAXNODELEN+1]; } ErlConnect; +#define EI_SCLBK_INF_TMO (~((unsigned) 0)) + +#define EI_SCLBK_FLG_FULL_IMPL (1 << 0) + +typedef struct { + int flags; + + int (*socket)(void **ctx, void *setup_ctx); + int (*close)(void *ctx); + int (*listen)(void *ctx, void *addr, int *len, int backlog); + int (*accept)(void **ctx, void *addr, int *len, unsigned tmo); + int (*connect)(void *ctx, void *addr, int len, unsigned tmo); + int (*writev)(void *ctx, const void *iov, int iovcnt, ssize_t *len, unsigned tmo); + int (*write)(void *ctx, const char *buf, ssize_t *len, unsigned tmo); + int (*read)(void *ctx, char *buf, ssize_t *len, unsigned tmo); + + int (*handshake_packet_header_size)(void *ctx, int *sz); + int (*connect_handshake_complete)(void *ctx); + int (*accept_handshake_complete)(void *ctx); + int (*get_fd)(void *ctx, int *fd); + + /* end of version 1 */ + +} ei_socket_callbacks; + typedef struct ei_cnode_s { char thishostname[EI_MAXHOSTNAMELEN+1]; char thisnodename[MAXNODELEN+1]; @@ -295,6 +323,8 @@ typedef struct ei_cnode_s { char ei_connect_cookie[EI_MAX_COOKIE_SIZE+1]; short creation; erlang_pid self; + ei_socket_callbacks *cbs; + void *setup_context; } ei_cnode; typedef struct in_addr *Erl_IpAddr; @@ -308,7 +338,6 @@ typedef struct ei_x_buff_TAG { int index; } ei_x_buff; - /* -------------------------------------------------------------------- */ /* Function definitions (listed in same order as documentation) */ /* -------------------------------------------------------------------- */ @@ -322,6 +351,16 @@ int ei_connect_xinit (ei_cnode* ec, const char *thishostname, Erl_IpAddr thisipaddr, const char *cookie, const short creation); +int ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name, + const char *cookie, short creation, + ei_socket_callbacks *cbs, int cbs_sz, + void *setup_context); +int ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname, + const char *thisalivename, const char *thisnodename, + Erl_IpAddr thisipaddr, const char *cookie, + const short creation, ei_socket_callbacks *cbs, + int cbs_sz, void *setup_context); + int ei_connect(ei_cnode* ec, char *nodename); int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms); int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename); @@ -348,11 +387,15 @@ int ei_rpc_from(ei_cnode* ec, int fd, int timeout, erlang_msg* msg, int ei_publish(ei_cnode* ec, int port); int ei_publish_tmo(ei_cnode* ec, int port, unsigned ms); +int ei_listen(ei_cnode *ec, int *port, int backlog); +int ei_xlisten(ei_cnode *ec, Erl_IpAddr adr, int *port, int backlog); int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp); int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms); int ei_unpublish(ei_cnode* ec); int ei_unpublish_tmo(const char *alive, unsigned ms); +int ei_close_connection(int fd); + const char *ei_thisnodename(const ei_cnode* ec); const char *ei_thishostname(const ei_cnode* ec); const char *ei_thisalivename(const ei_cnode* ec); @@ -626,6 +669,8 @@ struct ei_reg_tabstat { }; +int ei_init(void); + /* -------------------------------------------------------------------- */ /* XXXXXXXXXXX */ /* -------------------------------------------------------------------- */ diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in index 614e7325a9..b0bb9bfadf 100644 --- a/lib/erl_interface/src/Makefile.in +++ b/lib/erl_interface/src/Makefile.in @@ -31,12 +31,11 @@ .PHONY : debug opt release clean distclean depend -TARGET = @TARGET@ - # ---------------------------------------------------- # Application version and release dir specification # ---------------------------------------------------- include ../vsn.mk +include $(ERL_TOP)/make/target.mk include $(TARGET)/eidefs.mk include $(ERL_TOP)/make/output.mk @@ -417,7 +416,8 @@ MISCSRC = \ misc/eimd5.c \ misc/get_type.c \ misc/show_msg.c \ - misc/ei_compat.c + misc/ei_compat.c \ + misc/ei_init.c REGISTRYSRC = \ registry/hash_dohash.c \ diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c index 9df4fa3b6c..7a304e6d4f 100644 --- a/lib/erl_interface/src/connect/ei_connect.c +++ b/lib/erl_interface/src/connect/ei_connect.c @@ -42,10 +42,8 @@ #include <inetLib.h> #include <unistd.h> -#include <sys/types.h> #include <sys/times.h> #include <unistd.h> -#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> @@ -55,7 +53,6 @@ #else /* some other unix */ #include <unistd.h> -#include <sys/types.h> #include <sys/times.h> #if TIME_WITH_SYS_TIME @@ -84,6 +81,7 @@ #include <string.h> #include <errno.h> #include <ctype.h> +#include <stddef.h> #include "eiext.h" #include "ei_portio.h" @@ -98,11 +96,16 @@ #include "ei_epmd.h" #include "ei_internal.h" +static int ei_connect_initialized = 0; int ei_tracelevel = 0; #define COOKIE_FILE "/.erlang.cookie" #define EI_MAX_HOME_PATH 1024 +#define EI_SOCKET_CALLBACKS_SZ_V1 \ + (offsetof(ei_socket_callbacks, get_fd) \ + + sizeof(int (*)(void *))) + /* FIXME why not macro? */ static char *null_cookie = ""; @@ -113,35 +116,51 @@ static int get_home(char *buf, int size); static unsigned gen_challenge(void); static void gen_digest(unsigned challenge, char cookie[], unsigned char digest[16]); -static int send_status(int fd, char *status, unsigned ms); -static int recv_status(int fd, unsigned ms); -static int send_challenge(int fd, char *nodename, - unsigned challenge, unsigned version, unsigned ms); -static int recv_challenge(int fd, unsigned *challenge, - unsigned *version, - unsigned *flags, ErlConnect *namebuf, unsigned ms); -static int send_challenge_reply(int fd, unsigned char digest[16], +static int send_status(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, char *status, unsigned ms); +static int recv_status(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned ms); +static int send_challenge(ei_socket_callbacks *cbs, void *ctx, int pkt_sz, + char *nodename, unsigned challenge, + unsigned version, unsigned ms); +static int recv_challenge(ei_socket_callbacks *cbs, void *ctx, int pkt_sz, + unsigned *challenge, unsigned *version, + unsigned *flags, char *namebuf, unsigned ms); +static int send_challenge_reply(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned char digest[16], unsigned challenge, unsigned ms); -static int recv_challenge_reply(int fd, - unsigned our_challenge, +static int recv_challenge_reply(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned our_challenge, char cookie[], unsigned *her_challenge, unsigned ms); -static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms); -static int recv_challenge_ack(int fd, - unsigned our_challenge, +static int send_challenge_ack(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned char digest[16], + unsigned ms); +static int recv_challenge_ack(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned our_challenge, char cookie[], unsigned ms); -static int send_name(int fd, char *nodename, - unsigned version, unsigned ms); +static int send_name(ei_socket_callbacks *cbs, void *ctx, int pkt_sz, + char *nodename, unsigned version, unsigned ms); -/* Common for both handshake types */ -static int recv_name(int fd, - unsigned *version, - unsigned *flags, ErlConnect *namebuf, unsigned ms); +static int recv_name(ei_socket_callbacks *cbs, void *ctx, int pkt_sz, + unsigned *version, unsigned *flags, char *namebuf, + unsigned ms); static struct hostent* dyn_gethostbyname_r(const char *name, struct hostent *hostp, char **buffer_p, int buflen, int *h_errnop); +static void abort_connection(ei_socket_callbacks *cbs, void *ctx); +static int close_connection(ei_socket_callbacks *cbs, void *ctx, int fd); + +static char * +estr(int e) +{ + char *str = strerror(e); + if (!str) + return "unknown error"; + return str; +} /*************************************************************************** @@ -154,25 +173,208 @@ dyn_gethostbyname_r(const char *name, struct hostent *hostp, char **buffer_p, typedef struct ei_socket_info_s { int socket; + ei_socket_callbacks *cbs; + void *ctx; int dist_version; ei_cnode cnode; /* A copy, not a pointer. We don't know when freed */ char cookie[EI_MAX_COOKIE_SIZE+1]; } ei_socket_info; +/*************************************************************************** + * + * XXX + * + ***************************************************************************/ + +#ifndef ETHR_HAVE___atomic_compare_exchange_n +# define ETHR_HAVE___atomic_compare_exchange_n 0 +#endif +#ifndef ETHR_HAVE___atomic_load_n +# define ETHR_HAVE___atomic_load_n 0 +#endif +#ifndef ETHR_HAVE___atomic_store_n +# define ETHR_HAVE___atomic_store_n 0 +#endif + +#if defined(_REENTRANT) \ + && (!(ETHR_HAVE___atomic_compare_exchange_n & SIZEOF_VOID_P) \ + || !(ETHR_HAVE___atomic_load_n & SIZEOF_VOID_P) \ + || !(ETHR_HAVE___atomic_store_n & SIZEOF_VOID_P)) +# undef EI_DISABLE_SEQ_SOCKET_INFO +# define EI_DISABLE_SEQ_SOCKET_INFO +#endif + +#ifdef __WIN32__ +# undef EI_DISABLE_SEQ_SOCKET_INFO +# define EI_DISABLE_SEQ_SOCKET_INFO +#endif + +#ifndef EI_DISABLE_SEQ_SOCKET_INFO + +#ifdef _REENTRANT + +#define EI_ATOMIC_CMPXCHG_ACQ_REL(VARP, XCHGP, NEW) \ + __atomic_compare_exchange_n((VARP), (XCHGP), (NEW), 0, \ + __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE) +#define EI_ATOMIC_LOAD_ACQ(VARP) \ + __atomic_load_n((VARP), __ATOMIC_ACQUIRE) +#define EI_ATOMIC_STORE_REL(VARP, NEW) \ + __atomic_store_n((VARP), (NEW), __ATOMIC_RELEASE) + +#else /* ! _REENTRANT */ + +#define EI_ATOMIC_CMPXCHG_ACQ_REL(VARP, XCHGP, NEW) \ + (*(VARP) == *(XCHGP) \ + ? ((*(VARP) = (NEW)), !0) \ + : ((*(XCHGP) = *(VARP)), 0)) +#define EI_ATOMIC_LOAD_ACQ(VARP) (*(VARP)) +#define EI_ATOMIC_STORE_REL(VARP, NEW) (*(VARP) = (NEW)) + +#endif /* ! _REENTRANT */ + +#define EI_SOCKET_INFO_SEG_BITS 5 +#define EI_SOCKET_INFO_SEG_SIZE (1 << EI_SOCKET_INFO_SEG_BITS) +#define EI_SOCKET_INFO_SEG_MASK (EI_SOCKET_INFO_SEG_SIZE - 1) + +typedef struct { + int max_fds; + ei_socket_info *segments[1]; /* Larger in reality... */ +} ei_socket_info_data__; + +static ei_socket_info_data__ *socket_info_data = NULL; + +static int init_socket_info(int late) +{ + int max_fds; + int i; + size_t segments_len; + ei_socket_info_data__ *info_data, *xchg; + + if (EI_ATOMIC_LOAD_ACQ(&socket_info_data) != NULL) + return 0; /* Already initialized... */ + +#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) + max_fds = sysconf(_SC_OPEN_MAX); +#else + max_fds = 1024; +#endif + + if (max_fds < 0) + return EIO; + + segments_len = ((max_fds-1)/EI_SOCKET_INFO_SEG_SIZE + 1); + + info_data = malloc(sizeof(ei_socket_info_data__) + + (sizeof(ei_socket_info *)*(segments_len-1))); + if (!info_data) + return ENOMEM; + + info_data->max_fds = max_fds; + for (i = 0; i < segments_len; i++) + info_data->segments[i] = NULL; + + xchg = NULL; + if (!EI_ATOMIC_CMPXCHG_ACQ_REL(&socket_info_data, &xchg, info_data)) + free(info_data); /* Already initialized... */ + + return 0; +} + +static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec, + ei_socket_callbacks *cbs, void *ctx) +{ + int six; + ei_socket_info *seg, *si; + int socket; + + if (fd < 0 || socket_info_data->max_fds <= fd) + return -1; + + socket = fd; + six = fd >> EI_SOCKET_INFO_SEG_BITS; + seg = EI_ATOMIC_LOAD_ACQ(&socket_info_data->segments[six]); + + if (!seg) { + ei_socket_info *xchg; + int i; + seg = malloc(sizeof(ei_socket_info)*EI_SOCKET_INFO_SEG_SIZE); + if (!seg) + return -1; + for (i = 0; i < EI_SOCKET_INFO_SEG_SIZE; i++) { + seg[i].socket = -1; + } + + xchg = NULL; + if (!EI_ATOMIC_CMPXCHG_ACQ_REL(&socket_info_data->segments[six], &xchg, seg)) { + free(seg); + seg = xchg; + } + } + + si = &seg[fd & EI_SOCKET_INFO_SEG_MASK]; + + if (dist_version < 0) { + socket = -1; + si->cbs = NULL; + si->ctx = NULL; + } + else { + si->dist_version = dist_version; + si->cnode = *ec; + si->cbs = cbs; + si->ctx = ctx; + strcpy(si->cookie, cookie); + } + + EI_ATOMIC_STORE_REL(&si->socket, socket); + + return 0; +} + +static ei_socket_info* get_ei_socket_info(int fd) +{ + int six, socket; + ei_socket_info *seg, *si; + + if (fd < 0 || socket_info_data->max_fds <= fd) + return NULL; + + six = fd >> EI_SOCKET_INFO_SEG_BITS; + seg = EI_ATOMIC_LOAD_ACQ(&socket_info_data->segments[six]); + + if (!seg) + return NULL; + + si = &seg[fd & EI_SOCKET_INFO_SEG_MASK]; + socket = EI_ATOMIC_LOAD_ACQ(&si->socket); + if (socket != fd) + return NULL; + return si; +} + +#else /* EI_DISABLE_SEQ_SOCKET_INFO */ + int ei_n_sockets = 0, ei_sz_sockets = 0; ei_socket_info *ei_sockets = NULL; + #ifdef _REENTRANT ei_mutex_t* ei_sockets_lock = NULL; #endif /* _REENTRANT */ +static int init_socket_info(int late) +{ +#ifdef _REENTRANT + if (late) + return ENOTSUP; /* Refuse doing unsafe initialization... */ + ei_sockets_lock = ei_mutex_create(); + if (!ei_sockets_lock) + return ENOMEM; +#endif /* _REENTRANT */ + return 0; +} -/*************************************************************************** - * - * XXX - * - ***************************************************************************/ - -static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec) +static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec, + ei_socket_callbacks *cbs, void *ctx) { int i; @@ -182,11 +384,13 @@ static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode * for (i = 0; i < ei_n_sockets; ++i) { if (ei_sockets[i].socket == fd) { if (dist_version == -1) { - memmove(&ei_sockets[i], &ei_sockets[i+1], + memmove(&ei_sockets[i], &ei_sockets[i+1], sizeof(ei_sockets[0])*(ei_n_sockets-i-1)); } else { ei_sockets[i].dist_version = dist_version; /* Copy the content, see ei_socket_info */ + ei_sockets[i].cbs = cbs; + ei_sockets[i].ctx = ctx; ei_sockets[i].cnode = *ec; strcpy(ei_sockets[i].cookie, cookie); } @@ -209,7 +413,9 @@ static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode * } ei_sockets[ei_n_sockets].socket = fd; ei_sockets[ei_n_sockets].dist_version = dist_version; - ei_sockets[i].cnode = *ec; + ei_sockets[ei_n_sockets].cnode = *ec; + ei_sockets[ei_n_sockets].cbs = cbs; + ei_sockets[ei_n_sockets].ctx = ctx; strcpy(ei_sockets[ei_n_sockets].cookie, cookie); ++ei_n_sockets; } @@ -219,14 +425,6 @@ static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode * return 0; } -#if 0 -/* FIXME not used ?! */ -static int remove_ei_socket_info(int fd, int dist_version, char* cookie) -{ - return put_ei_socket_info(fd, -1, NULL); -} -#endif - static ei_socket_info* get_ei_socket_info(int fd) { int i; @@ -248,6 +446,13 @@ static ei_socket_info* get_ei_socket_info(int fd) return NULL; } +#endif /* EI_DISABLE_SEQ_SOCKET_INFO */ + +static int remove_ei_socket_info(int fd) +{ + return put_ei_socket_info(fd, -1, NULL, NULL, NULL, NULL); +} + ei_cnode *ei_fd_to_cnode(int fd) { ei_socket_info *sockinfo = get_ei_socket_info(fd); @@ -255,6 +460,19 @@ ei_cnode *ei_fd_to_cnode(int fd) return &sockinfo->cnode; } +int ei_get_cbs_ctx__(ei_socket_callbacks **cbs, void **ctx, int fd) +{ + ei_socket_info *sockinfo = get_ei_socket_info(fd); + if (sockinfo) { + *cbs = sockinfo->cbs; + *ctx = sockinfo->ctx; + return 0; + } + + *cbs = NULL; + *ctx = NULL; + return EBADF; +} /*************************************************************************** * Get/Set tracelevel @@ -333,21 +551,6 @@ const char *ei_getfdcookie(int fd) return r; } -/* call with cookie to set value to use on descriptor fd, -* or specify NULL to use default -*/ -/* FIXME why defined but not used? */ -#if 0 -static int ei_setfdcookie(ei_cnode* ec, int fd, char *cookie) -{ - int dist_version = ei_distversion(fd); - - if (cookie == NULL) - cookie = ec->ei_connect_cookie; - return put_ei_socket_info(fd, dist_version, cookie); -} -#endif - static int get_int32(unsigned char *s) { return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] )); @@ -400,34 +603,62 @@ static int initWinSock(void) } #endif +static int init_connect(int late) +{ + int error; + + /* + * 'late' is non-zero when not called via ei_init(). Such a + * call is not supported, but we for now save the day if + * it easy to do so; otherwise, return ENOTSUP. + */ + +#ifdef __WIN32__ + if (!initWinSock()) { + EI_TRACE_ERR0("ei_init_connect","can't initiate winsock"); + return EIO; + } +#endif /* win32 */ + + error = init_socket_info(late); + if (error) { + EI_TRACE_ERR0("ei_init_connect","can't initiate socket info"); + return error; + } + + ei_connect_initialized = !0; + return 0; +} + +int ei_init_connect(void) +{ + return init_connect(0); +} + /* * Perhaps run this routine instead of ei_connect_init/2 ? * Initailize by setting: * thishostname, thisalivename, thisnodename and thisipaddr */ -int ei_connect_xinit(ei_cnode* ec, const char *thishostname, - const char *thisalivename, const char *thisnodename, - Erl_IpAddr thisipaddr, const char *cookie, - const short creation) +int ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname, + const char *thisalivename, const char *thisnodename, + Erl_IpAddr thisipaddr, const char *cookie, + const short creation, ei_socket_callbacks *cbs, + int cbs_sz, void *setup_context) { char *dbglevel; - -/* FIXME this code was enabled for 'erl'_connect_xinit(), why not here? */ -#if 0 -#ifdef __WIN32__ - if (!initWinSock()) { - EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock"); - return ERL_ERROR; - } -#endif -#endif -#ifdef _REENTRANT - if (ei_sockets_lock == NULL) { - ei_sockets_lock = ei_mutex_create(); - } -#endif /* _REENTRANT */ + if (!ei_connect_initialized) + init_connect(!0); + if (cbs != &ei_default_socket_callbacks) + EI_SET_HAVE_PLUGIN_SOCKET_IMPL__; + + if (cbs_sz < EI_SOCKET_CALLBACKS_SZ_V1) { + EI_TRACE_ERR0("ei_connect_xinit","invalid size of ei_socket_callbacks struct"); + return ERL_ERROR; + } + ec->creation = creation & 0x3; /* 2 bits */ if (cookie) { @@ -469,6 +700,9 @@ int ei_connect_xinit(ei_cnode* ec, const char *thishostname, ec->self.serial = 0; ec->self.creation = creation & 0x3; /* 2 bits */ + ec->cbs = cbs; + ec->setup_context = setup_context; + if ((dbglevel = getenv("EI_TRACELEVEL")) != NULL || (dbglevel = getenv("ERL_DEBUG_DIST")) != NULL) ei_tracelevel = atoi(dbglevel); @@ -476,14 +710,27 @@ int ei_connect_xinit(ei_cnode* ec, const char *thishostname, return 0; } +int ei_connect_xinit(ei_cnode* ec, const char *thishostname, + const char *thisalivename, const char *thisnodename, + Erl_IpAddr thisipaddr, const char *cookie, + const short creation) +{ + return ei_connect_xinit_ussi(ec, thishostname, thisalivename, thisnodename, + thisipaddr, cookie, creation, + &ei_default_socket_callbacks, + sizeof(ei_default_socket_callbacks), + NULL); +} /* * Initialize by set: thishostname, thisalivename, * thisnodename and thisipaddr. At success return 0, * otherwise return -1. */ -int ei_connect_init(ei_cnode* ec, const char* this_node_name, - const char *cookie, short creation) +int ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name, + const char *cookie, short creation, + ei_socket_callbacks *cbs, int cbs_sz, + void *setup_context) { char thishostname[EI_MAXHOSTNAMELEN+1]; char thisnodename[MAXNODELEN+1]; @@ -494,17 +741,8 @@ int ei_connect_init(ei_cnode* ec, const char* this_node_name, int ei_h_errno; int res; -#ifdef __WIN32__ - if (!initWinSock()) { - EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock"); - return ERL_ERROR; - } -#endif /* win32 */ -#ifdef _REENTRANT - if (ei_sockets_lock == NULL) { - ei_sockets_lock = ei_mutex_create(); - } -#endif /* _REENTRANT */ + if (!ei_connect_initialized) + init_connect(!0); /* gethostname requires len to be max(hostname) + 1 */ if (gethostname(thishostname, EI_MAXHOSTNAMELEN+1) == -1) { @@ -561,43 +799,22 @@ int ei_connect_init(ei_cnode* ec, const char* this_node_name, sprintf(thisnodename, "%s@%s", this_node_name, hp->h_name); } } - res = ei_connect_xinit(ec, thishostname, thisalivename, thisnodename, - (struct in_addr *)*hp->h_addr_list, cookie, creation); + res = ei_connect_xinit_ussi(ec, thishostname, thisalivename, thisnodename, + (struct in_addr *)*hp->h_addr_list, cookie, creation, + cbs, cbs_sz, setup_context); if (buf != buffer) free(buf); return res; } - -/* connects to port at ip-address ip_addr -* and returns fd to socket -* port has to be in host byte order -*/ -static int cnct(uint16 port, struct in_addr *ip_addr, int addr_len, unsigned ms) +int ei_connect_init(ei_cnode* ec, const char* this_node_name, + const char *cookie, short creation) { - int s, res; - struct sockaddr_in iserv_addr; - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - erl_errno = errno; - return ERL_ERROR; - } - - memset((char*)&iserv_addr, 0, sizeof(struct sockaddr_in)); - memcpy((char*)&iserv_addr.sin_addr, (char*)ip_addr, addr_len); - iserv_addr.sin_family = AF_INET; - iserv_addr.sin_port = htons(port); - - if ((res = ei_connect_t(s, (struct sockaddr*)&iserv_addr, - sizeof(iserv_addr),ms)) < 0) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - closesocket(s); - return ERL_ERROR; - } - - return s; -} /* cnct */ - + return ei_connect_init_ussi(ec, this_node_name, cookie, creation, + &ei_default_socket_callbacks, + sizeof(ei_default_socket_callbacks), + NULL); +} /* * Same as ei_gethostbyname_r, but also handles ERANGE error @@ -758,91 +975,218 @@ int ei_connect(ei_cnode* ec, char *nodename) * the node through epmd at that host * */ -int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned ms) +int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr ip_addr, char *alivename, unsigned ms) { - struct in_addr *ip_addr=(struct in_addr *) adr; + ei_socket_callbacks *cbs = ec->cbs; + void *ctx; int rport = 0; /*uint16 rport = 0;*/ int sockd; - int one = 1; int dist = 0; - ErlConnect her_name; unsigned her_flags, her_version; - + unsigned our_challenge, her_challenge; + unsigned char our_digest[16]; + int err; + int pkt_sz; + struct sockaddr_in addr; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; + erl_errno = EIO; /* Default error code */ EI_TRACE_CONN1("ei_xconnect","-> CONNECT attempt to connect to %s", alivename); - if ((rport = ei_epmd_port_tmo(ip_addr,alivename,&dist, ms)) < 0) { + if ((rport = ei_epmd_port_tmo(ip_addr,alivename,&dist, tmo)) < 0) { EI_TRACE_ERR0("ei_xconnect","-> CONNECT can't get remote port"); /* ei_epmd_port_tmo() has set erl_errno */ return ERL_NO_PORT; } - - /* we now have port number to enode, try to connect */ - if((sockd = cnct((uint16)rport, ip_addr, sizeof(struct in_addr),ms)) < 0) { - EI_TRACE_ERR0("ei_xconnect","-> CONNECT socket connect failed"); - /* cnct() has set erl_errno */ - return ERL_CONNECT_FAIL; - } - - EI_TRACE_CONN0("ei_xconnect","-> CONNECT connected to remote"); - /* FIXME why connect before checking 'dist' output from ei_epmd_port() ?! */ if (dist <= 4) { EI_TRACE_ERR0("ei_xconnect","-> CONNECT remote version not compatible"); - goto error; + return ERL_ERROR; } - else { - unsigned our_challenge, her_challenge; - unsigned char our_digest[16]; - - if (send_name(sockd, ec->thisnodename, (unsigned) dist, ms)) - goto error; - if (recv_status(sockd, ms)) - goto error; - if (recv_challenge(sockd, &her_challenge, &her_version, - &her_flags, &her_name, ms)) - goto error; - our_challenge = gen_challenge(); - gen_digest(her_challenge, ec->ei_connect_cookie, our_digest); - if (send_challenge_reply(sockd, our_digest, our_challenge, ms)) - goto error; - if (recv_challenge_ack(sockd, our_challenge, - ec->ei_connect_cookie, ms)) - goto error; - put_ei_socket_info(sockd, dist, null_cookie, ec); /* FIXME check == 0 */ + + err = ei_socket_ctx__(cbs, &ctx, ec->setup_context); + if (err) { + EI_TRACE_ERR2("ei_xconnect","-> SOCKET failed: %s (%d)", + estr(err), err); + erl_errno = err; + return ERL_CONNECT_FAIL; + } + + memset((void *) &addr, 0, sizeof(struct sockaddr_in)); + memcpy((void *) &addr.sin_addr, (void *) ip_addr, sizeof(addr.sin_addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(rport); + + err = ei_connect_ctx_t__(cbs, ctx, (void *) &addr, sizeof(addr), tmo); + if (err) { + EI_TRACE_ERR2("ei_xconnect","-> CONNECT socket connect failed: %s (%d)", + estr(err), err); + abort_connection(cbs, ctx); + erl_errno = err; + return ERL_CONNECT_FAIL; } - setsockopt(sockd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)); - setsockopt(sockd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one)); + EI_TRACE_CONN0("ei_xconnect","-> CONNECT connected to remote"); - EI_TRACE_CONN1("ei_xconnect","-> CONNECT (ok) remote = %s",alivename); + err = EI_GET_FD__(cbs, ctx, &sockd); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + goto error; + } + + err = cbs->handshake_packet_header_size(ctx, &pkt_sz); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + goto error; + } + + if (send_name(cbs, ctx, pkt_sz, ec->thisnodename, (unsigned) dist, tmo)) + goto error; + if (recv_status(cbs, ctx, pkt_sz, tmo)) + goto error; + if (recv_challenge(cbs, ctx, pkt_sz, &her_challenge, + &her_version, &her_flags, NULL, tmo)) + goto error; + our_challenge = gen_challenge(); + gen_digest(her_challenge, ec->ei_connect_cookie, our_digest); + if (send_challenge_reply(cbs, ctx, pkt_sz, our_digest, our_challenge, tmo)) + goto error; + if (recv_challenge_ack(cbs, ctx, pkt_sz, our_challenge, + ec->ei_connect_cookie, tmo)) + goto error; + if (put_ei_socket_info(sockd, dist, null_cookie, ec, cbs, ctx) != 0) + goto error; + + if (cbs->connect_handshake_complete) { + err = cbs->connect_handshake_complete(ctx); + if (err) { + EI_TRACE_ERR2("ei_xconnect","-> CONNECT failed: %s (%d)", + estr(err), err); + close_connection(cbs, ctx, sockd); + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } + } + EI_TRACE_CONN1("ei_xconnect","-> CONNECT (ok) remote = %s",alivename); + erl_errno = 0; return sockd; error: EI_TRACE_ERR0("ei_xconnect","-> CONNECT failed"); - closesocket(sockd); + abort_connection(cbs, ctx); return ERL_ERROR; } /* ei_xconnect */ -int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename) +int ei_xconnect(ei_cnode* ec, Erl_IpAddr ip_addr, char *alivename) { - return ei_xconnect_tmo(ec, adr, alivename, 0); + return ei_xconnect_tmo(ec, ip_addr, alivename, 0); } +int ei_listen(ei_cnode *ec, int *port, int backlog) +{ + struct in_addr ip_addr; + ip_addr.s_addr = htonl(INADDR_ANY); + return ei_xlisten(ec, &ip_addr, port, backlog); +} + +int ei_xlisten(ei_cnode *ec, struct in_addr *ip_addr, int *port, int backlog) +{ + ei_socket_callbacks *cbs = ec->cbs; + struct sockaddr_in sock_addr; + void *ctx; + int fd, err, len; + + err = ei_socket_ctx__(cbs, &ctx, ec->setup_context); + if (err) { + EI_TRACE_ERR2("ei_xlisten","-> SOCKET failed: %s (%d)", + estr(err), err); + erl_errno = err; + return ERL_ERROR; + } + + memset((void *) &sock_addr, 0, sizeof(struct sockaddr_in)); + memcpy((void *) &sock_addr.sin_addr, (void *) ip_addr, sizeof(*ip_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = htons((short) *port); + + len = sizeof(sock_addr); + err = ei_listen_ctx__(cbs, ctx, (void *) &sock_addr, &len, backlog); + if (err) { + EI_TRACE_ERR2("ei_xlisten","-> listen failed: %s (%d)", + estr(err), err); + erl_errno = err; + goto error; + } + + if (len != sizeof(sock_addr)) { + if (len < offsetof(struct sockaddr_in, sin_addr) + sizeof(sock_addr.sin_addr) + || len < offsetof(struct sockaddr_in, sin_port) + sizeof(sock_addr.sin_port)) { + erl_errno = EIO; + EI_TRACE_ERR0("ei_xlisten","-> get info failed"); + goto error; + } + } + + memcpy((void *) ip_addr, (void *) &sock_addr.sin_addr, sizeof(*ip_addr)); + *port = (int) ntohs(sock_addr.sin_port); + + err = EI_GET_FD__(cbs, ctx, &fd); + if (err) { + erl_errno = err; + goto error; + } + + if (put_ei_socket_info(fd, 0, null_cookie, ec, cbs, ctx) != 0) { + EI_TRACE_ERR0("ei_xlisten","-> save socket info failed"); + erl_errno = EIO; + goto error; + } + + erl_errno = 0; + + return fd; + +error: + abort_connection(cbs, ctx); + return ERL_ERROR; +} + +static int close_connection(ei_socket_callbacks *cbs, void *ctx, int fd) +{ + int err; + remove_ei_socket_info(fd); + err = ei_close_ctx__(cbs, ctx); + if (err) { + erl_errno = err; + return ERL_ERROR; + } + return 0; +} - /* - * For symmetry reasons -*/ -#if 0 int ei_close_connection(int fd) { - return closesocket(fd); + ei_socket_callbacks *cbs; + void *ctx; + int err = EI_GET_CBS_CTX__(&cbs, &ctx, fd); + if (err) + erl_errno = err; + else { + if (close_connection(cbs, ctx, fd) == 0) + return 0; + } + EI_TRACE_ERR2("ei_close_connection","<- CLOSE socket close failed: %s (%d)", + estr(erl_errno), erl_errno); + return ERL_ERROR; } /* ei_close_connection */ -#endif + +static void abort_connection(ei_socket_callbacks *cbs, void *ctx) +{ + (void) ei_close_ctx__(cbs, ctx); +} /* * Accept and initiate a connection from another @@ -857,25 +1201,71 @@ int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp) int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms) { int fd; - struct sockaddr_in cli_addr; - int cli_addr_len=sizeof(struct sockaddr_in); unsigned her_version, her_flags; - ErlConnect her_name; + char tmp_nodename[MAXNODELEN+1]; + char *her_name; + int pkt_sz, err; + struct sockaddr_in addr; + int addr_len = sizeof(struct sockaddr_in); + ei_socket_callbacks *cbs; + void *ctx; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; erl_errno = EIO; /* Default error code */ + + err = EI_GET_CBS_CTX__(&cbs, &ctx, lfd); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } + EI_TRACE_CONN0("ei_accept","<- ACCEPT waiting for connection"); + + if (conp) { + her_name = &conp->nodename[0]; + } + else { + her_name = &tmp_nodename[0]; + } - if ((fd = ei_accept_t(lfd, (struct sockaddr*) &cli_addr, - &cli_addr_len, ms )) < 0) { - EI_TRACE_ERR0("ei_accept","<- ACCEPT socket accept failed"); - erl_errno = (fd == -2) ? ETIMEDOUT : EIO; - goto error; + /* + * ei_accept_ctx_t__() replaces the pointer to the listen context + * with a pointer to the accepted connection context on success. + */ + err = ei_accept_ctx_t__(cbs, &ctx, (void *) &addr, &addr_len, tmo); + if (err) { + EI_TRACE_ERR2("ei_accept","<- ACCEPT socket accept failed: %s (%d)", + estr(err), err); + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } + + err = EI_GET_FD__(cbs, ctx, &fd); + if (err) { + EI_TRACE_ERR2("ei_accept","<- ACCEPT get fd failed: %s (%d)", + estr(err), err); + EI_CONN_SAVE_ERRNO__(err); + } + + if (addr_len != sizeof(struct sockaddr_in)) { + if (addr_len < (offsetof(struct sockaddr_in, sin_addr) + + sizeof(addr.sin_addr))) { + EI_TRACE_ERR0("ei_accept","<- ACCEPT get addr failed"); + goto error; + } + } + + err = cbs->handshake_packet_header_size(ctx, &pkt_sz); + if (err) { + EI_TRACE_ERR2("ei_accept","<- ACCEPT get packet size failed: %s (%d)", + estr(err), err); + EI_CONN_SAVE_ERRNO__(err); } EI_TRACE_CONN0("ei_accept","<- ACCEPT connected to remote"); - if (recv_name(fd, &her_version, &her_flags, &her_name, ms)) { + if (recv_name(cbs, ctx, pkt_sz, &her_version, &her_flags, her_name, tmo)) { EI_TRACE_ERR0("ei_accept","<- ACCEPT initial ident failed"); goto error; } @@ -888,34 +1278,45 @@ int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms) unsigned our_challenge; unsigned her_challenge; unsigned char our_digest[16]; - - if (send_status(fd,"ok", ms)) + + if (send_status(cbs, ctx, pkt_sz, "ok", tmo)) goto error; our_challenge = gen_challenge(); - if (send_challenge(fd, ec->thisnodename, - our_challenge, her_version, ms)) + if (send_challenge(cbs, ctx, pkt_sz, ec->thisnodename, + our_challenge, her_version, tmo)) goto error; - if (recv_challenge_reply(fd, our_challenge, - ec->ei_connect_cookie, - &her_challenge, ms)) + if (recv_challenge_reply(cbs, ctx, pkt_sz, our_challenge, + ec->ei_connect_cookie, &her_challenge, tmo)) goto error; gen_digest(her_challenge, ec->ei_connect_cookie, our_digest); - if (send_challenge_ack(fd, our_digest, ms)) + if (send_challenge_ack(cbs, ctx, pkt_sz, our_digest, tmo)) goto error; - put_ei_socket_info(fd, her_version, null_cookie, ec); + if (put_ei_socket_info(fd, her_version, null_cookie, ec, cbs, ctx) != 0) + goto error; + } + if (conp) { + memcpy((void *) conp->ipadr, (void *) &addr.sin_addr, sizeof(conp->ipadr)); + } + + if (cbs->accept_handshake_complete) { + err = cbs->accept_handshake_complete(ctx); + if (err) { + EI_TRACE_ERR2("ei_xconnect","-> ACCEPT handshake failed: %s (%d)", + estr(err), err); + close_connection(cbs, ctx, fd); + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } } - if (conp) - *conp = her_name; - EI_TRACE_CONN1("ei_accept","<- ACCEPT (ok) remote = %s",her_name.nodename); + EI_TRACE_CONN1("ei_accept","<- ACCEPT (ok) remote = %s",her_name); erl_errno = 0; /* No error */ return fd; error: EI_TRACE_ERR0("ei_accept","<- ACCEPT failed"); - if (fd>=0) - closesocket(fd); + abort_connection(cbs, ctx); return ERL_ERROR; } /* ei_accept */ @@ -927,36 +1328,57 @@ error: */ int ei_receive_tmo(int fd, unsigned char *bufp, int bufsize, unsigned ms) { - int len; + ssize_t len; unsigned char fourbyte[4]={0,0,0,0}; - int res; - - if ((res = ei_read_fill_t(fd, (char *) bufp, 4, ms)) != 4) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; + int err; + ei_socket_callbacks *cbs; + void *ctx; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; + + err = EI_GET_CBS_CTX__(&cbs, &ctx, fd); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } + + len = (ssize_t) 4; + err = ei_read_fill_ctx_t__(cbs, ctx, (char *) bufp, &len, tmo); + if (!err && len != (ssize_t) 4) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); return ERL_ERROR; } /* Tick handling */ - if ((len = get_int32(bufp)) == ERL_TICK) - { - ei_write_fill_t(fd, (char *) fourbyte, 4, ms); + len = get_int32(bufp); + if (len == ERL_TICK) { + len = 4; + ei_write_fill_ctx_t__(cbs, ctx, (char *) fourbyte, &len, tmo); /* FIXME ok to ignore error or timeout? */ erl_errno = EAGAIN; return ERL_TICK; } - else if (len > bufsize) - { + + if (len > bufsize) { /* FIXME: We should drain the message. */ erl_errno = EMSGSIZE; return ERL_ERROR; } - else if ((res = ei_read_fill_t(fd, (char *) bufp, len, ms)) != len) - { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return ERL_ERROR; + else { + ssize_t need = len; + err = ei_read_fill_ctx_t__(cbs, ctx, (char *) bufp, &len, tmo); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } + if (len != need) { + erl_errno = EIO; + return ERL_ERROR; + } } - return len; + return (int) len; } @@ -1112,36 +1534,11 @@ int ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, int ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x) { - fd_set readmask; - struct timeval tv; - struct timeval *t = NULL; - - if (timeout >= 0) { - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - t = &tv; - } - - FD_ZERO(&readmask); - FD_SET(fd,&readmask); - - switch (select(fd+1, &readmask, NULL, NULL, t)) { - case -1: - erl_errno = EIO; - return ERL_ERROR; - - case 0: - erl_errno = ETIMEDOUT; - return ERL_TIMEOUT; - - default: - if (FD_ISSET(fd, &readmask)) { - return ei_xreceive_msg(fd, msg, x); - } else { - erl_errno = EIO; - return ERL_ERROR; - } - } + unsigned tmo = timeout < 0 ? EI_SCLBK_INF_TMO : (unsigned) timeout; + int res = ei_xreceive_msg_tmo(fd, msg, x, tmo); + if (res < 0 && erl_errno == ETIMEDOUT) + return ERL_TIMEOUT; + return res; } /* rpc_from */ /* @@ -1295,19 +1692,34 @@ static char *hex(char digest[16], char buff[33]) return buff; } -static int read_2byte_package(int fd, char **buf, int *buflen, - int *is_static, unsigned ms) +static int read_hs_package(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, char **buf, int *buflen, + int *is_static, unsigned ms) { - unsigned char nbuf[2]; + unsigned char nbuf[4]; unsigned char *x = nbuf; - unsigned len; - int res; - - if((res = ei_read_fill_t(fd, (char *)nbuf, 2, ms)) != 2) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; + ssize_t len, need; + int err; + + len = (ssize_t) pkt_sz; + err = ei_read_fill_ctx_t__(cbs, ctx, (char *)nbuf, &len, ms); + if (!err && len != (ssize_t) pkt_sz) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); return -1; } - len = get16be(x); + + switch (pkt_sz) { + case 2: + len = get16be(x); + break; + case 4: + len = get32be(x); + break; + default: + return -1; + } if (len > *buflen) { if (*is_static) { @@ -1329,20 +1741,26 @@ static int read_2byte_package(int fd, char **buf, int *buflen, *buflen = len; } } - if ((res = ei_read_fill_t(fd, *buf, len, ms)) != len) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; + need = len; + err = ei_read_fill_ctx_t__(cbs, ctx, *buf, &len, ms); + if (!err && len != need) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); return -1; } return len; } -static int send_status(int fd, char *status, unsigned ms) +static int send_status(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, char *status, unsigned ms) { char *buf, *s; char dbuf[DEFBUF_SIZ]; - int siz = strlen(status) + 1 + 2; - int res; + int siz = strlen(status) + 1 + pkt_sz; + int err; + ssize_t len; buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf; if (!buf) { @@ -1350,14 +1768,28 @@ static int send_status(int fd, char *status, unsigned ms) return -1; } s = buf; - put16be(s,siz - 2); + switch (pkt_sz) { + case 2: + put16be(s,siz - 2); + break; + case 4: + put32be(s,siz - 4); + break; + default: + return -1; + } put8(s, 's'); memcpy(s, status, strlen(status)); - if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) { - EI_TRACE_ERR0("send_status","-> SEND_STATUS socket write failed"); + len = (ssize_t) siz; + err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms); + if (!err && len != (ssize_t) siz) + err = EIO; + if (err) { + EI_TRACE_ERR2("send_status","-> SEND_STATUS socket write failed: %s (%d)", + estr(err), err); if (buf != dbuf) - free(buf); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; + free(buf); + EI_CONN_SAVE_ERRNO__(err); return -1; } EI_TRACE_CONN1("send_status","-> SEND_STATUS (%s)",status); @@ -1367,7 +1799,8 @@ static int send_status(int fd, char *status, unsigned ms) return 0; } -static int recv_status(int fd, unsigned ms) +static int recv_status(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned ms) { char dbuf[DEFBUF_SIZ]; char *buf = dbuf; @@ -1375,7 +1808,8 @@ static int recv_status(int fd, unsigned ms) int buflen = DEFBUF_SIZ; int rlen; - if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) { + if ((rlen = read_hs_package(cbs, ctx, pkt_sz, + &buf, &buflen, &is_static, ms)) <= 0) { EI_TRACE_ERR1("recv_status", "<- RECV_STATUS socket read failed (%d)", rlen); goto error; @@ -1396,7 +1830,10 @@ error: return -1; } -static int send_name_or_challenge(int fd, char *nodename, +static int send_name_or_challenge(ei_socket_callbacks *cbs, + void *ctx, + int pkt_sz, + char *nodename, int f_chall, unsigned challenge, unsigned version, @@ -1405,9 +1842,10 @@ static int send_name_or_challenge(int fd, char *nodename, char *buf; unsigned char *s; char dbuf[DEFBUF_SIZ]; - int siz = 2 + 1 + 2 + 4 + strlen(nodename); + int siz = pkt_sz + 1 + 2 + 4 + strlen(nodename); const char* function[] = {"SEND_NAME", "SEND_CHALLENGE"}; - int res; + int err; + ssize_t len; if (f_chall) siz += 4; @@ -1417,7 +1855,16 @@ static int send_name_or_challenge(int fd, char *nodename, return -1; } s = (unsigned char *)buf; - put16be(s,siz - 2); + switch (pkt_sz) { + case 2: + put16be(s,siz - 2); + break; + case 4: + put32be(s,siz - 4); + break; + default: + return -1; + } put8(s, 'n'); put16be(s, version); put32be(s, (DFLAG_EXTENDED_REFERENCES @@ -1433,13 +1880,16 @@ static int send_name_or_challenge(int fd, char *nodename, if (f_chall) put32be(s, challenge); memcpy(s, nodename, strlen(nodename)); - - if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) { + len = (ssize_t) siz; + err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms); + if (!err && len != (ssize_t) siz) + err = EIO; + if (err) { EI_TRACE_ERR1("send_name_or_challenge", "-> %s socket write failed", function[f_chall]); if (buf != dbuf) free(buf); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; + EI_CONN_SAVE_ERRNO__(err); return -1; } @@ -1448,9 +1898,9 @@ static int send_name_or_challenge(int fd, char *nodename, return 0; } -static int recv_challenge(int fd, unsigned *challenge, - unsigned *version, - unsigned *flags, ErlConnect *namebuf, unsigned ms) +static int recv_challenge(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned *challenge, unsigned *version, + unsigned *flags, char *namebuf, unsigned ms) { char dbuf[DEFBUF_SIZ]; char *buf = dbuf; @@ -1458,13 +1908,13 @@ static int recv_challenge(int fd, unsigned *challenge, int buflen = DEFBUF_SIZ; int rlen; char *s; - struct sockaddr_in sin; - socklen_t sin_len = sizeof(sin); char tag; - + char tmp_nodename[MAXNODELEN+1]; + erl_errno = EIO; /* Default */ - if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) { + if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, + &is_static, ms)) <= 0) { EI_TRACE_ERR1("recv_challenge", "<- RECV_CHALLENGE socket read failed (%d)",rlen); goto error; @@ -1505,22 +1955,19 @@ static int recv_challenge(int fd, unsigned *challenge, goto error; } - if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) { - EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE can't get peername"); - erl_errno = errno; - goto error; - } - memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr), - sizeof(sin.sin_addr.s_addr)); - memcpy(namebuf->nodename, s, rlen - 11); - namebuf->nodename[rlen - 11] = '\0'; + if (!namebuf) + namebuf = &tmp_nodename[0]; + + memcpy(namebuf, s, rlen - 11); + namebuf[rlen - 11] = '\0'; + if (!is_static) free(buf); EI_TRACE_CONN4("recv_challenge","<- RECV_CHALLENGE (ok) node = %s, " "version = %u, " "flags = %u, " "challenge = %d", - namebuf->nodename, + namebuf, *version, *flags, *challenge @@ -1533,24 +1980,40 @@ error: return -1; } -static int send_challenge_reply(int fd, unsigned char digest[16], +static int send_challenge_reply(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned char digest[16], unsigned challenge, unsigned ms) { char *s; char buf[DEFBUF_SIZ]; - int siz = 2 + 1 + 4 + 16; - int res; + int siz = pkt_sz + 1 + 4 + 16; + int err; + ssize_t len; s = buf; - put16be(s,siz - 2); + switch (pkt_sz) { + case 2: + put16be(s,siz - 2); + break; + case 4: + put32be(s,siz - 4); + break; + default: + return -1; + } put8(s, 'r'); put32be(s, challenge); memcpy(s, digest, 16); - - if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) { - EI_TRACE_ERR0("send_challenge_reply", - "-> SEND_CHALLENGE_REPLY socket write failed"); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; + + len = (ssize_t) siz; + err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms); + if (!err && len != (ssize_t) siz) + err = EIO; + if (err) { + EI_TRACE_ERR2("send_challenge_reply", + "-> SEND_CHALLENGE_REPLY socket write failed: %s (%d)", + estr(err), err); + EI_CONN_SAVE_ERRNO__(err); return -1; } @@ -1563,11 +2026,13 @@ static int send_challenge_reply(int fd, unsigned char digest[16], return 0; } -static int recv_challenge_reply (int fd, - unsigned our_challenge, - char cookie[], - unsigned *her_challenge, - unsigned ms) +static int recv_challenge_reply(ei_socket_callbacks *cbs, + void *ctx, + int pkt_sz, + unsigned our_challenge, + char cookie[], + unsigned *her_challenge, + unsigned ms) { char dbuf[DEFBUF_SIZ]; char *buf = dbuf; @@ -1580,7 +2045,7 @@ static int recv_challenge_reply (int fd, erl_errno = EIO; /* Default */ - if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 21) { + if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 21) { EI_TRACE_ERR1("recv_challenge_reply", "<- RECV_CHALLENGE_REPLY socket read failed (%d)",rlen); goto error; @@ -1620,23 +2085,38 @@ error: return -1; } -static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms) +static int send_challenge_ack(ei_socket_callbacks *cbs, void *ctx, int pkt_sz, + unsigned char digest[16], unsigned ms) { char *s; char buf[DEFBUF_SIZ]; - int siz = 2 + 1 + 16; - int res; + int siz = pkt_sz + 1 + 16; + int err; + ssize_t len; s = buf; - - put16be(s,siz - 2); + switch (pkt_sz) { + case 2: + put16be(s,siz - 2); + break; + case 4: + put32be(s,siz - 4); + break; + default: + return -1; + } put8(s, 'a'); memcpy(s, digest, 16); - if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) { - EI_TRACE_ERR0("recv_challenge_reply", - "-> SEND_CHALLENGE_ACK socket write failed"); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; + len = (ssize_t) siz; + err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms); + if (!err && len != (ssize_t) siz) + err = EIO; + if (err) { + EI_TRACE_ERR2("recv_challenge_reply", + "-> SEND_CHALLENGE_ACK socket write failed: %s (%d)", + estr(err), err); + EI_CONN_SAVE_ERRNO__(err); return -1; } @@ -1649,8 +2129,8 @@ static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms) return 0; } -static int recv_challenge_ack(int fd, - unsigned our_challenge, +static int recv_challenge_ack(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned our_challenge, char cookie[], unsigned ms) { char dbuf[DEFBUF_SIZ]; @@ -1664,7 +2144,7 @@ static int recv_challenge_ack(int fd, erl_errno = EIO; /* Default */ - if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 17) { + if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 17) { EI_TRACE_ERR1("recv_challenge_ack", "<- RECV_CHALLENGE_ACK socket read failed (%d)",rlen); goto error; @@ -1701,20 +2181,24 @@ error: return -1; } -static int send_name(int fd, char *nodename, unsigned version, unsigned ms) +static int send_name(ei_socket_callbacks *cbs, void *ctx, int pkt_sz, + char *nodename, unsigned version, unsigned ms) { - return send_name_or_challenge(fd, nodename, 0, 0, version, ms); + return send_name_or_challenge(cbs, ctx, pkt_sz, nodename, 0, + 0, version, ms); } -static int send_challenge(int fd, char *nodename, - unsigned challenge, unsigned version, unsigned ms) +static int send_challenge(ei_socket_callbacks *cbs, void *ctx, int pkt_sz, + char *nodename, unsigned challenge, unsigned version, + unsigned ms) { - return send_name_or_challenge(fd, nodename, 1, challenge, version, ms); + return send_name_or_challenge(cbs, ctx, pkt_sz, nodename, 1, + challenge, version, ms); } -static int recv_name(int fd, - unsigned *version, - unsigned *flags, ErlConnect *namebuf, unsigned ms) +static int recv_name(ei_socket_callbacks *cbs, void *ctx, + int pkt_sz, unsigned *version, + unsigned *flags, char *namebuf, unsigned ms) { char dbuf[DEFBUF_SIZ]; char *buf = dbuf; @@ -1722,13 +2206,13 @@ static int recv_name(int fd, int buflen = DEFBUF_SIZ; int rlen; char *s; - struct sockaddr_in sin; - socklen_t sin_len = sizeof(sin); + char tmp_nodename[MAXNODELEN+1]; char tag; erl_errno = EIO; /* Default */ - if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) { + if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, + &is_static, ms)) <= 0) { EI_TRACE_ERR1("recv_name","<- RECV_NAME socket read failed (%d)",rlen); goto error; } @@ -1759,21 +2243,18 @@ static int recv_name(int fd, erl_errno = EIO; goto error; } - - if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) { - EI_TRACE_ERR0("recv_name","<- RECV_NAME can't get peername"); - erl_errno = errno; - goto error; - } - memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr), - sizeof(sin.sin_addr.s_addr)); - memcpy(namebuf->nodename, s, rlen - 7); - namebuf->nodename[rlen - 7] = '\0'; + + if (!namebuf) + namebuf = &tmp_nodename[0]; + + memcpy(namebuf, s, rlen - 7); + namebuf[rlen - 7] = '\0'; + if (!is_static) free(buf); EI_TRACE_CONN3("recv_name", "<- RECV_NAME (ok) node = %s, version = %u, flags = %u", - namebuf->nodename,*version,*flags); + namebuf,*version,*flags); erl_errno = 0; return 0; @@ -1867,3 +2348,4 @@ static int get_cookie(char *buf, int bufsize) return 1; /* Success! */ } + diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c index 022a43d255..225fddc784 100644 --- a/lib/erl_interface/src/connect/ei_resolve.c +++ b/lib/erl_interface/src/connect/ei_resolve.c @@ -57,9 +57,9 @@ #ifdef HAVE_GETHOSTBYNAME_R -void ei_init_resolve(void) +int ei_init_resolve(void) { - return; /* Do nothing */ + return 0; /* Do nothing */ } #else /* !HAVE_GETHOSTBYNAME_R */ @@ -103,7 +103,7 @@ static int verify_dns_configuration(void); * our own, which are just wrappers around hostGetByName() and * hostGetByAddr(). Here we look up the functions. */ -void ei_init_resolve(void) +int ei_init_resolve(void) { #ifdef VXWORKS @@ -134,9 +134,12 @@ void ei_init_resolve(void) #ifdef _REENTRANT ei_gethost_sem = ei_mutex_create(); + if (!ei_gethost_sem) + return ENOMEM; #endif /* _REENTRANT */ ei_resolve_initialized = 1; + return 0; } #ifdef VXWORKS @@ -312,9 +315,11 @@ static struct hostent *my_gethostbyname_r(const char *name, struct hostent *src; struct hostent *rval = NULL; - /* FIXME this should have been done in 'erl'_init()? */ - if (!ei_resolve_initialized) ei_init_resolve(); - + if (!ei_resolve_initialized) { + *h_errnop = NO_RECOVERY; + return NULL; + } + #ifdef _REENTRANT /* === BEGIN critical section === */ if (ei_mutex_lock(ei_gethost_sem,0) != 0) { @@ -377,7 +382,10 @@ static struct hostent *my_gethostbyaddr_r(const char *addr, struct hostent *rval = NULL; /* FIXME this should have been done in 'erl'_init()? */ - if (!ei_resolve_initialized) ei_init_resolve(); + if (!ei_resolve_initialized) { + *h_errnop = NO_RECOVERY; + return NULL; + } #ifdef _REENTRANT /* === BEGIN critical section === */ diff --git a/lib/erl_interface/src/connect/ei_resolve.h b/lib/erl_interface/src/connect/ei_resolve.h index 10a49ffbc6..5711d7da76 100644 --- a/lib/erl_interface/src/connect/ei_resolve.h +++ b/lib/erl_interface/src/connect/ei_resolve.h @@ -20,6 +20,6 @@ #ifndef _EI_RESOLVE_H #define _EI_RESOLVE_H -void ei_init_resolve(void); +int ei_init_resolve(void); #endif /* _EI_RESOLVE_H */ diff --git a/lib/erl_interface/src/connect/eirecv.c b/lib/erl_interface/src/connect/eirecv.c index 7b9dbfc387..47eea06ced 100644 --- a/lib/erl_interface/src/connect/eirecv.c +++ b/lib/erl_interface/src/connect/eirecv.c @@ -60,22 +60,36 @@ ei_recv_internal (int fd, int arity; int version; int index = 0; - int i = 0; - int res; + int err; int show_this_msg = 0; + ei_socket_callbacks *cbs; + void *ctx; + ssize_t rlen; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; + + err = EI_GET_CBS_CTX__(&cbs, &ctx, fd); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return -1; + } /* get length field */ - if ((res = ei_read_fill_t(fd, header, 4, ms)) != 4) - { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; + rlen = 4; + err = ei_read_fill_ctx_t__(cbs, ctx, header, &rlen, tmo); + if (!err && rlen != 4) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); return -1; } + len = get32be(s); /* got tick - respond and return */ if (!len) { char tock[] = {0,0,0,0}; - ei_write_fill_t(fd, tock, sizeof(tock), ms); /* Failure no problem */ + ssize_t wlen = sizeof(tock); + ei_write_fill_ctx_t__(cbs, ctx, tock, &wlen, tmo); /* Failure no problem */ *msglenp = 0; return 0; /* maybe flag ERL_EAGAIN [sverkerw] */ } @@ -86,9 +100,12 @@ ei_recv_internal (int fd, ei_trace(-1,NULL); /* read enough to get at least entire header */ - bytesread = (len > EIRECVBUF ? EIRECVBUF : len); - if ((i = ei_read_fill_t(fd,header,bytesread,ms)) != bytesread) { - erl_errno = (i == -2) ? ETIMEDOUT : EIO; + rlen = bytesread = (len > EIRECVBUF ? EIRECVBUF : len); + err = ei_read_fill_ctx_t__(cbs, ctx, header, &rlen, tmo); + if (!err && rlen != bytesread) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); return -1; } @@ -212,12 +229,17 @@ ei_recv_internal (int fd, */ if (msglen > *bufsz) { if (staticbufp) { - int sz = EIRECVBUF; /* flush in rest of packet */ while (remain > 0) { - if (remain < sz) sz = remain; - if ((i=ei_read_fill_t(fd,header,sz,ms)) <= 0) break; - remain -= i; + rlen = remain > EIRECVBUF ? EIRECVBUF : remain; + err = ei_read_fill_ctx_t__(cbs, ctx, header, &rlen, tmo); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return -1; + } + if (rlen == 0) + break; + remain -= rlen; } erl_errno = EMSGSIZE; return -1; @@ -247,11 +269,15 @@ ei_recv_internal (int fd, /* read the rest of the message into callers buffer */ if (remain > 0) { - if ((i = ei_read_fill_t(fd,mbuf+bytesread-index,remain,ms)) != remain) { - *msglenp = bytesread-index+1; /* actual bytes in users buffer */ - erl_errno = (i == -2) ? ETIMEDOUT : EIO; - return -1; - } + rlen = remain; + err = ei_read_fill_ctx_t__(cbs, ctx, mbuf+bytesread-index, &rlen, tmo); + if (!err && rlen != remain) + err = EIO; + if (err) { + *msglenp = bytesread-index+1; /* actual bytes in users buffer */ + EI_CONN_SAVE_ERRNO__(err); + return -1; + } } if (show_this_msg) diff --git a/lib/erl_interface/src/connect/send.c b/lib/erl_interface/src/connect/send.c index 37d7db6d68..d97532d123 100644 --- a/lib/erl_interface/src/connect/send.c +++ b/lib/erl_interface/src/connect/send.c @@ -58,10 +58,17 @@ int ei_send_encoded_tmo(int fd, const erlang_pid *to, char *s, header[1200]; /* see size calculation below */ erlang_trace *token = NULL; int index = 5; /* reserve 5 bytes for control message */ - int res; -#ifdef HAVE_WRITEV - struct iovec v[2]; -#endif + int err; + ei_socket_callbacks *cbs; + void *ctx; + ssize_t len, tot_len; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; + + err = EI_GET_CBS_CTX__(&cbs, &ctx, fd); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } /* are we tracing? */ /* check that he can receive trace tokens first */ @@ -91,30 +98,47 @@ int ei_send_encoded_tmo(int fd, const erlang_pid *to, if (ei_tracelevel >= 4) ei_show_sendmsg(stderr,header,msg); -#ifdef HAVE_WRITEV - - v[0].iov_base = (char *)header; - v[0].iov_len = index; - v[1].iov_base = (char *)msg; - v[1].iov_len = msglen; - - if ((res = ei_writev_fill_t(fd,v,2,ms)) != index+msglen) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; - } - -#else /* !HAVE_WRITEV */ - - if ((res = ei_write_fill_t(fd,header,index,ms)) != index) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; + +#ifdef EI_HAVE_STRUCT_IOVEC__ + if (ei_socket_callbacks_have_writev__(cbs)) { + struct iovec v[2]; + + v[0].iov_base = (char *)header; + v[0].iov_len = index; + v[1].iov_base = (char *)msg; + v[1].iov_len = msglen; + + len = tot_len = (ssize_t) index+msglen; + err = ei_writev_fill_ctx_t__(cbs, ctx, v, 2, &len, tmo); + if (!err && len != tot_len) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return -1; + } + + return 0; } - if ((res = ei_write_fill_t(fd,msg,msglen,ms)) != msglen) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; +#endif /* EI_HAVE_STRUCT_IOVEC__ */ + + /* no writev() */ + len = tot_len = (ssize_t) index; + err = ei_write_fill_ctx_t__(cbs, ctx, header, &len, tmo); + if (!err && len != tot_len) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return -1; } -#endif /* !HAVE_WRITEV */ + len = tot_len = (ssize_t) msglen; + err = ei_write_fill_ctx_t__(cbs, ctx, msg, &len, tmo); + if (!err && len != tot_len) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return -1; + } return 0; } diff --git a/lib/erl_interface/src/connect/send_exit.c b/lib/erl_interface/src/connect/send_exit.c index 2e298e3221..b4f7e14c7f 100644 --- a/lib/erl_interface/src/connect/send_exit.c +++ b/lib/erl_interface/src/connect/send_exit.c @@ -55,6 +55,17 @@ int ei_send_exit_tmo(int fd, const erlang_pid *from, const erlang_pid *to, char *s; int index = 0; int len = strlen(reason) + 1080; /* see below */ + ei_socket_callbacks *cbs; + void *ctx; + int err; + ssize_t wlen; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; + + err = EI_GET_CBS_CTX__(&cbs, &ctx, fd); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } if (len > EISMALLBUF) if (!(dbuf = malloc(len))) @@ -92,10 +103,16 @@ int ei_send_exit_tmo(int fd, const erlang_pid *from, const erlang_pid *to, if (ei_tracelevel >= 4) ei_show_sendmsg(stderr,msgbuf,NULL); - ei_write_fill_t(fd,msgbuf,index,ms); - /* FIXME ignore timeout etc? erl_errno?! */ - - if (dbuf) free(dbuf); + wlen = (ssize_t) index; + err = ei_write_fill_ctx_t__(cbs, ctx, msgbuf, &wlen, tmo); + if (!err && wlen != (ssize_t) index) + err = EIO; + if (dbuf) + free(dbuf); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } return 0; } diff --git a/lib/erl_interface/src/connect/send_reg.c b/lib/erl_interface/src/connect/send_reg.c index 62478f042d..80d61e57b5 100644 --- a/lib/erl_interface/src/connect/send_reg.c +++ b/lib/erl_interface/src/connect/send_reg.c @@ -51,11 +51,17 @@ int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, char *s, header[1400]; /* see size calculation below */ erlang_trace *token = NULL; int index = 5; /* reserve 5 bytes for control message */ - int res; + int err; + ei_socket_callbacks *cbs; + void *ctx; + ssize_t len, tot_len; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; -#ifdef HAVE_WRITEV - struct iovec v[2]; -#endif + err = EI_GET_CBS_CTX__(&cbs, &ctx, fd); + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return ERL_ERROR; + } /* are we tracing? */ /* check that he can receive trace tokens first */ @@ -86,29 +92,45 @@ int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, if (ei_tracelevel >= 4) ei_show_sendmsg(stderr,header,msg); -#ifdef HAVE_WRITEV +#ifdef EI_HAVE_STRUCT_IOVEC__ + if (ei_socket_callbacks_have_writev__(cbs)) { + struct iovec v[2]; - v[0].iov_base = (char *)header; - v[0].iov_len = index; - v[1].iov_base = (char *)msg; - v[1].iov_len = msglen; + v[0].iov_base = (char *)header; + v[0].iov_len = index; + v[1].iov_base = (char *)msg; + v[1].iov_len = msglen; - if ((res = ei_writev_fill_t(fd,v,2,ms)) != index+msglen) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; + len = tot_len = (ssize_t) index+msglen; + err = ei_writev_fill_ctx_t__(cbs, ctx, v, 2, &len, tmo); + if (!err && len != tot_len) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return -1; + } + return 0; } -#else - +#endif /* EI_HAVE_STRUCT_IOVEC__ */ + /* no writev() */ - if ((res = ei_write_fill_t(fd,header,index,ms)) != index) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; + len = tot_len = (ssize_t) index; + err = ei_write_fill_ctx_t__(cbs, ctx, header, &len, tmo); + if (!err && len != tot_len) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return -1; } - if ((res = ei_write_fill_t(fd,msg,msglen,ms)) != msglen) { - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; + + len = tot_len = (ssize_t) msglen; + err = ei_write_fill_ctx_t__(cbs, ctx, msg, &len, tmo); + if (!err && len != tot_len) + err = EIO; + if (err) { + EI_CONN_SAVE_ERRNO__(err); + return -1; } -#endif return 0; } diff --git a/lib/erl_interface/src/epmd/epmd_port.c b/lib/erl_interface/src/epmd/epmd_port.c index 2ec418b24a..492c3fb3aa 100644 --- a/lib/erl_interface/src/epmd/epmd_port.c +++ b/lib/erl_interface/src/epmd/epmd_port.c @@ -62,31 +62,38 @@ int ei_epmd_connect_tmo(struct in_addr *inaddr, unsigned ms) { static unsigned int epmd_port = 0; - struct sockaddr_in saddr; - int sd; - int res; + int port, sd, err; + struct in_addr ip_addr; + struct sockaddr_in addr; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; + + err = ei_socket__(&sd); + if (err) { + erl_errno = err; + return -1; + } if (epmd_port == 0) { char* port_str = getenv("ERL_EPMD_PORT"); epmd_port = (port_str != NULL) ? atoi(port_str) : EPMD_PORT; } - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_port = htons(epmd_port); - saddr.sin_family = AF_INET; - if (!inaddr) saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - else memmove(&saddr.sin_addr,inaddr,sizeof(saddr.sin_addr)); + port = (int) epmd_port; - if (((sd = socket(PF_INET, SOCK_STREAM, 0)) < 0)) - { - erl_errno = errno; - return -1; + if (!inaddr) { + ip_addr.s_addr = htonl(INADDR_LOOPBACK); + inaddr = &ip_addr; } + + memset((void *) &addr, 0, sizeof(struct sockaddr_in)); + memcpy((void *) &addr.sin_addr, (void *) inaddr, sizeof(addr.sin_addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); - if ((res = ei_connect_t(sd,(struct sockaddr *)&saddr,sizeof(saddr),ms)) < 0) - { - erl_errno = (res == -2) ? ETIMEDOUT : errno; - closesocket(sd); + err = ei_connect_t__(sd, (void *) &addr, sizeof(addr), tmo); + if (err) { + erl_errno = err; + ei_close__(sd); return -1; } @@ -104,6 +111,9 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive, int port; int dist_high, dist_low, proto; int res; + int err; + ssize_t dlen; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; #if defined(VXWORKS) char ntoabuf[32]; #endif @@ -124,10 +134,14 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive, return -1; } - if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) { - closesocket(fd); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; + dlen = len + 2; + err = ei_write_fill_t__(fd, buf, &dlen, tmo); + if (!err && dlen != (ssize_t) len + 2) + erl_errno = EIO; + if (err) { + ei_close__(fd); + EI_CONN_SAVE_ERRNO__(err); + return -1; } #ifdef VXWORKS @@ -142,12 +156,15 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive, "-> PORT2_REQ alive=%s ip=%s",alive,inet_ntoa(*addr)); #endif - /* read first two bytes (response type, response) */ - if ((res = ei_read_fill_t(fd, buf, 2, ms)) != 2) { - EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE"); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - closesocket(fd); - return -2; /* version mismatch */ + dlen = (ssize_t) 2; + err = ei_read_fill_t__(fd, buf, &dlen, tmo); + if (!err && dlen != (ssize_t) 2) + erl_errno = EIO; + if (err) { + EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE"); + ei_close__(fd); + EI_CONN_SAVE_ERRNO__(err); + return -2; } s = buf; @@ -156,7 +173,7 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive, if (res != EI_EPMD_PORT2_RESP) { /* response type */ EI_TRACE_ERR1("ei_epmd_r4_port","<- unknown (%d)",res); EI_TRACE_ERR0("ei_epmd_r4_port","-> CLOSE"); - closesocket(fd); + ei_close__(fd); erl_errno = EIO; return -1; } @@ -167,7 +184,7 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive, if ((res = get8(s))) { /* got negative response */ EI_TRACE_ERR1("ei_epmd_r4_port","<- PORT2_RESP result=%d (failure)",res); - closesocket(fd); + ei_close__(fd); erl_errno = EIO; return -1; } @@ -175,14 +192,18 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive, EI_TRACE_CONN1("ei_epmd_r4_port","<- PORT2_RESP result=%d (ok)",res); /* expecting remaining 8 bytes */ - if ((res = ei_read_fill_t(fd,buf,8,ms)) != 8) { + dlen = (ssize_t) 8; + err = ei_read_fill_t__(fd, buf, &dlen, tmo); + if (!err && dlen != (ssize_t) 8) + err = EIO; + if (err) { EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE"); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - closesocket(fd); + ei_close__(fd); + EI_CONN_SAVE_ERRNO__(err); return -1; } - closesocket(fd); + ei_close__(fd); s = buf; port = get16be(s); diff --git a/lib/erl_interface/src/epmd/epmd_publish.c b/lib/erl_interface/src/epmd/epmd_publish.c index 47d68a6db0..20b8e867e8 100644 --- a/lib/erl_interface/src/epmd/epmd_publish.c +++ b/lib/erl_interface/src/epmd/epmd_publish.c @@ -68,8 +68,10 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms) int nlen = strlen(alive); int len = elen + nlen + 13; /* hard coded: be careful! */ int n; - int res, creation; - + int err, res, creation; + ssize_t dlen; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; + if (len > sizeof(buf)-2) { erl_errno = ERANGE; @@ -93,29 +95,39 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms) if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd; - if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) { - closesocket(fd); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; + dlen = (ssize_t) len+2; + err = ei_write_fill_t__(fd, buf, &dlen, tmo); + if (!err && dlen != (ssize_t) len + 2) + erl_errno = EIO; + if (err) { + ei_close__(fd); + EI_CONN_SAVE_ERRNO__(err); + return -1; } EI_TRACE_CONN6("ei_epmd_r4_publish", "-> ALIVE2_REQ alive=%s port=%d ntype=%d " "proto=%d dist-high=%d dist-low=%d", alive,port,'H',EI_MYPROTO,EI_DIST_HIGH,EI_DIST_LOW); - - if ((n = ei_read_fill_t(fd, buf, 4, ms)) != 4) { + + dlen = (ssize_t) 4; + err = ei_read_fill_t__(fd, buf, &dlen, tmo); + n = (int) dlen; + if (!err && n != 4) + err = EIO; + if (err) { EI_TRACE_ERR0("ei_epmd_r4_publish","<- CLOSE"); - closesocket(fd); - erl_errno = (n == -2) ? ETIMEDOUT : EIO; + ei_close__(fd); + EI_CONN_SAVE_ERRNO__(err); return -2; /* version mismatch */ } + /* Don't close fd here! It keeps us registered with epmd */ s = buf; if (((res=get8(s)) != EI_EPMD_ALIVE2_RESP)) { /* response */ EI_TRACE_ERR1("ei_epmd_r4_publish","<- unknown (%d)",res); EI_TRACE_ERR0("ei_epmd_r4_publish","-> CLOSE"); - closesocket(fd); + ei_close__(fd); erl_errno = EIO; return -1; } @@ -124,7 +136,7 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms) if (((res=get8(s)) != 0)) { /* 0 == success */ EI_TRACE_ERR1("ei_epmd_r4_publish"," result=%d (fail)",res); - closesocket(fd); + ei_close__(fd); erl_errno = EIO; return -1; } diff --git a/lib/erl_interface/src/epmd/epmd_unpublish.c b/lib/erl_interface/src/epmd/epmd_unpublish.c index 255d0ffb59..c112f74147 100644 --- a/lib/erl_interface/src/epmd/epmd_unpublish.c +++ b/lib/erl_interface/src/epmd/epmd_unpublish.c @@ -58,7 +58,9 @@ int ei_unpublish_tmo(const char *alive, unsigned ms) char buf[EPMDBUF]; char *s = (char*)buf; int len = 1 + strlen(alive); - int fd, res; + int fd, err; + ssize_t dlen; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; if (len > sizeof(buf)-3) { erl_errno = ERANGE; @@ -72,20 +74,29 @@ int ei_unpublish_tmo(const char *alive, unsigned ms) /* FIXME can't connect, return success?! At least commen whats up */ if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd; - if ((res = ei_write_fill_t(fd, buf, len+2,ms)) != len+2) { - closesocket(fd); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; + dlen = (ssize_t) len+2; + err = ei_write_fill_t__(fd, buf, &dlen, tmo); + if (!err && dlen != (ssize_t) len + 2) + erl_errno = EIO; + if (err) { + ei_close__(fd); + EI_CONN_SAVE_ERRNO__(err); + return -1; } EI_TRACE_CONN1("ei_unpublish_tmo","-> STOP %s",alive); - - if ((res = ei_read_fill_t(fd, buf, 7, ms)) != 7) { - closesocket(fd); - erl_errno = (res == -2) ? ETIMEDOUT : EIO; - return -1; + + dlen = (ssize_t) 7; + err = ei_read_fill_t__(fd, buf, &dlen, tmo); + if (!err && dlen != (ssize_t) 7) + erl_errno = EIO; + if (err) { + ei_close__(fd); + EI_CONN_SAVE_ERRNO__(err); + return -1; } - closesocket(fd); + + ei_close__(fd); buf[7]=(char)0; /* terminate the string */ if (!strcmp("STOPPED",(char *)buf)) { diff --git a/lib/erl_interface/src/legacy/erl_connect.c b/lib/erl_interface/src/legacy/erl_connect.c index 7ffd545d3e..e2fd4611c0 100644 --- a/lib/erl_interface/src/legacy/erl_connect.c +++ b/lib/erl_interface/src/legacy/erl_connect.c @@ -179,15 +179,13 @@ int erl_xconnect(Erl_IpAddr addr, char *alivename) * * API: erl_close_connection() * - * Close a connection. FIXME call ei_close_connection() later. - * * Returns 0 on success and -1 on failure. * ***************************************************************************/ int erl_close_connection(int fd) { - return closesocket(fd); + return ei_close_connection(fd); } /* @@ -220,7 +218,10 @@ int erl_reg_send(int fd, char *server_name, ETERM *msg) ei_x_buff x; int r; - ei_x_new_with_version(&x); + if (ei_x_new_with_version(&x) < 0) { + erl_errno = ENOMEM; + return 0; + } if (ei_x_encode_term(&x, msg) < 0) { erl_errno = EINVAL; r = 0; diff --git a/lib/erl_interface/src/legacy/erl_eterm.c b/lib/erl_interface/src/legacy/erl_eterm.c index 9ad92121f4..7ed2bdbc93 100644 --- a/lib/erl_interface/src/legacy/erl_eterm.c +++ b/lib/erl_interface/src/legacy/erl_eterm.c @@ -65,7 +65,7 @@ void erl_init(void *hp,long heap_size) { erl_init_malloc(hp, heap_size); erl_init_marshal(); - ei_init_resolve(); + (void) ei_init(); } void erl_set_compat_rel(unsigned rel) diff --git a/lib/erl_interface/src/misc/ei_init.c b/lib/erl_interface/src/misc/ei_init.c new file mode 100644 index 0000000000..5357968657 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_init.c @@ -0,0 +1,32 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * %CopyrightEnd% + */ + +#include "ei.h" +#include "ei_resolve.h" +#include "ei_internal.h" + +int +ei_init(void) +{ + int error = ei_init_connect(); + if (error) + return error; + return ei_init_resolve(); +} diff --git a/lib/erl_interface/src/misc/ei_internal.h b/lib/erl_interface/src/misc/ei_internal.h index aa6aacd703..f28dd6d668 100644 --- a/lib/erl_interface/src/misc/ei_internal.h +++ b/lib/erl_interface/src/misc/ei_internal.h @@ -22,19 +22,20 @@ #ifndef _EI_INTERNAL_H #define _EI_INTERNAL_H +#ifdef EI_HIDE_REAL_ERRNO +# define EI_CONN_SAVE_ERRNO__(E) \ + ((E) == ETIMEDOUT ? (erl_errno = ETIMEDOUT) : (erl_errno = EIO)) +#else +# define EI_CONN_SAVE_ERRNO__(E) \ + (erl_errno = (E)) +#endif + /* * Some useful stuff not to be exported to users. */ #ifdef __WIN32__ #define MAXPATHLEN 256 -#define writesocket(sock,buf,nbyte) send(sock,buf,nbyte,0) -#define readsocket(sock,buf,nbyte) recv(sock,buf,nbyte,0) -#else /* not __WIN32__ */ -#define writesocket write -#define readsocket read -#define closesocket close -#define ioctlsocket ioctl #endif /* @@ -152,7 +153,12 @@ extern int ei_tracelevel; +int ei_init_connect(void); + void ei_trace_printf(const char *name, int level, const char *format, ...); int ei_internal_use_r9_pids_ports(void); + +int ei_get_cbs_ctx__(ei_socket_callbacks **cbs, void **ctx, int fd); + #endif /* _EI_INTERNAL_H */ diff --git a/lib/erl_interface/src/misc/ei_portio.c b/lib/erl_interface/src/misc/ei_portio.c index 8cd35bf2e5..bccc86c1b1 100644 --- a/lib/erl_interface/src/misc/ei_portio.c +++ b/lib/erl_interface/src/misc/ei_portio.c @@ -19,9 +19,13 @@ * */ + +#include "eidef.h" + #ifdef __WIN32__ #include <winsock2.h> #include <windows.h> +#include <winbase.h> #include <process.h> #include <stdio.h> #include <stdlib.h> @@ -35,10 +39,6 @@ static unsigned long param_one = 1; #define SET_BLOCKING(Sock) ioctlsocket((Sock),FIONBIO,¶m_zero) #define SET_NONBLOCKING(Sock) ioctlsocket((Sock),FIONBIO,¶m_one) -#define ERROR_WOULDBLOCK WSAEWOULDBLOCK -#define ERROR_TIMEDOUT WSAETIMEDOUT -#define ERROR_INPROGRESS WSAEINPROGRESS -#define GET_SOCKET_ERROR() WSAGetLastError() #define MEANS_SOCKET_ERROR(Ret) ((Ret == SOCKET_ERROR)) #define IS_INVALID_SOCKET(Sock) ((Sock) == INVALID_SOCKET) @@ -50,125 +50,414 @@ static unsigned long param_one = 1; #include <taskLib.h> #include <inetLib.h> #include <selectLib.h> -#include <sys/types.h> #include <ioLib.h> #include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <timers.h> static unsigned long param_zero = 0; static unsigned long param_one = 1; #define SET_BLOCKING(Sock) ioctl((Sock),FIONBIO,(int)¶m_zero) #define SET_NONBLOCKING(Sock) ioctl((Sock),FIONBIO,(int)¶m_one) -#define ERROR_WOULDBLOCK EWOULDBLOCK -#define ERROR_TIMEDOUT ETIMEDOUT -#define ERROR_INPROGRESS EINPROGRESS -#define GET_SOCKET_ERROR() (errno) #define MEANS_SOCKET_ERROR(Ret) ((Ret) == ERROR) #define IS_INVALID_SOCKET(Sock) ((Sock) < 0) #else /* other unix */ #include <stdlib.h> -#include <sys/types.h> #include <sys/socket.h> -#include <sys/uio.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> -#ifndef EWOULDBLOCK -#define ERROR_WOULDBLOCK EAGAIN -#else -#define ERROR_WOULDBLOCK EWOULDBLOCK -#endif #define SET_BLOCKING(fd) fcntl((fd), F_SETFL, \ fcntl((fd), F_GETFL, 0) & ~O_NONBLOCK) #define SET_NONBLOCKING(fd) fcntl((fd), F_SETFL, \ fcntl((fd), F_GETFL, 0) | O_NONBLOCK) -#define ERROR_TIMEDOUT ETIMEDOUT -#define ERROR_INPROGRESS EINPROGRESS -#define GET_SOCKET_ERROR() (errno) #define MEANS_SOCKET_ERROR(Ret) ((Ret) < 0) #define IS_INVALID_SOCKET(Sock) ((Sock) < 0) #endif /* common includes */ -#include "eidef.h" +#include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "ei_portio.h" -#include "ei_internal.h" - #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #else #include <time.h> #endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#include "ei_portio.h" +#include "ei_internal.h" + +#ifdef __WIN32__ -#ifdef HAVE_WRITEV -static int ei_writev_t(int fd, struct iovec *iov, int iovcnt, unsigned ms) +#define writesocket(sock,buf,nbyte) send(sock,buf,nbyte,0) +#define readsocket(sock,buf,nbyte) recv(sock,buf,nbyte,0) + +static int get_error(void) { - int res; - if (ms != 0) { - fd_set writemask; - struct timeval tv; - tv.tv_sec = (time_t) (ms / 1000U); - ms %= 1000U; - tv.tv_usec = (time_t) (ms * 1000U); - FD_ZERO(&writemask); - FD_SET(fd,&writemask); - switch (select(fd+1, NULL, &writemask, NULL, &tv)) { - case -1 : - return -1; /* i/o error */ - case 0: - return -2; /* timeout */ - default: - if (!FD_ISSET(fd, &writemask)) { - return -1; /* Other error */ - } - } + switch (WSAGetLastError()) { + case WSAEWOULDBLOCK: return EWOULDBLOCK; + case WSAETIMEDOUT: return ETIMEDOUT; + case WSAEINPROGRESS: return EINPROGRESS; + case WSA_NOT_ENOUGH_MEMORY: return ENOMEM; + case WSA_INVALID_PARAMETER: return EINVAL; + case WSAEBADF: return EBADF; + case WSAEINVAL: return EINVAL; + case WSAEADDRINUSE: return EADDRINUSE; + case WSAENETUNREACH: return ENETUNREACH; + case WSAECONNABORTED: return ECONNABORTED; + case WSAECONNRESET: return ECONNRESET; + case WSAECONNREFUSED: return ECONNREFUSED; + case WSAEHOSTUNREACH: return EHOSTUNREACH; + case WSAEMFILE: return EMFILE; + case WSAEALREADY: return EALREADY; + default: return EIO; } +} + +#else /* not __WIN32__ */ + +#define writesocket write +#define readsocket read +#define closesocket close +#define ioctlsocket ioctl + +static int get_error(void) +{ + int err = errno; + if (err == 0) + return EIO; /* Make sure never to return 0 as error code... */ + return err; +} + +#endif + +int ei_plugin_socket_impl__ = 0; + +/* + * Callbacks for communication over TCP/IPv4 + */ + +static int tcp_get_fd(void *ctx, int *fd) +{ + return EI_DFLT_CTX_TO_FD__(ctx, fd); +} + +static int tcp_hs_packet_header_size(void *ctx, int *sz) +{ + int fd; + *sz = 2; + return EI_DFLT_CTX_TO_FD__(ctx, &fd); +} + +static int tcp_handshake_complete(void *ctx) +{ + int res, fd, one = 1; + + res = EI_DFLT_CTX_TO_FD__(ctx, &fd); + if (res) + return res; + + res = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + + res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one)); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + + return 0; +} + +static int tcp_socket(void **ctx, void *setup_ctx) +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (MEANS_SOCKET_ERROR(fd)) + return get_error(); + + *ctx = EI_FD_AS_CTX__(fd); + return 0; +} + +static int tcp_close(void *ctx) +{ + int fd, res; + + res = EI_DFLT_CTX_TO_FD__(ctx, &fd); + if (res) + return res; + + res = closesocket(fd); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + + return 0; +} + +static int tcp_listen(void *ctx, void *addr, int *len, int backlog) +{ + int res, fd; + socklen_t sz = (socklen_t) *len; + int on = 1; + + res = EI_DFLT_CTX_TO_FD__(ctx, &fd); + if (res) + return res; + + res = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + + res = bind(fd, (struct sockaddr *) addr, sz); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + + res = getsockname(fd, (struct sockaddr *) addr, (socklen_t *) &sz); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + *len = (int) sz; + + res = listen(fd, backlog); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + + return 0; +} + +static int tcp_accept(void **ctx, void *addr, int *len, unsigned unused) +{ + int fd, res; + socklen_t addr_len = (socklen_t) *len; + + if (!ctx) + return EINVAL; + + res = EI_DFLT_CTX_TO_FD__(*ctx, &fd); + if (res) + return res; + + res = accept(fd, (struct sockaddr*) addr, &addr_len); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + + *len = (int) addr_len; + + *ctx = EI_FD_AS_CTX__(res); + return 0; +} + +static int tcp_connect(void *ctx, void *addr, int len, unsigned unused) +{ + int res, fd; + + res = EI_DFLT_CTX_TO_FD__(ctx, &fd); + if (res) + return res; + + res = connect(fd, (struct sockaddr *) addr, len); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + + return 0; +} + +#if defined(EI_HAVE_STRUCT_IOVEC__) && defined(HAVE_WRITEV) + +static int tcp_writev(void *ctx, const void *viov, int iovcnt, ssize_t *len, unsigned unused) +{ + const struct iovec *iov = (const struct iovec *) viov; + int fd, error; + ssize_t res; + + error = EI_DFLT_CTX_TO_FD__(ctx, &fd); + if (error) + return error; + res = writev(fd, iov, iovcnt); - return (res < 0) ? -1 : res; + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + *len = res; + return 0; +} + +#endif + +static int tcp_write(void *ctx, const char* buf, ssize_t *len, unsigned unused) +{ + int error, fd; + ssize_t res; + + error = EI_DFLT_CTX_TO_FD__(ctx, &fd); + if (error) + return error; + + res = writesocket(fd, buf, *len); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + *len = res; + return 0; +} + +static int tcp_read(void *ctx, char* buf, ssize_t *len, unsigned unused) +{ + int error, fd; + ssize_t res; + + error = EI_DFLT_CTX_TO_FD__(ctx, &fd); + if (error) + return error; + + res = readsocket(fd, buf, *len); + if (MEANS_SOCKET_ERROR(res)) + return get_error(); + *len = res; + return 0; +} + +ei_socket_callbacks ei_default_socket_callbacks = { + 0, /* flags */ + tcp_socket, + tcp_close, + tcp_listen, + tcp_accept, + tcp_connect, +#if defined(EI_HAVE_STRUCT_IOVEC__) && defined(HAVE_WRITEV) + tcp_writev, +#else + NULL, +#endif + tcp_write, + tcp_read, + + tcp_hs_packet_header_size, + tcp_handshake_complete, + tcp_handshake_complete, + tcp_get_fd + +}; + + +/* + * + */ + +#if defined(EI_HAVE_STRUCT_IOVEC__) + +int ei_socket_callbacks_have_writev__(ei_socket_callbacks *cbs) +{ + return !!cbs->writev; } -int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned ms) +static int writev_ctx_t__(ei_socket_callbacks *cbs, void *ctx, + const struct iovec *iov, int iovcnt, + ssize_t *len, + unsigned ms) { - int i; - int done; + int error; + + if (!(cbs->flags & EI_SCLBK_FLG_FULL_IMPL) && ms != EI_SCLBK_INF_TMO) { + int fd; + + error = EI_GET_FD__(cbs, ctx, &fd); + if (error) + return error; + + do { + fd_set writemask; + struct timeval tv; + + tv.tv_sec = (time_t) (ms / 1000U); + ms %= 1000U; + tv.tv_usec = (time_t) (ms * 1000U); + FD_ZERO(&writemask); + FD_SET(fd,&writemask); + switch (select(fd+1, NULL, &writemask, NULL, &tv)) { + case -1 : + error = get_error(); + if (error != EINTR) + return error; + break; + case 0: + return ETIMEDOUT; /* timeout */ + default: + if (!FD_ISSET(fd, &writemask)) { + return EIO; /* Other error */ + } + error = 0; + break; + } + } while (error == EINTR); + } + do { + error = cbs->writev(ctx, (const void *) iov, iovcnt, len, ms); + } while (error == EINTR); + return error; +} + +int ei_writev_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, + const struct iovec *iov, int iovcnt, + ssize_t *len, + unsigned ms) +{ + ssize_t i, done, sum; struct iovec *iov_base = NULL; struct iovec *current_iov; int current_iovcnt; - int sum; + int fd, error; + int basic; + + if (!cbs->writev) + return ENOTSUP; + + error = EI_GET_FD__(cbs, ctx, &fd); + if (error) + return error; + basic = !(cbs->flags & EI_SCLBK_FLG_FULL_IMPL); + for (sum = 0, i = 0; i < iovcnt; ++i) { sum += iov[i].iov_len; } - if (ms != 0U) { + if (basic && ms != 0U) { SET_NONBLOCKING(fd); } current_iovcnt = iovcnt; current_iov = (struct iovec *) iov; done = 0; for (;;) { - i = ei_writev_t(fd, current_iov, current_iovcnt, ms); - if (i <= 0) { /* ei_writev_t should always return at least 1 */ + + error = writev_ctx_t__(cbs, ctx, current_iov, current_iovcnt, &i, ms); + if (error) { + *len = done; if (ms != 0U) { SET_BLOCKING(fd); } if (iov_base != NULL) { free(iov_base); } - return (i); - } + return error; + } done += i; if (done < sum) { if (iov_base == NULL) { iov_base = malloc(sizeof(struct iovec) * iovcnt); if (iov_base == NULL) { - return -1; + *len = done; + return ENOMEM; } memcpy(iov_base, iov, sizeof(struct iovec) * iovcnt); current_iov = iov_base; @@ -189,195 +478,383 @@ int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned break; } } - if (ms != 0U) { + if (basic && ms != 0U) { SET_BLOCKING(fd); } if (iov_base != NULL) { free(iov_base); } - return (sum); + *len = done; + return 0; } +#endif /* defined(EI_HAVE_STRUCT_IOVEC__) */ -#endif - -int ei_connect_t(int fd, void *sinp, int sin_siz, unsigned ms) +int ei_socket_ctx__(ei_socket_callbacks *cbs, void **ctx, void *setup_ctx) { int res; - int error; - int s_res; - struct timeval tv; - fd_set writefds; - fd_set exceptfds; - - if (ms == 0) { - res = connect(fd, sinp, sin_siz); - return (res < 0) ? -1 : res; - } else { - SET_NONBLOCKING(fd); - res = connect(fd, sinp, sin_siz); - error = GET_SOCKET_ERROR(); - SET_BLOCKING(fd); - if (!MEANS_SOCKET_ERROR(res)) { - return (res < 0) ? -1 : res; - } else { - if (error != ERROR_WOULDBLOCK && - error != ERROR_INPROGRESS) { - return -1; - } else { - tv.tv_sec = (long) (ms/1000U); - ms %= 1000U; - tv.tv_usec = (long) (ms * 1000U); - FD_ZERO(&writefds); - FD_SET(fd,&writefds); - FD_ZERO(&exceptfds); - FD_SET(fd,&exceptfds); - s_res = select(fd + 1, NULL, &writefds, &exceptfds, &tv); - switch (s_res) { - case 0: - return -2; - case 1: - if (FD_ISSET(fd, &exceptfds)) { - return -1; - } else { - return 0; /* Connect completed */ - } - default: - return -1; - } - } - } - } + + do { + res = cbs->socket(ctx, setup_ctx); + } while (res == EINTR); + + return res; } -int ei_accept_t(int fd, void *addr, void *addrlen, unsigned ms) +int ei_close_ctx__(ei_socket_callbacks *cbs, void *ctx) { - int res; - if (ms != 0) { - fd_set readmask; - struct timeval tv; - tv.tv_sec = (time_t) (ms / 1000U); - ms %= 1000U; - tv.tv_usec = (time_t) (ms * 1000U); - FD_ZERO(&readmask); - FD_SET(fd,&readmask); - switch (select(fd+1, &readmask, NULL, NULL, &tv)) { - case -1 : - return -1; /* i/o error */ - case 0: - return -2; /* timeout */ - default: - if (!FD_ISSET(fd, &readmask)) { - return -1; /* Other error */ - } - } - } - res = (int) accept(fd,addr,addrlen); - return (res < 0) ? -1 : res; + return cbs->close(ctx); } + +int ei_connect_ctx_t__(ei_socket_callbacks *cbs, void *ctx, + void *addr, int len, unsigned ms) +{ + int res, fd; + + if ((cbs->flags & EI_SCLBK_FLG_FULL_IMPL) || ms == EI_SCLBK_INF_TMO) { + do { + res = cbs->connect(ctx, addr, len, ms); + } while (res == EINTR); + return res; + } + + res = EI_GET_FD__(cbs, ctx, &fd); + if (res) + return res; + SET_NONBLOCKING(fd); + do { + res = cbs->connect(ctx, addr, len, 0); + } while (res == EINTR); + SET_BLOCKING(fd); + switch (res) { + case EINPROGRESS: + case EAGAIN: +#ifdef EWOULDBLOCK +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif +#endif + break; + default: + return res; + } -static int ei_read_t(int fd, char* buf, int len, unsigned ms) + while (1) { + struct timeval tv; + fd_set writefds; + fd_set exceptfds; + + tv.tv_sec = (long) (ms/1000U); + ms %= 1000U; + tv.tv_usec = (long) (ms * 1000U); + FD_ZERO(&writefds); + FD_SET(fd,&writefds); + FD_ZERO(&exceptfds); + FD_SET(fd,&exceptfds); + res = select(fd + 1, NULL, &writefds, &exceptfds, &tv); + switch (res) { + case -1: + res = get_error(); + if (res != EINTR) + return res; + break; + case 0: + return ETIMEDOUT; + case 1: + if (!FD_ISSET(fd, &exceptfds)) + return 0; /* Connect completed */ + /* fall through... */ + default: + return EIO; + } + } +} + +int ei_listen_ctx__(ei_socket_callbacks *cbs, void *ctx, + void *adr, int *len, int backlog) { int res; - if (ms != 0) { - fd_set readmask; - struct timeval tv; - tv.tv_sec = (time_t) (ms / 1000U); - ms %= 1000U; - tv.tv_usec = (time_t) (ms * 1000U); - FD_ZERO(&readmask); - FD_SET(fd,&readmask); - switch (select(fd+1, &readmask, NULL, NULL, &tv)) { - case -1 : - return -1; /* i/o error */ - case 0: - return -2; /* timeout */ - default: - if (!FD_ISSET(fd, &readmask)) { - return -1; /* Other error */ - } - } + + do { + res = cbs->listen(ctx, adr, len, backlog); + } while (res == EINTR); + return res; +} + +int ei_accept_ctx_t__(ei_socket_callbacks *cbs, void **ctx, + void *addr, int *len, unsigned ms) +{ + int error; + + if (!(cbs->flags & EI_SCLBK_FLG_FULL_IMPL) && ms != EI_SCLBK_INF_TMO) { + int fd; + + error = EI_GET_FD__(cbs, *ctx, &fd); + if (error) + return error; + + do { + fd_set readmask; + struct timeval tv; + + tv.tv_sec = (time_t) (ms / 1000U); + ms %= 1000U; + tv.tv_usec = (time_t) (ms * 1000U); + FD_ZERO(&readmask); + FD_SET(fd,&readmask); + switch (select(fd+1, &readmask, NULL, NULL, &tv)) { + case -1 : + error = get_error(); + if (error != EINTR) + return error; + break; + case 0: + return ETIMEDOUT; /* timeout */ + default: + if (!FD_ISSET(fd, &readmask)) { + return EIO; /* Other error */ + } + error = 0; + break; + } + } while (error == EINTR); } - res = readsocket(fd, buf, len); - return (res < 0) ? -1 : res; + do { + error = cbs->accept(ctx, addr, len, ms); + } while (error == EINTR); + return error; } -static int ei_write_t(int fd, const char* buf, int len, unsigned ms) +static int read_ctx_t__(ei_socket_callbacks *cbs, void *ctx, + char* buf, ssize_t *len, unsigned ms) { - int res; - if (ms != 0) { - fd_set writemask; - struct timeval tv; - tv.tv_sec = (time_t) (ms / 1000U); - ms %= 1000U; - tv.tv_usec = (time_t) (ms * 1000U); - FD_ZERO(&writemask); - FD_SET(fd,&writemask); - switch (select(fd+1, NULL, &writemask, NULL, &tv)) { - case -1 : - return -1; /* i/o error */ - case 0: - return -2; /* timeout */ - default: - if (!FD_ISSET(fd, &writemask)) { - return -1; /* Other error */ - } - } + int error; + + if (!(cbs->flags & EI_SCLBK_FLG_FULL_IMPL) && ms != EI_SCLBK_INF_TMO) { + int fd; + + error = EI_GET_FD__(cbs, ctx, &fd); + if (error) + return error; + + do { + fd_set readmask; + struct timeval tv; + + tv.tv_sec = (time_t) (ms / 1000U); + ms %= 1000U; + tv.tv_usec = (time_t) (ms * 1000U); + FD_ZERO(&readmask); + FD_SET(fd,&readmask); + switch (select(fd+1, &readmask, NULL, NULL, &tv)) { + case -1 : + error = get_error(); + if (error != EINTR) + return error; + break; + case 0: + return ETIMEDOUT; /* timeout */ + default: + if (!FD_ISSET(fd, &readmask)) { + return EIO; /* Other error */ + } + error = 0; + break; + } + } while (error == EINTR); + } + do { + error = cbs->read(ctx, buf, len, ms); + } while (error == EINTR); + return error; +} + +static int write_ctx_t__(ei_socket_callbacks *cbs, void *ctx, const char* buf, ssize_t *len, unsigned ms) +{ + int error; + + if (!(cbs->flags & EI_SCLBK_FLG_FULL_IMPL) && ms != EI_SCLBK_INF_TMO) { + int fd; + + error = EI_GET_FD__(cbs, ctx, &fd); + if (error) + return error; + + do { + fd_set writemask; + struct timeval tv; + + tv.tv_sec = (time_t) (ms / 1000U); + ms %= 1000U; + tv.tv_usec = (time_t) (ms * 1000U); + FD_ZERO(&writemask); + FD_SET(fd,&writemask); + switch (select(fd+1, NULL, &writemask, NULL, &tv)) { + case -1 : + error = get_error(); + if (error != EINTR) + return error; + break; + case 0: + return ETIMEDOUT; /* timeout */ + default: + if (!FD_ISSET(fd, &writemask)) { + return EIO; /* Other error */ + } + error = 0; + break; + } + } while (error == EINTR); } - res = writesocket(fd, buf, len); - return (res < 0) ? -1 : res; + do { + error = cbs->write(ctx, buf, len, ms); + } while (error == EINTR); + return error; } /* * Fill buffer, return buffer length, 0 for EOF, < 0 (and sets errno) * for error. */ -int ei_read_fill_t(int fd, char* buf, int len, unsigned ms) +int ei_read_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, char* buf, ssize_t *len, unsigned ms) { - int i,got=0; + ssize_t got = 0; + ssize_t want = *len; do { - i = ei_read_t(fd, buf+got, len-got, ms); - if (i <= 0) - return (i); - got += i; - } while (got < len); - return (len); - + ssize_t read_len = want-got; + int error; + + do { + error = read_ctx_t__(cbs, ctx, buf+got, &read_len, ms); + } while (error == EINTR); + if (error) + return error; + if (read_len == 0) { + *len = got; + return 0; + } + got += read_len; + } while (got < want); + + *len = got; + return 0; } /* read_fill */ -int ei_read_fill(int fd, char* buf, int len) +int ei_read_fill_ctx__(ei_socket_callbacks *cbs, void *ctx, char* buf, ssize_t *len) { - return ei_read_fill_t(fd, buf, len, 0); + return ei_read_fill_ctx_t__(cbs, ctx, buf, len, 0); } /* write entire buffer on fd or fail (setting errno) */ -int ei_write_fill_t(int fd, const char *buf, int len, unsigned ms) +int ei_write_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, const char *buf, ssize_t *len, unsigned ms) { - int i,done=0; - if (ms != 0U) { + ssize_t tot = *len, done = 0; + int error, fd = -1, basic = !(cbs->flags & EI_SCLBK_FLG_FULL_IMPL); + + if (basic && ms != 0U) { + error = EI_GET_FD__(cbs, ctx, &fd); + if (error) + return error; SET_NONBLOCKING(fd); } do { - i = ei_write_t(fd, buf+done, len-done, ms); - if (i <= 0) { - if (ms != 0U) { + ssize_t write_len = tot-done; + error = write_ctx_t__(cbs, ctx, buf+done, &write_len, ms); + if (error) { + *len = done; + if (basic && ms != 0U) { SET_BLOCKING(fd); } - return (i); + return error; } - done += i; - } while (done < len); - if (ms != 0U) { + done += write_len; + } while (done < tot); + if (basic && ms != 0U) { SET_BLOCKING(fd); } - return (len); + *len = done; + return 0; +} + +int ei_write_fill_ctx__(ei_socket_callbacks *cbs, void *ctx, const char *buf, ssize_t *len) +{ + return ei_write_fill_ctx_t__(cbs, ctx, buf, len, 0); +} + +/* + * Internal API for TCP/IPv4 + */ + +int ei_connect_t__(int fd, void *addr, int len, unsigned ms) +{ + return ei_connect_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd), + addr, len, ms); } -int ei_write_fill(int fd, const char *buf, int len) +int ei_socket__(int *fd) { - return ei_write_fill_t(fd, buf, len, 0); + void *ctx; + int error = ei_socket_ctx__(&ei_default_socket_callbacks, &ctx, NULL); + if (error) + return error; + return EI_GET_FD__(&ei_default_socket_callbacks, ctx, fd); } +int ei_close__(int fd) +{ + return ei_close_ctx__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd)); +} + +int ei_listen__(int fd, void *adr, int *len, int backlog) +{ + return ei_listen_ctx__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd), + adr, len, backlog); +} + +int ei_accept_t__(int *fd, void *addr, int *len, unsigned ms) +{ + void *ctx = EI_FD_AS_CTX__(*fd); + int error = ei_accept_ctx_t__(&ei_default_socket_callbacks, &ctx, + addr, len, ms); + if (error) + return error; + return EI_GET_FD__(&ei_default_socket_callbacks, ctx, fd); +} + +int ei_read_fill_t__(int fd, char* buf, ssize_t *len, unsigned ms) +{ + return ei_read_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd), + buf, len, ms); +} + +int ei_read_fill__(int fd, char* buf, ssize_t *len) +{ + return ei_read_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd), + buf, len, 0); +} + +int ei_write_fill_t__(int fd, const char *buf, ssize_t *len, unsigned ms) +{ + return ei_write_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd), + buf, len, ms); +} + +int ei_write_fill__(int fd, const char *buf, ssize_t *len) +{ + return ei_write_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd), + buf, len, 0); +} + +#if defined(EI_HAVE_STRUCT_IOVEC__) && defined(HAVE_WRITEV) + +int ei_writev_fill_t__(int fd, const struct iovec *iov, int iovcnt, ssize_t *len, unsigned ms) +{ + return ei_writev_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd), + iov, iovcnt, len, ms); +} + +#endif + diff --git a/lib/erl_interface/src/misc/ei_portio.h b/lib/erl_interface/src/misc/ei_portio.h index bded811a35..a84b5ca09c 100644 --- a/lib/erl_interface/src/misc/ei_portio.h +++ b/lib/erl_interface/src/misc/ei_portio.h @@ -21,21 +21,94 @@ */ #ifndef _EI_PORTIO_H #define _EI_PORTIO_H -#if !defined(__WIN32__) && !defined(VXWORKS) -#ifdef HAVE_WRITEV + +#undef EI_HAVE_STRUCT_IOVEC__ +#if !defined(__WIN32__) && !defined(VXWORKS) && defined(HAVE_SYS_UIO_H) /* Declaration of struct iovec *iov should be visible in this scope. */ -#include <sys/uio.h> +# include <sys/uio.h> +# define EI_HAVE_STRUCT_IOVEC__ #endif + +/* + * Internal API. Should not be used outside of the erl_interface application... + */ + +int ei_socket_ctx__(ei_socket_callbacks *cbs, void **ctx, void *setup); +int ei_close_ctx__(ei_socket_callbacks *cbs, void *ctx); +int ei_listen_ctx__(ei_socket_callbacks *cbs, void *ctx, void *adr, int *len, int backlog); +int ei_accept_ctx_t__(ei_socket_callbacks *cbs, void **ctx, void *addr, int *len, unsigned ms); +int ei_connect_ctx_t__(ei_socket_callbacks *cbs, void *ctx, void *addr, int len, unsigned ms); +int ei_read_fill_ctx__(ei_socket_callbacks *cbs, void *ctx, char* buf, ssize_t *len); +int ei_write_fill_ctx__(ei_socket_callbacks *cbs, void *ctx, const char *buf, ssize_t *len); +int ei_read_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, char* buf, ssize_t *len, unsigned ms); +int ei_write_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, const char *buf, ssize_t *len, unsigned ms); +#if defined(EI_HAVE_STRUCT_IOVEC__) +int ei_writev_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, const struct iovec *iov, int iovcnt, ssize_t *len, unsigned ms); +int ei_socket_callbacks_have_writev__(ei_socket_callbacks *cbs); #endif -int ei_accept_t(int fd, void *addr, void *addrlen, unsigned ms); -int ei_connect_t(int fd, void *sinp, int sin_siz, unsigned ms); -int ei_read_fill(int fd, char* buf, int len); -int ei_write_fill(int fd, const char *buf, int len); -int ei_read_fill_t(int fd, char* buf, int len, unsigned ms); -int ei_write_fill_t(int fd, const char *buf, int len, unsigned ms); -#ifdef HAVE_WRITEV -int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned ms); +ei_socket_callbacks ei_default_socket_callbacks; + +#define EI_FD_AS_CTX__(FD) \ + ((void *) (long) (FD)) + +#define EI_DFLT_CTX_TO_FD__(CTX, FD) \ + ((int) (long) (CTX) < 0 \ + ? EBADF \ + : (*(FD) = (int) (long) (CTX), 0)) + +#define EI_GET_FD__(CBS, CTX, FD) \ + ((CBS) == &ei_default_socket_callbacks \ + ? EI_DFLT_CTX_TO_FD__((CTX), FD) \ + : (CBS)->get_fd((CTX), (FD))) + +extern int ei_plugin_socket_impl__; + +#if !defined(_REENTRANT) + +#define EI_HAVE_PLUGIN_SOCKET_IMPL__ \ + ei_plugin_socket_impl__ +#define EI_SET_HAVE_PLUGIN_SOCKET_IMPL__ \ + ei_plugin_socket_impl__ = 1 + +#elif ((ETHR_HAVE___atomic_load_n & SIZEOF_INT) \ + && (ETHR_HAVE___atomic_store_n & SIZEOF_INT)) + +#define EI_HAVE_PLUGIN_SOCKET_IMPL__ \ + __atomic_load_n(&ei_plugin_socket_impl__, __ATOMIC_ACQUIRE) +#define EI_SET_HAVE_PLUGIN_SOCKET_IMPL__ \ + __atomic_store_n(&ei_plugin_socket_impl__, 1, __ATOMIC_RELEASE) + +#else + +/* No gcc atomics; always lookup using ei_get_cbs_ctx()... */ +#define EI_HAVE_PLUGIN_SOCKET_IMPL__ 0 +#define EI_SET_HAVE_PLUGIN_SOCKET_IMPL__ (void) 0 + +#endif + +#define EI_GET_CBS_CTX__(CBS, CTX, FD) \ + (EI_HAVE_PLUGIN_SOCKET_IMPL__ \ + ? ei_get_cbs_ctx__((CBS), (CTX), (FD)) \ + : ((FD) < 0 \ + ? EBADF \ + : (*(CBS) = &ei_default_socket_callbacks, \ + *(CTX) = EI_FD_AS_CTX__((FD)), \ + 0))) +/* + * The following uses our own TCP/IPv4 socket implementation... + */ +int ei_socket__(int *fd); +int ei_close__(int fd); +int ei_listen__(int fd, void *adr, int *len, int backlog); +int ei_accept_t__(int *fd, void *addr, int *len, unsigned ms); +int ei_connect_t__(int fd, void *addr, int len, unsigned ms); +int ei_read_fill__(int fd, char* buf, ssize_t *len); +int ei_write_fill__(int fd, const char *buf, ssize_t *len); +int ei_read_fill_t__(int fd, char* buf, ssize_t *len, unsigned ms); +int ei_write_fill_t__(int fd, const char *buf, ssize_t *len, unsigned ms); +#if defined(EI_HAVE_STRUCT_IOVEC__) && defined(HAVE_WRITEV) +int ei_writev_fill_t__(int fd, const struct iovec *iov, int iovcnt, ssize_t *len, unsigned ms); #endif #endif /* _EI_PORTIO_H */ diff --git a/lib/erl_interface/src/not_used/send_link.c b/lib/erl_interface/src/not_used/send_link.c index 7be476fd93..38fae27df4 100644 --- a/lib/erl_interface/src/not_used/send_link.c +++ b/lib/erl_interface/src/not_used/send_link.c @@ -50,6 +50,7 @@ static int link_unlink(int fd, const erlang_pid *from, const erlang_pid *to, char *s; int index = 0; int n; + unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms; index = 5; /* max sizes: */ ei_encode_version(msgbuf,&index); /* 1 */ @@ -69,7 +70,7 @@ static int link_unlink(int fd, const erlang_pid *from, const erlang_pid *to, if (ei_trace_distribution > 1) ei_show_sendmsg(stderr,msgbuf,NULL); #endif - n = ei_write_fill_t(fd,msgbuf,index,ms); + n = ei_write_fill_t__(fd,msgbuf,index,tmo); return (n==index ? 0 : -1); } diff --git a/lib/erl_interface/test/ei_accept_SUITE.erl b/lib/erl_interface/test/ei_accept_SUITE.erl index 78a433d21b..9c9c3f86b6 100644 --- a/lib/erl_interface/test/ei_accept_SUITE.erl +++ b/lib/erl_interface/test/ei_accept_SUITE.erl @@ -81,12 +81,10 @@ ei_accept(Config) when is_list(Config) -> ei_threaded_accept(Config) when is_list(Config) -> Einode = filename:join(proplists:get_value(data_dir, Config), "eiaccnode"), - N = 1, % 3, + N = 3, Host = atom_to_list(node()), - Port = 6767, - start_einode(Einode, N, Host, Port), + start_einode(Einode, N, Host), io:format("started eiaccnode"), - %%spawn_link(fun() -> start_einode(Einode, N, Host, Port) end), TestServerPid = self(), [spawn_link(fun() -> send_rec_einode(I, TestServerPid) end) || I <- lists:seq(0, N-1)], [receive I -> ok end || I <- lists:seq(0, N-1) ], @@ -159,10 +157,9 @@ send_rec_einode(N, TestServerPid) -> ct:fail(EINode) end. -start_einode(Einode, N, Host, Port) -> +start_einode(Einode, N, Host) -> Einodecmd = Einode ++ " " ++ atom_to_list(erlang:get_cookie()) - ++ " " ++ integer_to_list(N) ++ " " ++ Host ++ " " - ++ integer_to_list(Port) ++ " nothreads", + ++ " " ++ integer_to_list(N) ++ " " ++ Host, io:format("Einodecmd ~p ~n", [Einodecmd]), open_port({spawn, Einodecmd}, []), ok. diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c index 50df848b69..c209f506b1 100644 --- a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c +++ b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c @@ -74,6 +74,8 @@ TESTCASE(interpret) int i; ei_term term; + ei_init(); + ei_x_new(&x); while (get_bin_term(&x, &term) == 0) { char* buf = x.buff, func[MAXATOMLEN]; @@ -125,45 +127,26 @@ static void cmd_ei_connect_init(char* buf, int len) ei_x_free(&res); } -static int my_listen(int port) -{ - int listen_fd; - struct sockaddr_in addr; - const char *on = "1"; - - if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - return -1; - - setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, on, sizeof(on)); - - memset((void*) &addr, 0, (size_t) sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) - return -1; - - listen(listen_fd, 5); - return listen_fd; -} - static void cmd_ei_publish(char* buf, int len) { int index = 0; - int listen, r; - long port; + int iport, lfd, r; + long lport; ei_x_buff x; int i; /* get port */ - if (ei_decode_long(buf, &index, &port) < 0) + if (ei_decode_long(buf, &index, &lport) < 0) fail("expected int (port)"); /* Make a listen socket */ - if ((listen = my_listen(port)) <= 0) + + iport = (int) lport; + lfd = ei_listen(&ec, &iport, 5); + if (lfd < 0) fail("listen"); + lport = (long) iport; - if ((i = ei_publish(&ec, port)) == -1) + if ((i = ei_publish(&ec, lport)) == -1) fail("ei_publish"); #ifdef VXWORKS save_fd(i); @@ -171,7 +154,7 @@ static void cmd_ei_publish(char* buf, int len) /* send listen-fd, result and errno */ ei_x_new_with_version(&x); ei_x_encode_tuple_header(&x, 3); - ei_x_encode_long(&x, listen); + ei_x_encode_long(&x, (long) lfd); ei_x_encode_long(&x, i); ei_x_encode_long(&x, erl_errno); send_bin_term(&x); diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c b/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c index 308f843530..90c7a2259f 100644 --- a/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c +++ b/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c @@ -47,8 +47,6 @@ #define MAIN main #endif -static int my_listen(int port); - /* A small einode. To be called from the test case ei_accept_SUITE:multi_thread @@ -64,7 +62,6 @@ static int my_listen(int port); */ static const char* cookie, * desthost; -static int port; /* actually base port */ #ifndef SD_SEND #ifdef SHUTWR @@ -74,10 +71,6 @@ static int port; /* actually base port */ #endif #endif -#ifndef __WIN32__ -#define closesocket(fd) close(fd) -#endif - #ifdef __WIN32__ static DWORD WINAPI #else @@ -86,26 +79,32 @@ static void* einode_thread(void* num) { int n = (int)num; + int port; ei_cnode ec; - char myname[100], destname[100]; + char myname[100], destname[100], filename[100]; int r, fd, listen; ErlConnect conn; erlang_msg msg; -/* FILE* f;*/ + FILE* file; - sprintf(myname, "eiacc%d", n); - printf("thread %d (%s) listening\n", n, myname, destname); + sprintf(filename, "eiacc%d_trace.txt", n); + file = fopen(filename, "w"); + + sprintf(myname, "eiacc%d", n); fflush(file); r = ei_connect_init(&ec, myname, cookie, 0); - if ((listen = my_listen(port+n)) <= 0) { - printf("listen err\n"); + port = 0; + listen = ei_listen(&ec, &port, 5); + if (listen <= 0) { + fprintf(file, "listen err\n"); fflush(file); exit(7); } - if (ei_publish(&ec, port + n) == -1) { - printf("ei_publish port %d\n", port+n); + fprintf(file, "thread %d (%s:%s) listening on port %d\n", n, myname, destname, port); + if (ei_publish(&ec, port) == -1) { + fprintf(file, "ei_publish port %d\n", port+n); fflush(file); exit(8); } fd = ei_accept(&ec, listen, &conn); - printf("ei_accept %d\n", fd); + fprintf(file, "ei_accept %d\n", fd); fflush(file); if (fd >= 0) { ei_x_buff x, xs; int index, version; @@ -117,37 +116,38 @@ static void* if (got == ERL_TICK) continue; if (got == ERL_ERROR) { - printf("receive error %d\n", n); + fprintf(file, "receive error %d\n", n); fflush(file); return 0; } - printf("received %d\n", got); + fprintf(file, "received %d\n", got); fflush(file); break; } index = 0; if (ei_decode_version(x.buff, &index, &version) != 0) { - printf("ei_decode_version %d\n", n); + fprintf(file, "ei_decode_version %d\n", n); fflush(file); return 0; } if (ei_decode_pid(x.buff, &index, &pid) != 0) { - printf("ei_decode_pid %d\n", n); + fprintf(file, "ei_decode_pid %d\n", n); fflush(file); return 0; } -/* fprintf(f, "got pid from %s \n", pid.node);*/ + fprintf(file, "got pid from %s \n", pid.node); fflush(file); ei_x_new_with_version(&xs); ei_x_encode_tuple_header(&xs, 2); ei_x_encode_long(&xs, n); ei_x_encode_pid(&xs, &pid); r = ei_send(fd, &pid, xs.buff, xs.index); -/* fprintf(f, "sent %d bytes %d\n", xs.index, r);*/ + fprintf(file, "sent %d bytes %d\n", xs.index, r); fflush(file); shutdown(fd, SD_SEND); - closesocket(fd); + ei_close_connection(fd); ei_x_free(&x); ei_x_free(&xs); } else { - printf("coudn't connect fd %d r %d\n", fd, r); + fprintf(file, "coudn't connect fd %d r %d\n", fd, r); fflush(file); } - printf("done thread %d\n", n); -/* fclose(f);*/ + ei_close_connection(listen); + fprintf(file, "done thread %d\n", n); + fclose(file); return 0; } @@ -170,12 +170,16 @@ MAIN(int argc, char *argv[]) if (n > 100) exit(2); desthost = argv[3]; - port = atoi(argv[4]); -#ifndef VXWORKS - no_threads = argv[5] != NULL && strcmp(argv[5], "nothreads") == 0; -#else + if (argc == 3) + no_threads = 0; + else + no_threads = argv[4] != NULL && strcmp(argv[4], "nothreads") == 0; +#ifdef VXWORKS no_threads = 1; #endif + + ei_init(); + for (i = 0; i < n; ++i) { if (!no_threads) { #ifndef VXWORKS @@ -209,27 +213,3 @@ MAIN(int argc, char *argv[]) printf("ok\n"); return 0; } - -static int my_listen(int port) -{ - int listen_fd; - struct sockaddr_in addr; - const char *on = "1"; - - if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - return -1; - - setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, on, sizeof(on)); - - memset((void*) &addr, 0, (size_t) sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) - return -1; - - listen(listen_fd, 5); - return listen_fd; -} - diff --git a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c index 29c03d7604..58c0c7f8d8 100644 --- a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c +++ b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c @@ -73,6 +73,8 @@ TESTCASE(interpret) int i; ei_term term; + ei_init(); + ei_x_new(&x); while (get_bin_term(&x, &term) == 0) { char* buf = x.buff, func[MAXATOMLEN]; diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c index f945a7d378..e516f310b6 100644 --- a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c +++ b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c @@ -321,6 +321,8 @@ int ei_decode_my_string(const char *buf, int *index, char *to, TESTCASE(test_ei_decode_long) { + ei_init(); + EI_DECODE_2 (decode_long, 2, long, 0); EI_DECODE_2 (decode_long, 2, long, 255); EI_DECODE_2 (decode_long, 5, long, 256); @@ -363,6 +365,8 @@ TESTCASE(test_ei_decode_long) TESTCASE(test_ei_decode_ulong) { + ei_init(); + EI_DECODE_2 (decode_ulong, 2, unsigned long, 0); EI_DECODE_2 (decode_ulong, 2, unsigned long, 255); EI_DECODE_2 (decode_ulong, 5, unsigned long, 256); @@ -409,6 +413,8 @@ TESTCASE(test_ei_decode_ulong) TESTCASE(test_ei_decode_longlong) { + ei_init(); + #ifndef VXWORKS EI_DECODE_2 (decode_longlong, 2, EI_LONGLONG, 0); EI_DECODE_2 (decode_longlong, 2, EI_LONGLONG, 255); @@ -443,6 +449,8 @@ TESTCASE(test_ei_decode_longlong) TESTCASE(test_ei_decode_ulonglong) { + ei_init(); + #ifndef VXWORKS EI_DECODE_2 (decode_ulonglong, 2, EI_ULONGLONG, 0); EI_DECODE_2 (decode_ulonglong, 2, EI_ULONGLONG, 255); @@ -478,6 +486,8 @@ TESTCASE(test_ei_decode_ulonglong) TESTCASE(test_ei_decode_char) { + ei_init(); + EI_DECODE_2(decode_char, 2, char, 0); EI_DECODE_2(decode_char, 2, char, 0x7f); EI_DECODE_2(decode_char, 2, char, 0xff); @@ -491,6 +501,8 @@ TESTCASE(test_ei_decode_char) TESTCASE(test_ei_decode_nonoptimal) { + ei_init(); + EI_DECODE_2(decode_char, 2, char, 42); EI_DECODE_2(decode_char, 5, char, 42); EI_DECODE_2(decode_char, 4, char, 42); @@ -612,6 +624,8 @@ TESTCASE(test_ei_decode_nonoptimal) TESTCASE(test_ei_decode_misc) { + ei_init(); + /* EI_DECODE_0(decode_version); */ @@ -647,6 +661,7 @@ TESTCASE(test_ei_decode_misc) TESTCASE(test_ei_decode_utf8_atom) { + ei_init(); EI_DECODE_STRING_4(decode_my_atom_as, 4, P99({229,0}), /* LATIN1 "�" */ P99({ERLANG_ANY,ERLANG_LATIN1,ERLANG_LATIN1})); diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c index 9977683d59..55d9ed1b1a 100644 --- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c +++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c @@ -477,6 +477,8 @@ TESTCASE(test_ei_decode_encode) { int i; + ei_init(); + decode_encode_one(&fun_type); decode_encode_one(&pid_type); decode_encode_one(&port_type); diff --git a/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c b/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c index 32811fdf22..6f63cc5d7e 100644 --- a/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c +++ b/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c @@ -403,6 +403,8 @@ TESTCASE(test_ei_encode_long) { + ei_init(); + EI_ENCODE_1(encode_long, 0); EI_ENCODE_1(encode_long, 255); @@ -430,6 +432,8 @@ TESTCASE(test_ei_encode_long) TESTCASE(test_ei_encode_ulong) { + ei_init(); + EI_ENCODE_1(encode_ulong, 0); EI_ENCODE_1(encode_ulong, 255); @@ -454,6 +458,7 @@ TESTCASE(test_ei_encode_ulong) TESTCASE(test_ei_encode_longlong) { + ei_init(); #ifndef VXWORKS @@ -494,6 +499,7 @@ TESTCASE(test_ei_encode_longlong) TESTCASE(test_ei_encode_ulonglong) { + ei_init(); #ifndef VXWORKS @@ -527,6 +533,8 @@ TESTCASE(test_ei_encode_ulonglong) TESTCASE(test_ei_encode_char) { + ei_init(); + EI_ENCODE_1(encode_char, 0); EI_ENCODE_1(encode_char, 0x7f); @@ -540,6 +548,8 @@ TESTCASE(test_ei_encode_char) TESTCASE(test_ei_encode_misc) { + ei_init(); + EI_ENCODE_0(encode_version); EI_ENCODE_1(encode_double, 0.0); @@ -594,6 +604,8 @@ TESTCASE(test_ei_encode_fails) char buf[1024]; int index; + ei_init(); + /* FIXME the ei_x versions are not tested */ index = 0; @@ -660,6 +672,7 @@ TESTCASE(test_ei_encode_fails) TESTCASE(test_ei_encode_utf8_atom) { + ei_init(); EI_ENCODE_3(encode_atom_as, "�", ERLANG_LATIN1, ERLANG_UTF8); EI_ENCODE_3(encode_atom_as, "�", ERLANG_LATIN1, ERLANG_LATIN1); @@ -686,6 +699,7 @@ TESTCASE(test_ei_encode_utf8_atom) TESTCASE(test_ei_encode_utf8_atom_len) { + ei_init(); EI_ENCODE_4(encode_atom_len_as, "���", 1, ERLANG_LATIN1, ERLANG_UTF8); EI_ENCODE_4(encode_atom_len_as, "���", 2, ERLANG_LATIN1, ERLANG_LATIN1); diff --git a/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c b/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c index 8450332b28..1c0443c0f4 100644 --- a/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c +++ b/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c @@ -48,6 +48,8 @@ send_format(char* format) TESTCASE(atoms) { + ei_init(); + send_format("''"); send_format("'a'"); send_format("'A'"); @@ -82,6 +84,8 @@ TESTCASE(atoms) TESTCASE(tuples) { + ei_init(); + send_format("{}"); send_format("{a}"); send_format("{a, b}"); @@ -108,6 +112,8 @@ TESTCASE(lists) ei_x_buff x; static char str[65537]; + ei_init(); + send_format("[]"); send_format("[a]"); send_format("[a, b]"); @@ -177,6 +183,8 @@ TESTCASE(format_wo_ver) { */ ei_x_buff x; + ei_init(); + ei_x_new (&x); ei_x_format(&x, "[-1, +2, ~c, {~a,~s},{~a,~i}]", 'c', "a", "b", "c", 10); send_bin_term(&x); diff --git a/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c b/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c index 15cfbcae34..80be3016e6 100644 --- a/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c +++ b/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c @@ -84,6 +84,8 @@ static void send_printed3f(char* format, float f1, float f2) TESTCASE(atoms) { + ei_init(); + send_printed("''"); send_printed("'a'"); send_printed("'A'"); @@ -118,6 +120,8 @@ TESTCASE(atoms) TESTCASE(tuples) { + ei_init(); + send_printed("{}"); send_printed("{a}"); send_printed("{a, b}"); @@ -138,6 +142,8 @@ TESTCASE(lists) { ei_x_buff x; + ei_init(); + send_printed("[]"); send_printed("[a]"); send_printed("[a, b]"); @@ -164,6 +170,8 @@ TESTCASE(strings) { ei_x_buff x; + ei_init(); + send_printed("\"\n\""); send_printed("\"\r\n\""); send_printed("\"a\""); diff --git a/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c b/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c index 39846e4a58..693e405f75 100644 --- a/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c +++ b/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c @@ -96,6 +96,8 @@ TESTCASE(framework_check) int i; #endif + ei_init(); + OPEN_DEBUGFILE(1); DEBUGF(("B�rjar... \n")); @@ -340,6 +342,7 @@ TESTCASE(recv_tmo) int com_sock = -1; ei_cnode nodeinfo; + ei_init(); OPEN_DEBUGFILE(5); @@ -450,6 +453,7 @@ TESTCASE(send_tmo) int com_sock = -1; ei_cnode nodeinfo; + ei_init(); OPEN_DEBUGFILE(4); @@ -591,7 +595,7 @@ TESTCASE(connect_tmo) int com_sock = -1; ei_cnode nodeinfo; - + ei_init(); OPEN_DEBUGFILE(3); @@ -680,7 +684,7 @@ TESTCASE(accept_tmo) ErlConnect peer; ei_cnode nodeinfo; - + ei_init(); OPEN_DEBUGFILE(2); diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c b/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c index bead0f8413..b87feb9dfc 100644 --- a/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c +++ b/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c @@ -20,7 +20,7 @@ #include <stdlib.h> #include <stdio.h> - +#include <string.h> #include "ei.h" #include "erl_interface.h" @@ -68,6 +68,7 @@ MAIN(int argc, char **argv) char host[80]; int number; ETERM *ref, *ref1, *ref2; + FILE *dfile = fopen("cnode_debug_printout", "w"); erl_init(NULL, 0); @@ -80,28 +81,30 @@ MAIN(int argc, char **argv) gethostname(host, sizeof(host)); sprintf(node, "c%d@%s", number, host); - printf("s = %d\n", s); + fprintf(dfile, "s = %d\n", s); fflush(dfile); sprintf(server, "test_server@%s", host); fd = erl_connect(server); - printf("fd = %d\n", fd); + fprintf(dfile, "fd = %d\n", fd); -/* printf("dist = %d\n", erl_distversion(fd)); */ +/* fprintf(dfile, "dist = %d\n", erl_distversion(fd)); */ #if 1 ref = erl_mk_long_ref(node, 4711, 113, 98, 0); #else ref = erl_mk_ref(node, 4711, 0); #endif - printf("ref = %d\n", ref); + fprintf(dfile, "ref = %p\n", ref); fflush(dfile); s = erl_reg_send(fd, "mip", ref); - printf("s = %d\n", s); + fprintf(dfile, "s = %d\n", s); fflush(dfile); { ETERM* emsg; emsg = SELF(fd); - erl_reg_send(fd,"mip",emsg); + fprintf(dfile, "pid = %p\n", emsg); fflush(dfile); + s = erl_reg_send(fd,"mip",emsg); + fprintf(dfile, "s2 = %d\n", s); fflush(dfile); erl_free_term(emsg); } @@ -116,28 +119,29 @@ MAIN(int argc, char **argv) #endif switch (s) { case ERL_TICK: - printf("tick\n"); + fprintf(dfile, "tick\n"); break; case ERL_ERROR: - printf("error\n"); + fprintf(dfile, "error: %s (%d)\n", strerror(erl_errno), erl_errno); break; case ERL_MSG: - printf("msg %d\n", msgsize); + fprintf(dfile, "msg %d\n", msgsize); break; default: - printf("unknown result %d\n", s); + fprintf(dfile, "unknown result %d\n", s); break; } + fflush(dfile); } while (s == ERL_TICK); s = erl_reg_send(fd, "mip", msg.msg); - printf("s = %d\n", s); + fprintf(dfile, "s = %d\n", s); fflush(dfile); s = erl_reg_send(fd, "mip", msg.to); - printf("s = %d\n", s); + fprintf(dfile, "s = %d\n", s); fflush(dfile); #if 0 /* from = NULL! */ s = erl_reg_send(fd, "mip", msg.from); - printf("s = %d\n", s); + fprintf(dfile, "s = %d\n", s); fflush(dfile); #endif #if 0 @@ -150,17 +154,19 @@ MAIN(int argc, char **argv) ref1 = erl_mk_long_ref(node, 4711, 113, 98, 0); ref2 = erl_mk_ref(node, 4711, 0); s = erl_encode(ref1, buf1); - printf("enc1 s = %d\n", s); + fprintf(dfile, "enc1 s = %d\n", s); fflush(dfile); s = erl_encode(ref2, buf2); - printf("enc2 s = %d\n", s); + fprintf(dfile, "enc2 s = %d\n", s); fflush(dfile); s = erl_compare_ext(buf1, buf2); - printf("comp s = %d\n", s); + fprintf(dfile, "comp s = %d\n", s); fflush(dfile); /* Compare, in another way */ s = erl_match(ref1, ref2); - printf("match s = %d\n", s); + fprintf(dfile, "match s = %d\n", s); fflush(dfile); #endif + fclose(dfile); + erl_close_connection(fd); return 0; diff --git a/lib/et/doc/src/et.xml b/lib/et/doc/src/et.xml index 3009b559e1..a362d00b3e 100644 --- a/lib/et/doc/src/et.xml +++ b/lib/et/doc/src/et.xml @@ -32,14 +32,14 @@ <rev>%VSN%</rev> <file>et</file> </header> - <module>et</module> + <module since="">et</module> <modulesummary>Main API of the Event Trace (ET) application</modulesummary> <description> <p>Interface module for the Event Trace (ET) application</p> </description> <funcs> <func> - <name>trace_me(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name> + <name since="OTP R13B04">trace_me(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name> <fsummary>A function that is intended to be traced.</fsummary> <type> <v>DetailLevel = integer(X) when X =< 0, X >= 100</v> @@ -70,7 +70,7 @@ </func> <func> - <name>trace_me(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name> + <name since="OTP R13B04">trace_me(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name> <fsummary>A function that is intended to be traced.</fsummary> <desc> <p>Invokes <c>et:trace_me/5</c> with both <c>From</c> and <c>To</c> @@ -79,8 +79,8 @@ </func> <func> - <name>phone_home(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name> - <name>phone_home(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name> + <name since="">phone_home(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name> + <name since="">phone_home(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name> <fsummary>Send a signal to the outer space</fsummary> <desc> <p>These functions sends a signal to the outer space and the @@ -90,8 +90,8 @@ </desc> </func> <func> - <name>report_event(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name> - <name>report_event(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name> + <name since="">report_event(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name> + <name since="">report_event(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name> <fsummary>Deprecated functions</fsummary> <desc> <p>Deprecated functions which for the time being are kept for diff --git a/lib/et/doc/src/et_collector.xml b/lib/et/doc/src/et_collector.xml index fd90ecfc41..f908612797 100644 --- a/lib/et/doc/src/et_collector.xml +++ b/lib/et/doc/src/et_collector.xml @@ -32,14 +32,14 @@ <rev>%VSN%</rev> <file>et_collector.xml</file> </header> - <module>et_collector</module> + <module since="">et_collector</module> <modulesummary>Collect trace events and provide a backing storage appropriate for iteration </modulesummary> <description> <p>Interface module for the Event Trace (ET) application</p> </description> <funcs> <func> - <name>start_link(Options) -> {ok, CollectorPid} | {error, Reason}</name> + <name since="">start_link(Options) -> {ok, CollectorPid} | {error, Reason}</name> <fsummary>Start a collector process</fsummary> <type> <v>Options = [option()]</v> @@ -105,7 +105,7 @@ </desc> </func> <func> - <name>stop(CollectorPid) -> ok</name> + <name since="">stop(CollectorPid) -> ok</name> <fsummary>Stop a collector process</fsummary> <type> <v>CollectorPid = pid()</v> @@ -115,7 +115,7 @@ </desc> </func> <func> - <name>save_event_file(CollectorPid, FileName, Options) -> ok | {error, Reason}</name> + <name since="">save_event_file(CollectorPid, FileName, Options) -> ok | {error, Reason}</name> <fsummary>Save the events to a file</fsummary> <type> <v>CollectorPid = pid()</v> @@ -139,7 +139,7 @@ </desc> </func> <func> - <name>load_event_file(CollectorPid, FileName) -> {ok, BadBytes} | exit(Reason)</name> + <name since="">load_event_file(CollectorPid, FileName) -> {ok, BadBytes} | exit(Reason)</name> <fsummary>Load the event table from a file</fsummary> <type> <v>CollectorPid = pid()</v> @@ -152,9 +152,9 @@ </desc> </func> <func> - <name>report(Handle, TraceOrEvent) -> {ok, Continuation} | exit(Reason)</name> - <name>report_event(Handle, DetailLevel, FromTo, Label, Contents) -> {ok, Continuation} | exit(Reason)</name> - <name>report_event(Handle, DetailLevel, From, To, Label, Contents) -> {ok, Continuation} | exit(Reason)</name> + <name since="">report(Handle, TraceOrEvent) -> {ok, Continuation} | exit(Reason)</name> + <name since="">report_event(Handle, DetailLevel, FromTo, Label, Contents) -> {ok, Continuation} | exit(Reason)</name> + <name since="">report_event(Handle, DetailLevel, From, To, Label, Contents) -> {ok, Continuation} | exit(Reason)</name> <fsummary>Report an event to the collector</fsummary> <type> <v>Handle = Initial | Continuation</v> @@ -181,7 +181,7 @@ </desc> </func> <func> - <name>make_key(Type, Stuff) -> Key</name> + <name since="">make_key(Type, Stuff) -> Key</name> <fsummary>Make a key out of an event record or an old key</fsummary> <type> <v>Type = record(table_handle) | trace_ts | event_ts</v> @@ -193,7 +193,7 @@ </desc> </func> <func> - <name>get_table_handle(CollectorPid) -> Handle</name> + <name since="">get_table_handle(CollectorPid) -> Handle</name> <fsummary>Return a table handle</fsummary> <type> <v>CollectorPid = pid()</v> @@ -204,7 +204,7 @@ </desc> </func> <func> - <name>get_global_pid() -> CollectorPid | exit(Reason)</name> + <name since="">get_global_pid() -> CollectorPid | exit(Reason)</name> <fsummary>Return a the identity of the globally registered collector if there is any</fsummary> <type> <v>CollectorPid = pid()</v> @@ -216,7 +216,7 @@ </desc> </func> <func> - <name>change_pattern(CollectorPid, RawPattern) -> {old_pattern, TracePattern}</name> + <name since="">change_pattern(CollectorPid, RawPattern) -> {old_pattern, TracePattern}</name> <fsummary>Change active trace pattern globally on all trace nodes</fsummary> <type> <v>CollectorPid = pid()</v> @@ -232,9 +232,9 @@ </desc> </func> <func> - <name>dict_insert(CollectorPid, {filter, collector}, FilterFun) -> ok</name> - <name>dict_insert(CollectorPid, {subscriber, SubscriberPid}, Void) -> ok</name> - <name>dict_insert(CollectorPid, Key, Val) -> ok</name> + <name since="">dict_insert(CollectorPid, {filter, collector}, FilterFun) -> ok</name> + <name since="">dict_insert(CollectorPid, {subscriber, SubscriberPid}, Void) -> ok</name> + <name since="">dict_insert(CollectorPid, Key, Val) -> ok</name> <fsummary>Insert a dictionary entry and send a {et, {dict_insert, Key, Val}} tuple to all registered subscribers.</fsummary> <type> <v>CollectorPid = pid()</v> @@ -259,7 +259,7 @@ </desc> </func> <func> - <name>dict_lookup(CollectorPid, Key) -> [Val]</name> + <name since="">dict_lookup(CollectorPid, Key) -> [Val]</name> <fsummary>Lookup a dictionary entry and return zero or one value</fsummary> <type> <v>CollectorPid = pid()</v> @@ -273,7 +273,7 @@ </desc> </func> <func> - <name>dict_delete(CollectorPid, Key) -> ok</name> + <name since="">dict_delete(CollectorPid, Key) -> ok</name> <fsummary>Delete a dictionary entry and send a {et, {dict_delete, Key}} tuple to all registered subscribers.</fsummary> <type> <v>CollectorPid = pid()</v> @@ -290,7 +290,7 @@ </desc> </func> <func> - <name>dict_match(CollectorPid, Pattern) -> [Match]</name> + <name since="">dict_match(CollectorPid, Pattern) -> [Match]</name> <fsummary>Match some dictionary entries</fsummary> <type> <v>CollectorPid = pid()</v> @@ -306,7 +306,7 @@ </desc> </func> <func> - <name>multicast(_CollectorPid, Msg) -> ok</name> + <name since="">multicast(_CollectorPid, Msg) -> ok</name> <fsummary>Sends a message to all registered subscribers</fsummary> <type> <v>CollectorPid = pid()</v> @@ -318,7 +318,7 @@ </desc> </func> <func> - <name>start_trace_client(CollectorPid, Type, Parameters) -> file_loaded | {trace_client_pid, pid()} | exit(Reason)</name> + <name since="">start_trace_client(CollectorPid, Type, Parameters) -> file_loaded | {trace_client_pid, pid()} | exit(Reason)</name> <fsummary>Load raw Erlang trace from a file, port or process.</fsummary> <type> <v>Type = dbg_trace_client_type()</v> @@ -330,14 +330,14 @@ </desc> </func> <func> - <name>iterate(Handle, Prev, Limit) -> NewAcc</name> + <name since="">iterate(Handle, Prev, Limit) -> NewAcc</name> <fsummary>Iterates over the currently stored events</fsummary> <desc> <p>Short for iterate(Handle, Prev, Limit, undefined, Prev) -> NewAcc</p> </desc> </func> <func> - <name>iterate(Handle, Prev, Limit, Fun, Acc) -> NewAcc</name> + <name since="">iterate(Handle, Prev, Limit, Fun, Acc) -> NewAcc</name> <fsummary>Iterate over the currently stored events</fsummary> <type> <v>Handle = collector_pid() | table_handle()</v> @@ -361,7 +361,7 @@ </desc> </func> <func> - <name>clear_table(Handle) -> ok</name> + <name since="">clear_table(Handle) -> ok</name> <fsummary>Clear the event table</fsummary> <type> <v>Handle = collector_pid() | table_handle()</v> diff --git a/lib/et/doc/src/et_selector.xml b/lib/et/doc/src/et_selector.xml index 30ca74c872..3c766cafb7 100644 --- a/lib/et/doc/src/et_selector.xml +++ b/lib/et/doc/src/et_selector.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>et_selector.xml</file> </header> - <module>et_selector</module> + <module since="">et_selector</module> <modulesummary>Define event transforms and trace patterns</modulesummary> <description> <p></p> @@ -40,7 +40,7 @@ <funcs> <func> - <name>make_pattern(RawPattern) -> TracePattern</name> + <name since="">make_pattern(RawPattern) -> TracePattern</name> <fsummary>Makes a trace pattern suitable to feed change_pattern/1</fsummary> <type> @@ -61,7 +61,7 @@ </func> <func> - <name>change_pattern(Pattern) -> ok</name> + <name since="">change_pattern(Pattern) -> ok</name> <fsummary>Activates/deactivates tracing by changing the current trace pattern</fsummary> @@ -85,7 +85,7 @@ </desc> </func> <func> - <name>parse_event(Mod, ValidTraceData) -> false | true | {true, Event}</name> + <name since="">parse_event(Mod, ValidTraceData) -> false | true | {true, Event}</name> <fsummary>Transforms trace data and makes an event record out of it</fsummary> diff --git a/lib/et/doc/src/et_viewer.xml b/lib/et/doc/src/et_viewer.xml index e0b39636e9..9d59eef668 100644 --- a/lib/et/doc/src/et_viewer.xml +++ b/lib/et/doc/src/et_viewer.xml @@ -32,14 +32,14 @@ <rev>%VSN%</rev> <file>et_viewer.xml</file> </header> - <module>et_viewer</module> + <module since="">et_viewer</module> <modulesummary>Displays a sequence chart for trace events (messages/actions)</modulesummary> <description> <p></p> </description> <funcs> <func> - <name>file(FileName) -> {ok, ViewerPid} | {error, Reason}</name> + <name since="">file(FileName) -> {ok, ViewerPid} | {error, Reason}</name> <fsummary>Start a new event viewer and a corresponding collector and load them with trace events from a trace file.</fsummary> <type> <v>FileName() = string()</v> @@ -52,7 +52,7 @@ </desc> </func> <func> - <name>start() -> ok</name> + <name since="">start() -> ok</name> <fsummary>Simplified start of a sequence chart viewer with global tracing activated.</fsummary> <desc> <p>Simplified start of a sequence chart viewer with @@ -62,7 +62,7 @@ </desc> </func> <func> - <name>start(Options) -> ok</name> + <name since="">start(Options) -> ok</name> <fsummary>Start of a sequence chart viewer without linking to the parent process.</fsummary> <desc> <p>Start of a sequence chart viewer without linking @@ -70,7 +70,7 @@ </desc> </func> <func> - <name>start_link(Options) -> {ok, ViewerPid} | {error, Reason}</name> + <name since="">start_link(Options) -> {ok, ViewerPid} | {error, Reason}</name> <fsummary>Start a sequence chart viewer for trace events (messages/actions)</fsummary> <type> <v>Options = [option() | collector_option()]</v> @@ -125,7 +125,7 @@ </desc> </func> <func> - <name>get_collector_pid(ViewerPid) -> CollectorPid</name> + <name since="">get_collector_pid(ViewerPid) -> CollectorPid</name> <fsummary>Returns the identifier of the collector process</fsummary> <type> <v>ViewerPid = pid()</v> @@ -136,7 +136,7 @@ </desc> </func> <func> - <name>stop(ViewerPid) -> ok</name> + <name since="">stop(ViewerPid) -> ok</name> <fsummary>Stops a viewer</fsummary> <type> <v>ViewerPid = pid()</v> diff --git a/lib/ftp/doc/src/ftp.xml b/lib/ftp/doc/src/ftp.xml index 34e3ff84b0..9645b03364 100644 --- a/lib/ftp/doc/src/ftp.xml +++ b/lib/ftp/doc/src/ftp.xml @@ -29,7 +29,7 @@ <rev>B</rev> <file>ftp.xml</file> </header> - <module>ftp</module> + <module since="">ftp</module> <modulesummary>A File Transfer Protocol client.</modulesummary> <description> @@ -272,7 +272,7 @@ <funcs> <func> - <name>account(Pid, Account) -> ok | {error, Reason}</name> + <name since="">account(Pid, Account) -> ok | {error, Reason}</name> <fsummary>Specifies which account to use.</fsummary> <type> <v>Pid = pid()</v> @@ -289,8 +289,8 @@ </func> <func> - <name>append(Pid, LocalFile) -> </name> - <name>append(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name> + <name since="">append(Pid, LocalFile) -> </name> + <name since="">append(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Transfers a file to remote server, and appends it to <c>Remotefile</c>.</fsummary> <type> @@ -310,7 +310,7 @@ </func> <func> - <name>append_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name> + <name since="">append_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Transfers a binary into a remote file.</fsummary> <type> <v>Pid = pid()</v> @@ -328,7 +328,7 @@ </func> <func> - <name>append_chunk(Pid, Bin) -> ok | {error, Reason}</name> + <name since="">append_chunk(Pid, Bin) -> ok | {error, Reason}</name> <fsummary>Appends a chunk to the remote file.</fsummary> <type> <v>Pid = pid()</v> @@ -348,7 +348,7 @@ </func> <func> - <name>append_chunk_start(Pid, File) -> ok | {error, Reason}</name> + <name since="">append_chunk_start(Pid, File) -> ok | {error, Reason}</name> <fsummary>Starts transfer of file chunks for appending to <c>File</c>.</fsummary> <type> <v>Pid = pid()</v> @@ -365,7 +365,7 @@ </func> <func> - <name>append_chunk_end(Pid) -> ok | {error, Reason}</name> + <name since="">append_chunk_end(Pid) -> ok | {error, Reason}</name> <fsummary>Stops transfer of chunks for appending.</fsummary> <type> <v>Pid = pid()</v> @@ -381,7 +381,7 @@ </func> <func> - <name>cd(Pid, Dir) -> ok | {error, Reason}</name> + <name since="">cd(Pid, Dir) -> ok | {error, Reason}</name> <fsummary>Changes remote working directory.</fsummary> <type> <v>Pid = pid()</v> @@ -397,7 +397,7 @@ </func> <func> - <name>close(Pid) -> ok</name> + <name since="">close(Pid) -> ok</name> <fsummary>Ends the FTP session.</fsummary> <type> <v>Pid = pid()</v> @@ -411,7 +411,7 @@ </func> <func> - <name>delete(Pid, File) -> ok | {error, Reason}</name> + <name since="">delete(Pid, File) -> ok | {error, Reason}</name> <fsummary>Deletes a file at the remote server.</fsummary> <type> <v>Pid = pid()</v> @@ -426,7 +426,7 @@ </func> <func> - <name>formaterror(Tag) -> string()</name> + <name since="">formaterror(Tag) -> string()</name> <fsummary>Returns error diagnostics.</fsummary> <type> <v>Tag = {error, atom()} | atom()</v> @@ -440,7 +440,7 @@ </func> <func> - <name>lcd(Pid, Dir) -> ok | {error, Reason}</name> + <name since="">lcd(Pid, Dir) -> ok | {error, Reason}</name> <fsummary>Changes local working directory.</fsummary> <type> <v>Pid = pid()</v> @@ -455,7 +455,7 @@ </func> <func> - <name>lpwd(Pid) -> {ok, Dir}</name> + <name since="">lpwd(Pid) -> {ok, Dir}</name> <fsummary>Gets local current working directory.</fsummary> <type> <v>Pid = pid()</v> @@ -470,8 +470,8 @@ </func> <func> - <name>ls(Pid) -> </name> - <name>ls(Pid, Pathname) -> {ok, Listing} | {error, Reason}</name> + <name since="">ls(Pid) -> </name> + <name since="">ls(Pid, Pathname) -> {ok, Listing} | {error, Reason}</name> <fsummary>List of files.</fsummary> <type> <v>Pid = pid()</v> @@ -493,7 +493,7 @@ </func> <func> - <name>mkdir(Pid, Dir) -> ok | {error, Reason}</name> + <name since="">mkdir(Pid, Dir) -> ok | {error, Reason}</name> <fsummary>Creates a remote directory.</fsummary> <type> <v>Pid = pid()</v> @@ -510,8 +510,8 @@ </func> <func> - <name>nlist(Pid) -> </name> - <name>nlist(Pid, Pathname) -> {ok, Listing} | {error, Reason}</name> + <name since="">nlist(Pid) -> </name> + <name since="">nlist(Pid, Pathname) -> {ok, Listing} | {error, Reason}</name> <fsummary>List of files.</fsummary> <type> <v>Pid = pid()</v> @@ -535,8 +535,8 @@ </func> <func> - <name>open(Host) -> {ok, Pid} | {error, Reason}</name> - <name>open(Host, Opts) -> {ok, Pid} | {error, Reason}</name> + <name since="">open(Host) -> {ok, Pid} | {error, Reason}</name> + <name since="">open(Host, Opts) -> {ok, Pid} | {error, Reason}</name> <fsummary>Starts a standalone FTP client.</fsummary> <type> <v>Host = string() | ip_address()</v> @@ -550,7 +550,7 @@ <v>ipfamily() = inet | inet6 | inet6fb4 (default is inet)</v> <v>port() = integer() > 0 (default is 21)</v> <v>mode() = active | passive (default is passive)</v> - <v>tls_options() = [<seealso marker="ssl:ssl#type-ssloption">ssl:ssloption()</seealso>]</v> + <v>tls_options() = [<seealso marker="ssl:ssl#type-tls_option">ssl:tls_option()</seealso>]</v> <v>sock_opts() = [<seealso marker="kernel:gen_tcp#type-option">gen_tcp:option()</seealso> except for ipv6_v6only, active, packet, mode, packet_size and header</v> <v>timeout() = integer() > 0 (default is 60000 milliseconds)</v> <v>dtimeout() = integer() > 0 | infinity (default is infinity)</v> @@ -587,7 +587,7 @@ </func> <func> - <name>pwd(Pid) -> {ok, Dir} | {error, Reason}</name> + <name since="">pwd(Pid) -> {ok, Dir} | {error, Reason}</name> <fsummary>Gets the remote current working directory.</fsummary> <type> <v>Pid = pid()</v> @@ -603,8 +603,8 @@ </func> <func> - <name>recv(Pid, RemoteFile) -> </name> - <name>recv(Pid, RemoteFile, LocalFile) -> ok | {error, Reason}</name> + <name since="">recv(Pid, RemoteFile) -> </name> + <name since="">recv(Pid, RemoteFile, LocalFile) -> ok | {error, Reason}</name> <fsummary>Transfers a file from remote server.</fsummary> <type> <v>Pid = pid()</v> @@ -627,7 +627,7 @@ </func> <func> - <name>recv_bin(Pid, RemoteFile) -> {ok, Bin} | {error, Reason}</name> + <name since="">recv_bin(Pid, RemoteFile) -> {ok, Bin} | {error, Reason}</name> <fsummary>Transfers a file from remote server as a binary.</fsummary> <type> <v>Pid = pid()</v> @@ -644,7 +644,7 @@ </func> <func> - <name>recv_chunk_start(Pid, RemoteFile) -> ok | {error, Reason}</name> + <name since="">recv_chunk_start(Pid, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Starts chunk-reading of the remote file.</fsummary> <type> <v>Pid = pid()</v> @@ -660,7 +660,7 @@ </func> <func> - <name>recv_chunk(Pid) -> ok | {ok, Bin} | {error, Reason}</name> + <name since="">recv_chunk(Pid) -> ok | {ok, Bin} | {error, Reason}</name> <fsummary>Receives a chunk of the remote file.</fsummary> <type> <v>Pid = pid()</v> @@ -682,7 +682,7 @@ </func> <func> - <name>rename(Pid, Old, New) -> ok | {error, Reason}</name> + <name since="">rename(Pid, Old, New) -> ok | {error, Reason}</name> <fsummary>Renames a file at the remote server.</fsummary> <type> <v>Pid = pid()</v> @@ -697,7 +697,7 @@ </func> <func> - <name>rmdir(Pid, Dir) -> ok | {error, Reason}</name> + <name since="">rmdir(Pid, Dir) -> ok | {error, Reason}</name> <fsummary>Removes a remote directory.</fsummary> <type> <v>Pid = pid()</v> @@ -714,8 +714,8 @@ </func> <func> - <name>send(Pid, LocalFile) -></name> - <name>send(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name> + <name since="">send(Pid, LocalFile) -></name> + <name since="">send(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Transfers a file to the remote server.</fsummary> <type> <v>Pid = pid()</v> @@ -732,7 +732,7 @@ </func> <func> - <name>send_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name> + <name since="">send_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name> <fsummary>Transfers a binary into a remote file.</fsummary> <type> <v>Pid = pid()</v> @@ -749,7 +749,7 @@ </func> <func> - <name>send_chunk(Pid, Bin) -> ok | {error, Reason}</name> + <name since="">send_chunk(Pid, Bin) -> ok | {error, Reason}</name> <fsummary>Writes a chunk to the remote file.</fsummary> <type> <v>Pid = pid()</v> @@ -769,7 +769,7 @@ </func> <func> - <name>send_chunk_start(Pid, File) -> ok | {error, Reason}</name> + <name since="">send_chunk_start(Pid, File) -> ok | {error, Reason}</name> <fsummary>Starts transfer of file chunks.</fsummary> <type> <v>Pid = pid()</v> @@ -785,7 +785,7 @@ </func> <func> - <name>send_chunk_end(Pid) -> ok | {error, Reason}</name> + <name since="">send_chunk_end(Pid) -> ok | {error, Reason}</name> <fsummary>Stops transfer of chunks.</fsummary> <type> <v>Pid = pid()</v> @@ -801,7 +801,7 @@ </func> <func> - <name>start_service(ServiceConfig) -> {ok, Pid} | {error, Reason}</name> + <name since="OTP 21.0">start_service(ServiceConfig) -> {ok, Pid} | {error, Reason}</name> <fsummary>Dynamically starts an <c>FTP</c> session after the <c>ftp</c> application has been started.</fsummary> <type> @@ -820,7 +820,7 @@ </func> <func> - <name>stop_service(Reference) -> ok | {error, Reason} </name> + <name since="OTP 21.0">stop_service(Reference) -> ok | {error, Reason} </name> <fsummary>Stops an FTP session.</fsummary> <type> <v>Reference = pid() | term() - service-specified reference</v> @@ -832,7 +832,7 @@ </func> <func> - <name>type(Pid, Type) -> ok | {error, Reason}</name> + <name since="">type(Pid, Type) -> ok | {error, Reason}</name> <fsummary>Sets transfer type to <c>ascii</c>or <c>binary</c>.</fsummary> <type> <v>Pid = pid()</v> @@ -849,7 +849,7 @@ </func> <func> - <name>user(Pid, User, Password) -> ok | {error, Reason}</name> + <name since="">user(Pid, User, Password) -> ok | {error, Reason}</name> <fsummary>User login.</fsummary> <type> <v>Pid = pid()</v> @@ -864,7 +864,7 @@ </func> <func> - <name>user(Pid, User, Password, Account) -> ok | {error, Reason}</name> + <name since="">user(Pid, User, Password, Account) -> ok | {error, Reason}</name> <fsummary>User login.</fsummary> <type> <v>Pid = pid()</v> @@ -880,7 +880,7 @@ </func> <func> - <name>quote(Pid, Command) -> [FTPLine]</name> + <name since="">quote(Pid, Command) -> [FTPLine]</name> <fsummary>Sends an arbitrary FTP command.</fsummary> <type> <v>Pid = pid()</v> diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 48ce641ab9..799957dfdc 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -2224,11 +2224,7 @@ type_order() -> [t_number(), t_atom(), t_reference(), t_fun(), t_port(), t_pid(), t_tuple(), t_map(), t_list(), t_bitstr()]. -key_comparisons_fail(X0, KeyPos, TupleList, Opaques) -> - X = case t_is_number(t_inf(X0, t_number(), Opaques), Opaques) of - false -> X0; - true -> t_number() - end, +key_comparisons_fail(X, KeyPos, TupleList, Opaques) -> lists:all(fun(Tuple) -> Key = type(erlang, element, 2, [KeyPos, Tuple]), t_is_none(t_inf(Key, X, Opaques)) diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml index 2dec5acbf9..6d3547f4fe 100644 --- a/lib/inets/doc/src/http_uri.xml +++ b/lib/inets/doc/src/http_uri.xml @@ -30,7 +30,7 @@ <rev></rev> </header> - <module>http_uri</module> + <module since="OTP R15B01">http_uri</module> <modulesummary>URI utility module</modulesummary> <description> @@ -79,7 +79,7 @@ <funcs> <func> - <name>decode(HexEncodedURI) -> URI</name> + <name since="OTP R15B01">decode(HexEncodedURI) -> URI</name> <fsummary>Decodes a hexadecimal encoded URI.</fsummary> <type> @@ -93,7 +93,7 @@ </desc> </func> <func> - <name>encode(URI) -> HexEncodedURI</name> + <name since="OTP R15B01">encode(URI) -> HexEncodedURI</name> <fsummary>Encodes a hexadecimal encoded URI.</fsummary> <type> @@ -109,8 +109,8 @@ </func> <func> - <name>parse(URI) -> {ok, Result} | {error, Reason}</name> - <name>parse(URI, Options) -> {ok, Result} | {error, Reason}</name> + <name since="OTP R15B01">parse(URI) -> {ok, Result} | {error, Reason}</name> + <name since="OTP R15B01">parse(URI, Options) -> {ok, Result} | {error, Reason}</name> <fsummary>Parses a URI.</fsummary> <type> <v>URI = uri()</v> @@ -165,7 +165,7 @@ fun(SchemeStr :: string() | binary()) -> </func> <func> - <name>scheme_defaults() -> SchemeDefaults</name> + <name since="OTP R15B01">scheme_defaults() -> SchemeDefaults</name> <fsummary>A list of the scheme and their default ports.</fsummary> <type> <v>SchemeDefaults = [{scheme(), default_scheme_port_number()}] </v> diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index a2871f3b95..7451b314ec 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -30,7 +30,7 @@ <rev></rev> </header> - <module>httpc</module> + <module since="OTP R13B04">httpc</module> <modulesummary>An HTTP/1.1 client</modulesummary> <description> @@ -151,8 +151,8 @@ <funcs> <func> - <name>cancel_request(RequestId) -></name> - <name>cancel_request(RequestId, Profile) -> ok</name> + <name since="OTP R13B04">cancel_request(RequestId) -></name> + <name since="OTP R13B04">cancel_request(RequestId, Profile) -> ok</name> <fsummary>Cancels an asynchronous HTTP request.</fsummary> <type> <v>RequestId = request_id() - A unique identifier as returned @@ -169,9 +169,9 @@ </func> <func> - <name>cookie_header(Url) -> </name> - <name>cookie_header(Url, Profile | Opts) -> header() | {error, Reason}</name> - <name>cookie_header(Url, Opts, Profile) -> header() | {error, Reason}</name> + <name since="OTP R13B04">cookie_header(Url) -> </name> + <name since="OTP R13B04">cookie_header(Url, Profile | Opts) -> header() | {error, Reason}</name> + <name since="OTP R15B">cookie_header(Url, Opts, Profile) -> header() | {error, Reason}</name> <fsummary>Returns the cookie header that would have been sent when making a request to URL using the profile <c>Profile</c>.</fsummary> <type> @@ -193,8 +193,8 @@ </func> <func> - <name>get_options(OptionItems) -> {ok, Values} | {error, Reason}</name> - <name>get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason}</name> + <name since="OTP R15B01">get_options(OptionItems) -> {ok, Values} | {error, Reason}</name> + <name since="OTP R15B01">get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason}</name> <fsummary>Gets the currently used options.</fsummary> <type> <v>OptionItems = all | [option_item()]</v> @@ -223,8 +223,8 @@ </func> <func> - <name>info() -> list()</name> - <name>info(Profile) -> list()</name> + <name since="OTP R15B02">info() -> list()</name> + <name since="OTP R15B02">info(Profile) -> list()</name> <fsummary>Produces a list of miscellaneous information.</fsummary> <type> <v>Profile = profile() | pid()</v> @@ -239,8 +239,8 @@ <func> - <name>reset_cookies() -> void()</name> - <name>reset_cookies(Profile) -> void()</name> + <name since="OTP R13B04">reset_cookies() -> void()</name> + <name since="OTP R13B04">reset_cookies(Profile) -> void()</name> <fsummary>Resets the cookie database.</fsummary> <type> <v>Profile = profile() | pid()</v> @@ -254,8 +254,8 @@ </func> <func> - <name>request(Url) -> </name> - <name>request(Url, Profile) -> {ok, Result} | {error, Reason}</name> + <name since="OTP R13B04">request(Url) -> </name> + <name since="OTP R13B04">request(Url, Profile) -> {ok, Result} | {error, Reason}</name> <fsummary>Sends a get HTTP request.</fsummary> <type> <v>Url = url()</v> @@ -272,8 +272,8 @@ </func> <func> - <name>request(Method, Request, HTTPOptions, Options) -></name> - <name>request(Method, Request, HTTPOptions, Options, Profile) -> {ok, Result} | {ok, saved_to_file} | {error, Reason}</name> + <name since="OTP R13B04">request(Method, Request, HTTPOptions, Options) -></name> + <name since="OTP R13B04">request(Method, Request, HTTPOptions, Options, Profile) -> {ok, Result} | {ok, saved_to_file} | {error, Reason}</name> <fsummary>Sends an HTTP request.</fsummary> <type> @@ -521,8 +521,8 @@ <func> - <name>set_options(Options) -> </name> - <name>set_options(Options, Profile) -> ok | {error, Reason}</name> + <name since="OTP R13B04">set_options(Options) -> </name> + <name since="OTP R13B04">set_options(Options, Profile) -> ok | {error, Reason}</name> <fsummary>Sets options to be used for subsequent requests.</fsummary> <type> <v>Options = [Option]</v> @@ -639,8 +639,8 @@ </func> <func> - <name>store_cookies(SetCookieHeaders, Url) -> </name> - <name>store_cookies(SetCookieHeaders, Url, Profile) -> ok | {error, Reason}</name> + <name since="OTP R14B02">store_cookies(SetCookieHeaders, Url) -> </name> + <name since="OTP R14B02">store_cookies(SetCookieHeaders, Url, Profile) -> ok | {error, Reason}</name> <fsummary>Saves the cookies defined in <c>SetCookieHeaders</c> in the client profile cookie database.</fsummary> <type> @@ -658,7 +658,7 @@ </func> <func> - <name>stream_next(Pid) -> ok</name> + <name since="OTP R13B04">stream_next(Pid) -> ok</name> <fsummary>Triggers the next message to be streamed, that is, the same behavior as active one for sockets. </fsummary> @@ -676,8 +676,8 @@ </func> <func> - <name>which_cookies() -> cookies()</name> - <name>which_cookies(Profile) -> cookies()</name> + <name since="OTP R13B04">which_cookies() -> cookies()</name> + <name since="OTP R13B04">which_cookies(Profile) -> cookies()</name> <fsummary>Dumps the entire cookie database.</fsummary> <type> <v>Profile = profile() | pid()</v> @@ -695,8 +695,8 @@ </func> <func> - <name>which_sessions() -> session_info()</name> - <name>which_sessions(Profile) -> session_info()</name> + <name since="OTP R15B02">which_sessions() -> session_info()</name> + <name since="OTP R15B02">which_sessions(Profile) -> session_info()</name> <fsummary>Produces a slightly processed dump of the sessions database.</fsummary> <type> <v>Profile = profile() | pid()</v> diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml index 2c70c2b050..66369e8df9 100644 --- a/lib/inets/doc/src/httpd.xml +++ b/lib/inets/doc/src/httpd.xml @@ -29,7 +29,7 @@ <rev>2.2</rev> <file>httpd.sgml</file> </header> - <module>httpd</module> + <module since="">httpd</module> <modulesummary> HTTP server API </modulesummary> @@ -874,8 +874,8 @@ text/plain asc txt</pre> <funcs> <func> - <name>info(Pid) -></name> - <name>info(Pid, Properties) -> [{Option, Value}]</name> + <name since="">info(Pid) -></name> + <name since="">info(Pid, Properties) -> [{Option, Value}]</name> <fsummary>Fetches information about the HTTP server.</fsummary> <type> <v>Properties = [property()]</v> @@ -899,10 +899,10 @@ text/plain asc txt</pre> </func> <func> - <name>info(Address, Port) -> </name> - <name>info(Address, Port, Profile) -> </name> - <name>info(Address, Port, Profile, Properties) -> [{Option, Value}] </name> - <name>info(Address, Port, Properties) -> [{Option, Value}] </name> + <name since="">info(Address, Port) -> </name> + <name since="">info(Address, Port, Profile) -> </name> + <name since="OTP 18.0">info(Address, Port, Profile, Properties) -> [{Option, Value}] </name> + <name since="">info(Address, Port, Properties) -> [{Option, Value}] </name> <fsummary>Fetches information about the HTTP server.</fsummary> <type> <v>Address = ip_address()</v> @@ -927,7 +927,7 @@ text/plain asc txt</pre> </func> <func> - <name>reload_config(Config, Mode) -> ok | {error, Reason}</name> + <name since="">reload_config(Config, Mode) -> ok | {error, Reason}</name> <fsummary>Reloads the HTTP server configuration without restarting the server.</fsummary> <type> @@ -1051,7 +1051,7 @@ text/plain asc txt</pre> </section> <funcs> <func> - <name>Module:do(ModData)-> {proceed, OldData} | {proceed, NewData} | {break, NewData} | done</name> + <name since="">Module:do(ModData)-> {proceed, OldData} | {proceed, NewData} | {break, NewData} | done</name> <fsummary>Called for each request to the web server.</fsummary> <type> <v>OldData = list()</v> @@ -1105,7 +1105,7 @@ text/plain asc txt</pre> </func> <func> - <name>Module:load(Line, AccIn)-> eof | ok | {ok, AccOut} | {ok, AccOut, {Option, Value}} | {ok, AccOut, [{Option, Value}]} | {error, Reason}</name> + <name since="">Module:load(Line, AccIn)-> eof | ok | {ok, AccOut} | {ok, AccOut, {Option, Value}} | {ok, AccOut, [{Option, Value}]} | {error, Reason}</name> <fsummary>Converts a line in an Apache-like config file to an <c>{Option, Value}</c> tuple.</fsummary> <type> @@ -1128,7 +1128,7 @@ text/plain asc txt</pre> </func> <func> - <name>Module:remove(ConfigDB) -> ok | {error, Reason} </name> + <name since="">Module:remove(ConfigDB) -> ok | {error, Reason} </name> <fsummary>Callback function that is called when the web server is closed.</fsummary> <type> <v>ConfigDB = ets_table()</v> @@ -1143,7 +1143,7 @@ text/plain asc txt</pre> </func> <func> - <name>Module:store({Option, Value}, Config)-> {ok, {Option, NewValue}} | {error, Reason}</name> + <name since="">Module:store({Option, Value}, Config)-> {ok, {Option, NewValue}} | {error, Reason}</name> <fsummary>Checks the validity of the configuration options.</fsummary> <type> <v>Line = string()</v> @@ -1171,7 +1171,7 @@ text/plain asc txt</pre> </section> <funcs> <func> - <name>parse_query(QueryString) -> [{Key,Value}]</name> + <name since="">parse_query(QueryString) -> [{Key,Value}]</name> <fsummary>Parses incoming data to <c>erl</c> and <c>eval</c> scripts.</fsummary> <type> <v>QueryString = string()</v> diff --git a/lib/inets/doc/src/httpd_custom_api.xml b/lib/inets/doc/src/httpd_custom_api.xml index d2e5441895..2c0f92ff83 100644 --- a/lib/inets/doc/src/httpd_custom_api.xml +++ b/lib/inets/doc/src/httpd_custom_api.xml @@ -25,7 +25,7 @@ <title>httpd_custom_api</title> <file>httpd_custom_api.xml</file> </header> - <module>httpd_custom_api</module> + <module since="OTP 17.5.6">httpd_custom_api</module> <modulesummary>Behaviour with optional callbacks to customize the inets HTTP server.</modulesummary> <description> <p> The module implementing this behaviour shall be supplied to to the servers @@ -34,7 +34,7 @@ </description> <funcs> <func> - <name>response_default_headers() -> [Header] </name> + <name since="OTP 18.1.1">response_default_headers() -> [Header] </name> <fsummary>Provide default headers for the HTTP servers responses.</fsummary> <type> <v>Header = {HeaderName :: string(), HeaderValue::string()}</v> @@ -48,7 +48,7 @@ </func> <func> - <name>response_header({HeaderName, HeaderValue}) -> {true, Header} | false </name> + <name since="OTP 17.5.6">response_header({HeaderName, HeaderValue}) -> {true, Header} | false </name> <fsummary>Filter and possible alter HTTP response headers.</fsummary> <type> <v>Header = {HeaderName :: string(), HeaderValue::string()}</v> @@ -61,7 +61,7 @@ </func> <func> - <name>request_header({HeaderName, HeaderValue}) -> {true, Header} | false </name> + <name since="OTP 17.5.6">request_header({HeaderName, HeaderValue}) -> {true, Header} | false </name> <fsummary>Filter and possible alter HTTP request headers.</fsummary> <type> <v>Header = {HeaderName :: string(), HeaderValue::string()}</v> diff --git a/lib/inets/doc/src/httpd_socket.xml b/lib/inets/doc/src/httpd_socket.xml index d3aa82a540..22ead06f38 100644 --- a/lib/inets/doc/src/httpd_socket.xml +++ b/lib/inets/doc/src/httpd_socket.xml @@ -29,7 +29,7 @@ <rev>2.2</rev> <file>httpd_socket.sgml</file> </header> - <module>httpd_socket</module> + <module since="">httpd_socket</module> <modulesummary>Communication utility functions to be used by the Erlang web server API programmer.</modulesummary> <description> @@ -43,7 +43,7 @@ <funcs> <func> - <name>deliver(SocketType, Socket, Data) -> Result</name> + <name since="">deliver(SocketType, Socket, Data) -> Result</name> <fsummary>Sends binary data over socket.</fsummary> <type> <v>SocketType = socket_type()</v> @@ -63,7 +63,7 @@ </func> <func> - <name>peername(SocketType,Socket) -> {Port,IPAddress}</name> + <name since="">peername(SocketType,Socket) -> {Port,IPAddress}</name> <fsummary>Returns the port and IP address of the remote socket.</fsummary> <type> <v>SocketType = socket_type()</v> @@ -81,7 +81,7 @@ </func> <func> - <name>resolve() -> HostName</name> + <name since="">resolve() -> HostName</name> <fsummary>Returns the official name of the current host.</fsummary> <type> <v>HostName = string()</v> diff --git a/lib/inets/doc/src/httpd_util.xml b/lib/inets/doc/src/httpd_util.xml index 220a2ede35..e0f947f860 100644 --- a/lib/inets/doc/src/httpd_util.xml +++ b/lib/inets/doc/src/httpd_util.xml @@ -29,7 +29,7 @@ <rev>2.2</rev> <file>httpd_util.sgml</file> </header> - <module>httpd_util</module> + <module since="">httpd_util</module> <modulesummary>Miscellaneous utility functions to be used when implementing Erlang web server API modules.</modulesummary> <description> @@ -41,12 +41,11 @@ <funcs> <func> - <name>convert_request_date(DateString) -> ErlDate|bad_date</name> + <name since="">convert_request_date(DateString) -> ErlDate|bad_date</name> <fsummary>Converts the date to the Erlang date format.</fsummary> <type> <v>DateString = string()</v> - <v>ErlDate = {{Year,Month,Date},{Hour,Min,Sec}}</v> - <v>Year = Month = Date = Hour = Min = Sec = integer()</v> + <v>ErlDate = calendar:datetime() </v> </type> <desc> <p><c>convert_request_date/1</c> converts <c>DateString</c> to @@ -57,7 +56,7 @@ </func> <func> - <name>create_etag(FileInfo) -> Etag</name> + <name since="">create_etag(FileInfo) -> Etag</name> <fsummary>Calculates the Etag for a file.</fsummary> <type> <v>FileInfo = file_info()</v> @@ -71,7 +70,7 @@ </func> <func> - <name>day(NthDayOfWeek) -> DayOfWeek</name> + <name since="">day(NthDayOfWeek) -> DayOfWeek</name> <fsummary>Converts the day of the week (integer [1-7]) to an abbreviated string.</fsummary> <type> @@ -87,7 +86,7 @@ </func> <func> - <name>decode_hex(HexValue) -> DecValue</name> + <name since="">decode_hex(HexValue) -> DecValue</name> <fsummary>Converts a hexadecimal value into its decimal equivalent.</fsummary> <type> <v>HexValue = DecValue = string()</v> @@ -99,7 +98,7 @@ </func> <func> - <name>flatlength(NestedList) -> Size</name> + <name since="">flatlength(NestedList) -> Size</name> <fsummary>Computes the size of a possibly nested list.</fsummary> <type> <v>NestedList = list()</v> @@ -112,7 +111,7 @@ </func> <func> - <name>hexlist_to_integer(HexString) -> Number</name> + <name since="">hexlist_to_integer(HexString) -> Number</name> <fsummary>Converts a hexadecimal string to an integer.</fsummary> <type> <v>Number = integer()</v> @@ -125,7 +124,7 @@ </func> <func> - <name>integer_to_hexlist(Number) -> HexString</name> + <name since="">integer_to_hexlist(Number) -> HexString</name> <fsummary>Converts an integer to a hexadecimal string.</fsummary> <type> <v>Number = integer()</v> @@ -138,8 +137,8 @@ </func> <func> - <name>lookup(ETSTable,Key) -> Result</name> - <name>lookup(ETSTable,Key,Undefined) -> Result</name> + <name since="">lookup(ETSTable,Key) -> Result</name> + <name since="">lookup(ETSTable,Key,Undefined) -> Result</name> <fsummary>Extracts the first value associated with a <c>Key</c> in an ETS table.</fsummary> <type> @@ -160,8 +159,8 @@ </func> <func> - <name>lookup_mime(ConfigDB,Suffix)</name> - <name>lookup_mime(ConfigDB,Suffix,Undefined) -> MimeType</name> + <name since="">lookup_mime(ConfigDB,Suffix)</name> + <name since="">lookup_mime(ConfigDB,Suffix,Undefined) -> MimeType</name> <fsummary>Returns the MIME type associated with a specific file suffix.</fsummary> <type> <v>ConfigDB = ets_table()</v> @@ -179,8 +178,8 @@ </func> <func> - <name>lookup_mime_default(ConfigDB,Suffix)</name> - <name>lookup_mime_default(ConfigDB,Suffix,Undefined) -> MimeType</name> + <name since="">lookup_mime_default(ConfigDB,Suffix)</name> + <name since="">lookup_mime_default(ConfigDB,Suffix,Undefined) -> MimeType</name> <fsummary>Returns the MIME type associated with a specific file suffix or the value of the DefaultType.</fsummary> <type> @@ -201,7 +200,7 @@ </func> <func> - <name>message(StatusCode,PhraseArgs,ConfigDB) -> Message</name> + <name since="">message(StatusCode,PhraseArgs,ConfigDB) -> Message</name> <fsummary>Returns an informative HTTP 1.1 status string in HTML.</fsummary> <type> <v>StatusCode = 301 | 400 | 403 | 404 | 500 | 501 | 504</v> @@ -236,7 +235,7 @@ </func> <func> - <name>month(NthMonth) -> Month</name> + <name since="">month(NthMonth) -> Month</name> <fsummary>Converts the month as an integer (1-12) to an abbreviated string.</fsummary> <type> <v>NthMonth = 1-12</v> @@ -250,7 +249,7 @@ </func> <func> - <name>multi_lookup(ETSTable,Key) -> Result</name> + <name since="">multi_lookup(ETSTable,Key) -> Result</name> <fsummary>Extracts the values associated with a key in an ETS table.</fsummary> <type> <v>ETSTable = ets_table()</v> @@ -265,7 +264,7 @@ </func> <func> - <name>reason_phrase(StatusCode) -> Description</name> + <name since="">reason_phrase(StatusCode) -> Description</name> <fsummary>Returns the description of an HTTP 1.1 status code.</fsummary> <type> <v>StatusCode = 100| 200 | 201 | 202 | 204 | 205 | 206 | 300 | 301 | 302 | 303 | 304 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 410 411 | 412 | 413 | 414 415 | 416 | 417 | 500 | 501 | 502 | 503 | 504 | 505</v> @@ -280,11 +279,11 @@ </func> <func> - <name>rfc1123_date() -> RFC1123Date</name> - <name>rfc1123_date({{YYYY,MM,DD},{Hour,Min,Sec}}) -> RFC1123Date</name> + <name since="">rfc1123_date() -> RFC1123Date</name> + <name since="">rfc1123_date(Date) -> RFC1123Date</name> <fsummary>Returns the current date in RFC 1123 format.</fsummary> <type> - <v>YYYY = MM = DD = Hour = Min = Sec = integer()</v> + <v> Date = calendar:datetime()</v> <v>RFC1123Date = string()</v> </type> <desc> @@ -295,7 +294,7 @@ </func> <func> - <name>split(String,RegExp,N) -> SplitRes</name> + <name since="">split(String,RegExp,N) -> SplitRes</name> <fsummary>Splits a string in N chunks using a regular expression.</fsummary> <type> <v>String = RegExp = string()</v> @@ -313,7 +312,7 @@ </func> <func> - <name>split_script_path(RequestLine) -> Splitted</name> + <name since="">split_script_path(RequestLine) -> Splitted</name> <fsummary>Splits a <c>RequestLine</c> in a file reference to an executable, and a <c>QueryString</c> or a <c>PathInfo</c>string.</fsummary> <type> @@ -330,7 +329,7 @@ </func> <func> - <name>split_path(RequestLine) -> {Path,QueryStringOrPathInfo}</name> + <name since="">split_path(RequestLine) -> {Path,QueryStringOrPathInfo}</name> <fsummary>Splits a <c>RequestLine</c> in a file reference, and a <c>QueryString</c> or a <c>PathInfo</c> string.</fsummary> <type> @@ -356,7 +355,7 @@ </func> <func> - <name>strip(String) -> Stripped</name> + <name since="">strip(String) -> Stripped</name> <fsummary>Returns <c>String</c> where the leading and trailing space tabs are removed.</fsummary> <type> @@ -370,7 +369,7 @@ </func> <func> - <name>suffix(FileName) -> Suffix</name> + <name since="">suffix(FileName) -> Suffix</name> <fsummary>Extracts the file suffix from a given filename.</fsummary> <type> <v>FileName = Suffix = string()</v> diff --git a/lib/inets/doc/src/inets.xml b/lib/inets/doc/src/inets.xml index 9b0ffaad5e..176af3137a 100644 --- a/lib/inets/doc/src/inets.xml +++ b/lib/inets/doc/src/inets.xml @@ -29,7 +29,7 @@ <date></date> <rev></rev> </header> - <module>inets</module> + <module since="">inets</module> <modulesummary>The Inets services API.</modulesummary> <description> <p>This module provides the most basic API to the @@ -51,7 +51,7 @@ <funcs> <func> - <name>services() -> [{Service, Pid}]</name> + <name since="">services() -> [{Service, Pid}]</name> <fsummary>Returns a list of currently running services.</fsummary> <type> <v>Service = service()</v> @@ -68,7 +68,7 @@ </func> <func> - <name>services_info() -> [{Service, Pid, Info}]</name> + <name since="">services_info() -> [{Service, Pid, Info}]</name> <fsummary>Returns a list of currently running services where each service is described by an <c>[{Option, Value}]</c> list.</fsummary> @@ -91,7 +91,7 @@ </func> <func> - <name>service_names() -> [Service] </name> + <name since="">service_names() -> [Service] </name> <fsummary>Returns a list of available service names.</fsummary> <type> <v>Service = service()</v> @@ -104,8 +104,8 @@ </func> <func> - <name>start() -> </name> - <name>start(Type) -> ok | {error, Reason}</name> + <name since="">start() -> </name> + <name since="">start(Type) -> ok | {error, Reason}</name> <fsummary>Starts the <c>Inets</c> application.</fsummary> <type> <v>Type = permanent | transient | temporary</v> @@ -120,8 +120,8 @@ </func> <func> - <name>start(Service, ServiceConfig) -> {ok, Pid} | {error, Reason}</name> - <name>start(Service, ServiceConfig, How) -> {ok, Pid} | {error, Reason}</name> + <name since="">start(Service, ServiceConfig) -> {ok, Pid} | {error, Reason}</name> + <name since="">start(Service, ServiceConfig, How) -> {ok, Pid} | {error, Reason}</name> <fsummary>Dynamically starts an <c>Inets</c> service after the <c>Inets</c> application has been started.</fsummary> <type> @@ -156,7 +156,7 @@ </func> <func> - <name>stop() -> ok </name> + <name since="">stop() -> ok </name> <fsummary>Stops the <c>Inets</c> application.</fsummary> <desc> <p>Stops the <c>Inets</c> application. See also @@ -167,7 +167,7 @@ </func> <func> - <name>stop(Service, Reference) -> ok | {error, Reason} </name> + <name since="">stop(Service, Reference) -> ok | {error, Reason} </name> <fsummary>Stops a started service of the <c>Inets</c> application or takes down a <c>stand_alone </c>service gracefully.</fsummary> <type> diff --git a/lib/inets/doc/src/mod_alias.xml b/lib/inets/doc/src/mod_alias.xml index 6ae19700a5..ff57d49d08 100644 --- a/lib/inets/doc/src/mod_alias.xml +++ b/lib/inets/doc/src/mod_alias.xml @@ -29,7 +29,7 @@ <rev>2.2</rev> <file>mod_alias.sgml</file> </header> - <module>mod_alias</module> + <module since="">mod_alias</module> <modulesummary>URL aliasing.</modulesummary> <description> <p>Erlang web server internal API for handling of, for example, @@ -40,7 +40,7 @@ <funcs> <func> - <name>default_index(ConfigDB, Path) -> NewPath</name> + <name since="">default_index(ConfigDB, Path) -> NewPath</name> <fsummary>Returns a new path with the default resource or file appended.</fsummary> <type> <v>ConfigDB = config_db()</v> @@ -64,7 +64,7 @@ </func> <func> - <name>path(PathData, ConfigDB, RequestURI) -> Path</name> + <name since="">path(PathData, ConfigDB, RequestURI) -> Path</name> <fsummary>Returns the file path to a URL.</fsummary> <type> <v>PathData = interaction_data()</v> @@ -89,7 +89,7 @@ </func> <func> - <name>real_name(ConfigDB, RequestURI, Aliases) -> Ret</name> + <name since="">real_name(ConfigDB, RequestURI, Aliases) -> Ret</name> <fsummary>Expands a request URI using <c>Aliases</c> config directives.</fsummary> <type> <v>ConfigDB = config_db()</v> @@ -120,7 +120,7 @@ </func> <func> - <name>real_script_name(ConfigDB, RequestURI, ScriptAliases) -> Ret</name> + <name since="">real_script_name(ConfigDB, RequestURI, ScriptAliases) -> Ret</name> <fsummary>Expands a request URI using <c>ScriptAliases</c> config directives.</fsummary> <type> diff --git a/lib/inets/doc/src/mod_auth.xml b/lib/inets/doc/src/mod_auth.xml index c4f844622b..ad864ca4d1 100644 --- a/lib/inets/doc/src/mod_auth.xml +++ b/lib/inets/doc/src/mod_auth.xml @@ -29,7 +29,7 @@ <rev>2.3</rev> <file>mod_auth.sgml</file> </header> - <module>mod_auth</module> + <module since="">mod_auth</module> <modulesummary>User authentication using text files, Dets, or Mnesia database.</modulesummary> <description> <p>This module provides for basic user authentication using @@ -38,9 +38,9 @@ <funcs> <func> - <name>add_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> - <name>add_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> - <name>add_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name> + <name since="">add_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> + <name since="">add_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> + <name since="">add_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name> <fsummary>Adds a user to a group.</fsummary> <type> <v>GroupName = string()</v> @@ -65,9 +65,9 @@ </func> <func> - <name>add_user(UserName, Options) -> true| {error, Reason}</name> - <name>add_user(UserName, Password, UserData, Port, Dir) -> true | {error, Reason}</name> - <name>add_user(UserName, Password, UserData, Address, Port, Dir) -> true | {error, Reason}</name> + <name since="">add_user(UserName, Options) -> true| {error, Reason}</name> + <name since="">add_user(UserName, Password, UserData, Port, Dir) -> true | {error, Reason}</name> + <name since="">add_user(UserName, Password, UserData, Address, Port, Dir) -> true | {error, Reason}</name> <fsummary>Adds a user to the user database.</fsummary> <type> <v>UserName = string()</v> @@ -92,8 +92,8 @@ </func> <func> - <name>delete_group(GroupName, Options) -> true | {error,Reason} <name>delete_group(GroupName, Port, Dir) -> true | {error, Reason}</name> - <name>delete_group(GroupName, Address, Port, Dir) -> true | {error, Reason}</name> + <name since="">delete_group(GroupName, Options) -> true | {error,Reason} <name>delete_group(GroupName, Port, Dir) -> true | {error, Reason}</name> + <name since="">delete_group(GroupName, Address, Port, Dir) -> true | {error, Reason}</name> <fsummary>Deletes a group.</fsummary> <type> <v>Options = [Option]</v> @@ -115,9 +115,9 @@ </func> <func> - <name>delete_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> - <name>delete_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> - <name>delete_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name> + <name since="">delete_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> + <name since="">delete_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> + <name since="">delete_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name> <fsummary>Removes a user from a group.</fsummary> <type> <v>GroupName = string()</v> @@ -141,9 +141,9 @@ </func> <func> - <name>delete_user(UserName,Options) -> true | {error, Reason}</name> - <name>delete_user(UserName, Port, Dir) -> true | {error, Reason}</name> - <name>delete_user(UserName, Address, Port, Dir) -> true | {error, Reason}</name> + <name since="">delete_user(UserName,Options) -> true | {error, Reason}</name> + <name since="">delete_user(UserName, Port, Dir) -> true | {error, Reason}</name> + <name since="">delete_user(UserName, Address, Port, Dir) -> true | {error, Reason}</name> <fsummary>Deletes a user from the user database.</fsummary> <type> <v>UserName = string()</v> @@ -166,9 +166,9 @@ </func> <func> - <name>get_user(UserName,Options) -> {ok, #httpd_user} |{error, Reason}</name> - <name>get_user(UserName, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name> - <name>get_user(UserName, Address, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name> + <name since="">get_user(UserName,Options) -> {ok, #httpd_user} |{error, Reason}</name> + <name since="">get_user(UserName, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name> + <name since="">get_user(UserName, Address, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name> <fsummary>Returns a user from the user database.</fsummary> <type> <v>UserName = string()</v> @@ -190,9 +190,9 @@ </func> <func> - <name>list_groups(Options) -> {ok, Groups} | {error, Reason}</name> - <name>list_groups(Port, Dir) -> {ok, Groups} | {error, Reason}</name> - <name>list_groups(Address, Port, Dir) -> {ok, Groups} | {error, Reason}</name> + <name since="">list_groups(Options) -> {ok, Groups} | {error, Reason}</name> + <name since="">list_groups(Port, Dir) -> {ok, Groups} | {error, Reason}</name> + <name since="">list_groups(Address, Port, Dir) -> {ok, Groups} | {error, Reason}</name> <fsummary>Lists all the groups.</fsummary> <type> <v>Options = [Option]</v> @@ -214,9 +214,9 @@ </func> <func> - <name>list_group_members(GroupName, Options) -> {ok, Users} | {error, Reason}</name> - <name>list_group_members(GroupName, Port, Dir) -> {ok, Users} | {error, Reason}</name> - <name>list_group_members(GroupName, Address, Port, Dir) -> {ok, Users} | {error, Reason}</name> + <name since="">list_group_members(GroupName, Options) -> {ok, Users} | {error, Reason}</name> + <name since="">list_group_members(GroupName, Port, Dir) -> {ok, Users} | {error, Reason}</name> + <name since="">list_group_members(GroupName, Address, Port, Dir) -> {ok, Users} | {error, Reason}</name> <fsummary>Lists the members of a group.</fsummary> <type> <v>GroupName = string()</v> @@ -240,9 +240,9 @@ </func> <func> - <name>list_users(Options) -> {ok, Users} | {error, Reason}</name> - <name>list_users(Port, Dir) -> {ok, Users} | {error, Reason}</name> - <name>list_users(Address, Port, Dir) -> {ok, Users} | {error, Reason}</name> + <name since="">list_users(Options) -> {ok, Users} | {error, Reason}</name> + <name since="OTP R14B01">list_users(Port, Dir) -> {ok, Users} | {error, Reason}</name> + <name since="">list_users(Address, Port, Dir) -> {ok, Users} | {error, Reason}</name> <fsummary>Lists users in the user database.</fsummary> <type> <v>Options = [Option]</v> @@ -264,8 +264,8 @@ </func> <func> - <name>update_password(Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name> - <name>update_password(Address,Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name> + <name since="">update_password(Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name> + <name since="">update_password(Address,Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name> <fsummary>Changes <c>AuthAcessPassword</c>.</fsummary> <type> <v>Port = integer()</v> diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml index ede7dc8f7d..bc5f98068f 100644 --- a/lib/inets/doc/src/mod_esi.xml +++ b/lib/inets/doc/src/mod_esi.xml @@ -25,7 +25,7 @@ <title>mod_esi</title> <file>mod_esi.sgml</file> </header> - <module>mod_esi</module> + <module since="">mod_esi</module> <modulesummary>Erlang Server Interface</modulesummary> <description> <p>This module defines the Erlang Server Interface (ESI) API. @@ -88,7 +88,7 @@ <funcs> <func> - <name>deliver(SessionID, Data) -> ok | {error, Reason}</name> + <name since="">deliver(SessionID, Data) -> ok | {error, Reason}</name> <fsummary>Sends <c>Data</c> back to client.</fsummary> <type> <v>SessionID = term()</v> @@ -121,7 +121,7 @@ <funcs> <func> - <name>Module:Function(SessionID, Env, Input)-> {continue, State} | _ </name> + <name since="">Module:Function(SessionID, Env, Input)-> {continue, State} | _ </name> <fsummary>Creates a dynamic web page and returns it chunk by chunk to the server process by calling <c>mod_esi:deliver/2</c>.</fsummary> <type> @@ -179,7 +179,7 @@ </func> <func> - <name>Module:Function(Env, Input)-> Response </name> + <name since="">Module:Function(Env, Input)-> Response </name> <fsummary>Creates a dynamic web page and returns it as a list. This function is deprecated and is only kept for backwards compatibility.</fsummary> <type> diff --git a/lib/inets/doc/src/mod_security.xml b/lib/inets/doc/src/mod_security.xml index 6f3f3c048a..c26d7468c2 100644 --- a/lib/inets/doc/src/mod_security.xml +++ b/lib/inets/doc/src/mod_security.xml @@ -29,7 +29,7 @@ <rev>1.0</rev> <file>mod_security.sgml</file> </header> - <module>mod_security</module> + <module since="">mod_security</module> <modulesummary>Security Audit and Trailing Functionality</modulesummary> <description> <p>Security Audit and Trailing Functionality</p> @@ -37,8 +37,8 @@ <funcs> <func> - <name>block_user(User, Port, Dir, Seconds) -> true | {error, Reason}</name> - <name>block_user(User, Address, Port, Dir, Seconds) -> true | {error, Reason}</name> + <name since="">block_user(User, Port, Dir, Seconds) -> true | {error, Reason}</name> + <name since="">block_user(User, Address, Port, Dir, Seconds) -> true | {error, Reason}</name> <fsummary>Blocks a user from access to a directory for a certain amount of time.</fsummary> <type> <v>User = string()</v> @@ -56,10 +56,10 @@ </func> <func> - <name>list_auth_users(Port) -> Users | []</name> - <name>list_auth_users(Address, Port) -> Users | []</name> - <name>list_auth_users(Port, Dir) -> Users | []</name> - <name>list_auth_users(Address, Port, Dir) -> Users | []</name> + <name since="">list_auth_users(Port) -> Users | []</name> + <name since="">list_auth_users(Address, Port) -> Users | []</name> + <name since="">list_auth_users(Port, Dir) -> Users | []</name> + <name since="">list_auth_users(Address, Port, Dir) -> Users | []</name> <fsummary>Lists users that have authenticated within the <c>SecurityAuthTimeout</c> time for a given address (if specified), port number, and directory (if specified).</fsummary> @@ -77,10 +77,10 @@ </desc> </func> <func> - <name>list_blocked_users(Port) -> Users | []</name> - <name>list_blocked_users(Address, Port) -> Users | []</name> - <name>list_blocked_users(Port, Dir) -> Users | []</name> - <name>list_blocked_users(Address, Port, Dir) -> Users | []</name> + <name since="">list_blocked_users(Port) -> Users | []</name> + <name since="">list_blocked_users(Address, Port) -> Users | []</name> + <name since="">list_blocked_users(Port, Dir) -> Users | []</name> + <name since="">list_blocked_users(Address, Port, Dir) -> Users | []</name> <fsummary>Lists users that are currently blocked from access to a specified port number, for a given address (if specified).</fsummary> <type> @@ -97,10 +97,10 @@ </func> <func> - <name>unblock_user(User, Port) -> true | {error, Reason}</name> - <name>unblock_user(User, Address, Port) -> true | {error, Reason}</name> - <name>unblock_user(User, Port, Dir) -> true | {error, Reason}</name> - <name>unblock_user(User, Address, Port, Dir) -> true | {error, Reason}</name> + <name since="">unblock_user(User, Port) -> true | {error, Reason}</name> + <name since="">unblock_user(User, Address, Port) -> true | {error, Reason}</name> + <name since="">unblock_user(User, Port, Dir) -> true | {error, Reason}</name> + <name since="">unblock_user(User, Address, Port, Dir) -> true | {error, Reason}</name> <fsummary>Removes a blocked user from the block list.</fsummary> <type> <v>User = string()</v> @@ -129,8 +129,8 @@ <funcs> <func> - <name>Module:event(What, Port, Dir, Data) -> ignored</name> - <name>Module:event(What, Address, Port, Dir, Data) -> ignored</name> + <name since="OTP 18.1">Module:event(What, Port, Dir, Data) -> ignored</name> + <name since="OTP 18.1">Module:event(What, Address, Port, Dir, Data) -> ignored</name> <fsummary>Called whenever an event occurs in <c>mod_security</c>.</fsummary> <type> <v>What = atom()</v> diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 12f5acb2e9..3624c6e3d7 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -33,7 +33,47 @@ <file>notes.xml</file> </header> - <section><title>Inets 7.0.3</title> + <section><title>Inets 7.0.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed bug that causes a crash in http client when using + hostnames (e.g. localhost) with the the option + ipv6_host_with_brackets set to true.</p> + <p> + This change also fixes a regression: httpc:request fails + with connection error (nxdomain) if option + ipv6_host_with_brackets set to true and host component of + the URI is an IPv6 address.</p> + <p> + Own Id: OTP-15554 Aux Id: ERIERL-289 </p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 7.0.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Make sure ipv6 addresses with brackets in URIs are + converted correctly before passing to lower level + functions like gen_tcp and ssl functions. Could cause + connection to fail.</p> + <p> + Own Id: OTP-15544 Aux Id: ERIERL-289 </p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 7.0.3</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 1bf5d25c98..8d443a1477 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -809,7 +809,7 @@ connect_and_send_first_request(Address, Request, #state{options = Options0} = St SocketType = socket_type(Request), ConnTimeout = (Request#request.settings)#http_options.connect_timeout, Options = handle_unix_socket_options(Request, Options0), - case connect(SocketType, Address, Options, ConnTimeout) of + case connect(SocketType, format_address(Address), Options, ConnTimeout) of {ok, Socket} -> ClientClose = httpc_request:is_client_closing( @@ -1738,4 +1738,8 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) -> {stacktrace, Stacktrace}]}} end. - +format_address({[$[|T], Port}) -> + {ok, Address} = inet:parse_address(string:strip(T, right, $])), + {Address, Port}; +format_address(HostPort) -> + HostPort. diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 52c05a7974..921161dce1 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -19,6 +19,6 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 7.0.3 +INETS_VSN = 7.0.5 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml index 38c7b5acf1..4e32c1a3a5 100644 --- a/lib/kernel/doc/src/application.xml +++ b/lib/kernel/doc/src/application.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>application</module> + <module since="">application</module> <modulesummary>Generic OTP application functions</modulesummary> <description> <p>In OTP, <em>application</em> denotes a component implementing @@ -67,8 +67,8 @@ </datatypes> <funcs> <func> - <name name="ensure_all_started" arity="1"/> - <name name="ensure_all_started" arity="2"/> + <name name="ensure_all_started" arity="1" since="OTP R16B02"/> + <name name="ensure_all_started" arity="2" since="OTP R16B02"/> <fsummary>Load and start an application and its dependencies, recursively.</fsummary> <desc> <p>Equivalent to calling @@ -85,8 +85,8 @@ </desc> </func> <func> - <name name="ensure_started" arity="1"/> - <name name="ensure_started" arity="2"/> + <name name="ensure_started" arity="1" since="OTP R16B01"/> + <name name="ensure_started" arity="2" since="OTP R16B01"/> <fsummary>Load and start an application.</fsummary> <desc> <p>Equivalent to @@ -95,8 +95,8 @@ </desc> </func> <func> - <name name="get_all_env" arity="0"/> - <name name="get_all_env" arity="1"/> + <name name="get_all_env" arity="0" since=""/> + <name name="get_all_env" arity="1" since=""/> <fsummary>Get the configuration parameters for an application.</fsummary> <desc> <p>Returns the configuration parameters and their values for @@ -108,8 +108,8 @@ </desc> </func> <func> - <name name="get_all_key" arity="0"/> - <name name="get_all_key" arity="1"/> + <name name="get_all_key" arity="0" since=""/> + <name name="get_all_key" arity="1" since=""/> <fsummary>Get the application specification keys.</fsummary> <desc> <p>Returns the application specification keys and their values @@ -122,8 +122,8 @@ </desc> </func> <func> - <name name="get_application" arity="0"/> - <name name="get_application" arity="1"/> + <name name="get_application" arity="0" since=""/> + <name name="get_application" arity="1" since=""/> <fsummary>Get the name of an application containing a certain process or module.</fsummary> <desc> <p>Returns the name of the application to which the process @@ -136,8 +136,8 @@ </desc> </func> <func> - <name name="get_env" arity="1"/> - <name name="get_env" arity="2"/> + <name name="get_env" arity="1" since=""/> + <name name="get_env" arity="2" since=""/> <fsummary>Get the value of a configuration parameter.</fsummary> <desc> <p>Returns the value of configuration parameter <c><anno>Par</anno></c> @@ -153,7 +153,7 @@ </desc> </func> <func> - <name name="get_env" arity="3"/> + <name name="get_env" arity="3" since="OTP R16B"/> <fsummary>Get the value of a configuration parameter using a default.</fsummary> <desc> <p>Works like <seealso marker="#get_env/2"><c>get_env/2</c></seealso> but returns @@ -162,8 +162,8 @@ </desc> </func> <func> - <name name="get_key" arity="1"/> - <name name="get_key" arity="2"/> + <name name="get_key" arity="1" since=""/> + <name name="get_key" arity="2" since=""/> <fsummary>Get the value of an application specification key.</fsummary> <desc> <p>Returns the value of the application specification key @@ -180,8 +180,8 @@ </desc> </func> <func> - <name name="load" arity="1"/> - <name name="load" arity="2"/> + <name name="load" arity="1" since=""/> + <name name="load" arity="2" since=""/> <fsummary>Load an application.</fsummary> <type name="application_spec"/> <type name="application_opt"/> @@ -226,7 +226,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="loaded_applications" arity="0"/> + <name name="loaded_applications" arity="0" since=""/> <fsummary>Get the currently loaded applications.</fsummary> <desc> <p>Returns a list with information about the applications, and included @@ -238,7 +238,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="permit" arity="2"/> + <name name="permit" arity="2" since=""/> <fsummary>Change the permission for an application to run at a node.</fsummary> <desc> <p>Changes the permission for <c><anno>Application</anno></c> to run at @@ -271,8 +271,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="set_env" arity="3"/> - <name name="set_env" arity="4"/> + <name name="set_env" arity="3" since=""/> + <name name="set_env" arity="4" since=""/> <fsummary>Set the value of a configuration parameter.</fsummary> <desc> <p>Sets the value of configuration parameter <c><anno>Par</anno></c> for @@ -302,8 +302,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="start" arity="1"/> - <name name="start" arity="2"/> + <name name="start" arity="1" since=""/> + <name name="start" arity="2" since=""/> <fsummary>Load and start an application.</fsummary> <desc> <p>Starts <c><anno>Application</anno></c>. If it is not loaded, @@ -353,7 +353,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="start_type" arity="0"/> + <name name="start_type" arity="0" since=""/> <fsummary>Get the start type of an ongoing application startup.</fsummary> <desc> <p>This function is intended to be called by a process belonging @@ -370,7 +370,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="stop" arity="1"/> + <name name="stop" arity="1" since=""/> <fsummary>Stop an application.</fsummary> <desc> <p>Stops <c><anno>Application</anno></c>. The application master calls @@ -399,7 +399,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="takeover" arity="2"/> + <name name="takeover" arity="2" since=""/> <fsummary>Take over a distributed application.</fsummary> <desc> <p>Takes over the distributed application @@ -424,7 +424,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="unload" arity="1"/> + <name name="unload" arity="1" since=""/> <fsummary>Unload an application.</fsummary> <desc> <p>Unloads the application specification for <c><anno>Application</anno></c> @@ -435,8 +435,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="unset_env" arity="2"/> - <name name="unset_env" arity="3"/> + <name name="unset_env" arity="2" since=""/> + <name name="unset_env" arity="3" since=""/> <fsummary>Unset the value of a configuration parameter.</fsummary> <desc> <p>Removes the configuration parameter <c><anno>Par</anno></c> and its value @@ -459,8 +459,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="which_applications" arity="0"/> - <name name="which_applications" arity="1"/> + <name name="which_applications" arity="0" since=""/> + <name name="which_applications" arity="1" since=""/> <fsummary>Get the currently running applications.</fsummary> <desc> <p>Returns a list with information about the applications that @@ -484,7 +484,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </section> <funcs> <func> - <name>Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name> + <name since="">Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name> <fsummary>Start an application.</fsummary> <type> <v>StartType = <seealso marker="#type-start_type"><c>start_type()</c></seealso></v> @@ -526,7 +526,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>Module:start_phase(Phase, StartType, PhaseArgs) -> ok | {error, Reason}</name> + <name since="">Module:start_phase(Phase, StartType, PhaseArgs) -> ok | {error, Reason}</name> <fsummary>Extended start of an application.</fsummary> <type> <v>Phase = atom()</v> @@ -551,7 +551,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>Module:prep_stop(State) -> NewState</name> + <name since="">Module:prep_stop(State) -> NewState</name> <fsummary>Prepare an application for termination.</fsummary> <type> <v>State = NewState = term()</v> @@ -569,7 +569,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>Module:stop(State)</name> + <name since="">Module:stop(State)</name> <fsummary>Clean up after termination of an application.</fsummary> <type> <v>State = term()</v> @@ -585,7 +585,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>Module:config_change(Changed, New, Removed) -> ok</name> + <name since="">Module:config_change(Changed, New, Removed) -> ok</name> <fsummary>Update the configuration parameters for an application.</fsummary> <type> <v>Changed = [{Par,Val}]</v> diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml index 5901446960..a57da18de9 100644 --- a/lib/kernel/doc/src/auth.xml +++ b/lib/kernel/doc/src/auth.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>auth</module> + <module since="">auth</module> <modulesummary>Erlang network authentication server.</modulesummary> <description> <p>This module is deprecated. For a description of the Magic @@ -42,7 +42,7 @@ </datatypes> <funcs> <func> - <name name="cookie" arity="0"/> + <name name="cookie" arity="0" since=""/> <fsummary>Magic cookie for local node (deprecated).</fsummary> <desc> <p>Use @@ -51,7 +51,7 @@ </desc> </func> <func> - <name name="cookie" arity="1"/> + <name name="cookie" arity="1" since=""/> <fsummary>Set the magic for the local node (deprecated).</fsummary> <type_desc variable="TheCookie"> The cookie can also be specified as a list with a single atom element. @@ -63,7 +63,7 @@ </desc> </func> <func> - <name name="is_auth" arity="1"/> + <name name="is_auth" arity="1" since=""/> <fsummary>Status of communication authorization (deprecated).</fsummary> <desc> <p>Returns <c>yes</c> if communication with <c><anno>Node</anno></c> is @@ -76,7 +76,7 @@ </desc> </func> <func> - <name>node_cookie([Node, Cookie]) -> yes | no</name> + <name since="">node_cookie([Node, Cookie]) -> yes | no</name> <fsummary>Set the magic cookie for a node and verify authorization (deprecated).</fsummary> <type> <v>Node = node()</v> @@ -88,7 +88,7 @@ </desc> </func> <func> - <name name="node_cookie" arity="2"/> + <name name="node_cookie" arity="2" since=""/> <fsummary>Set the magic cookie for a node and verify authorization (deprecated).</fsummary> <desc> <p>Sets the magic cookie of <c><anno>Node</anno></c> to diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index aff3e8133c..85178da930 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>code</module> + <module since="">code</module> <modulesummary>Erlang code server.</modulesummary> <description> <p>This module contains the interface to the Erlang @@ -322,7 +322,7 @@ zip:create("mnesia-4.4.7.ez", <funcs> <func> - <name name="set_path" arity="1"/> + <name name="set_path" arity="1" since=""/> <fsummary>Set the code server search path.</fsummary> <desc> <p>Sets the code path to the list of directories <c><anno>Path</anno></c>.</p> @@ -336,15 +336,15 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="get_path" arity="0"/> + <name name="get_path" arity="0" since=""/> <fsummary>Return the code server search path.</fsummary> <desc> <p>Returns the code path.</p> </desc> </func> <func> - <name name="add_path" arity="1"/> - <name name="add_pathz" arity="1"/> + <name name="add_path" arity="1" since=""/> + <name name="add_pathz" arity="1" since=""/> <fsummary>Add a directory to the end of the code path.</fsummary> <type name="add_path_ret"/> <desc> @@ -357,7 +357,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="add_patha" arity="1"/> + <name name="add_patha" arity="1" since=""/> <fsummary>Add a directory to the beginning of the code path.</fsummary> <type name="add_path_ret"/> <desc> @@ -370,8 +370,8 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="add_paths" arity="1"/> - <name name="add_pathsz" arity="1"/> + <name name="add_paths" arity="1" since=""/> + <name name="add_pathsz" arity="1" since=""/> <fsummary>Add directories to the end of the code path.</fsummary> <desc> <p>Adds the directories in <c><anno>Dirs</anno></c> to the end of the code @@ -381,7 +381,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="add_pathsa" arity="1"/> + <name name="add_pathsa" arity="1" since=""/> <fsummary>Add directories to the beginning of the code path.</fsummary> <desc> <p>Traverses <c><anno>Dirs</anno></c> and adds @@ -397,7 +397,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="del_path" arity="1"/> + <name name="del_path" arity="1" since=""/> <fsummary>Delete a directory from the code path.</fsummary> <desc> <p>Deletes a directory from the code path. The argument can be @@ -417,7 +417,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="replace_path" arity="2"/> + <name name="replace_path" arity="2" since=""/> <fsummary>Replace a directory with another in the code path.</fsummary> <desc> <p>Replaces an old occurrence of a directory @@ -441,7 +441,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="load_file" arity="1"/> + <name name="load_file" arity="1" since=""/> <fsummary>Load a module.</fsummary> <type name="load_ret"/> <desc> @@ -460,7 +460,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="load_abs" arity="1"/> + <name name="load_abs" arity="1" since=""/> <fsummary>Load a module, residing in a specified file.</fsummary> <type name="load_ret"/> <type name="loaded_filename"/> @@ -477,7 +477,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="ensure_loaded" arity="1"/> + <name name="ensure_loaded" arity="1" since=""/> <fsummary>Ensure that a module is loaded.</fsummary> <desc> <p>Tries to load a module in the same way as @@ -489,7 +489,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="load_binary" arity="3"/> + <name name="load_binary" arity="3" since=""/> <fsummary>Load object code for a module.</fsummary> <type name="loaded_filename"/> <type name="loaded_ret_atoms"/> @@ -507,7 +507,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="atomic_load" arity="1"/> + <name name="atomic_load" arity="1" since="OTP 19.0"/> <fsummary>Load a list of modules atomically</fsummary> <desc> <p>Tries to load all of the modules in the list @@ -566,7 +566,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="prepare_loading" arity="1"/> + <name name="prepare_loading" arity="1" since="OTP 19.0"/> <fsummary>Prepare a list of modules atomically</fsummary> <desc> <p>Prepares to load the modules in the list @@ -598,7 +598,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="finish_loading" arity="1"/> + <name name="finish_loading" arity="1" since="OTP 19.0"/> <fsummary>Finish loading a list of prepared modules atomically</fsummary> <desc> <p>Tries to load code for all modules that have been previously @@ -627,7 +627,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="ensure_modules_loaded" arity="1"/> + <name name="ensure_modules_loaded" arity="1" since="OTP 19.0"/> <fsummary>Ensure that a list of modules is loaded</fsummary> <desc> <p>Tries to load any modules not already loaded in the list @@ -639,7 +639,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="delete" arity="1"/> + <name name="delete" arity="1" since=""/> <fsummary>Remove current code for a module.</fsummary> <desc> <p>Removes the current code for <c><anno>Module</anno></c>, that is, @@ -652,7 +652,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="purge" arity="1"/> + <name name="purge" arity="1" since=""/> <fsummary>Remove old code for a module.</fsummary> <desc> <p>Purges the code for <c><anno>Module</anno></c>, that is, removes code @@ -668,7 +668,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="soft_purge" arity="1"/> + <name name="soft_purge" arity="1" since=""/> <fsummary>Remove old code for a module, unless no process uses it.</fsummary> <desc> <p>Purges the code for <c><anno>Module</anno></c>, that is, removes code @@ -683,7 +683,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="is_loaded" arity="1"/> + <name name="is_loaded" arity="1" since=""/> <fsummary>Check if a module is loaded.</fsummary> <type name="loaded_filename"/> <type name="loaded_ret_atoms"/> @@ -702,7 +702,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="all_loaded" arity="0"/> + <name name="all_loaded" arity="0" since=""/> <fsummary>Get all loaded modules.</fsummary> <type name="loaded_filename"/> <type name="loaded_ret_atoms"/> @@ -716,7 +716,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="which" arity="1"/> + <name name="which" arity="1" since=""/> <fsummary>The object code file of a module.</fsummary> <type name="loaded_ret_atoms"/> <desc> @@ -731,7 +731,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="get_object_code" arity="1"/> + <name name="get_object_code" arity="1" since=""/> <fsummary>Gets the object code for a module.</fsummary> <desc> <p>Searches the code path for the object code of module @@ -750,7 +750,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="root_dir" arity="0"/> + <name name="root_dir" arity="0" since=""/> <fsummary>Root directory of Erlang/OTP.</fsummary> <desc> <p>Returns the root directory of Erlang/OTP, which is @@ -762,7 +762,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="lib_dir" arity="0"/> + <name name="lib_dir" arity="0" since=""/> <fsummary>Library directory of Erlang/OTP.</fsummary> <desc> <p>Returns the library directory, <c>$OTPROOT/lib</c>, where @@ -774,7 +774,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="lib_dir" arity="1"/> + <name name="lib_dir" arity="1" since=""/> <fsummary>Library directory for an application.</fsummary> <desc> <p>Returns the path @@ -807,7 +807,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="lib_dir" arity="2"/> + <name name="lib_dir" arity="2" since=""/> <fsummary>Subdirectory for an application.</fsummary> <desc> <p>Returns the path to a subdirectory directly under the top @@ -827,7 +827,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="compiler_dir" arity="0"/> + <name name="compiler_dir" arity="0" since=""/> <fsummary>Library directory for the compiler.</fsummary> <desc> <p>Returns the compiler library directory. Equivalent to @@ -835,7 +835,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="priv_dir" arity="1"/> + <name name="priv_dir" arity="1" since=""/> <fsummary>Priv directory for an application.</fsummary> <desc> <p>Returns the path to the <c>priv</c> directory in an @@ -846,7 +846,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="objfile_extension" arity="0"/> + <name name="objfile_extension" arity="0" since=""/> <fsummary>Object code file extension.</fsummary> <desc> <p>Returns the object code file extension corresponding to @@ -854,7 +854,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="stick_dir" arity="1"/> + <name name="stick_dir" arity="1" since=""/> <fsummary>Mark a directory as sticky.</fsummary> <desc> <p>Marks <c><anno>Dir</anno></c> as sticky.</p> @@ -862,7 +862,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="unstick_dir" arity="1"/> + <name name="unstick_dir" arity="1" since=""/> <fsummary>Remove a sticky directory mark.</fsummary> <desc> <p>Unsticks a directory that is marked as @@ -871,7 +871,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="is_sticky" arity="1"/> + <name name="is_sticky" arity="1" since=""/> <fsummary>Test if a module is sticky.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Module</anno></c> is the @@ -882,7 +882,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="where_is_file" arity="1"/> + <name name="where_is_file" arity="1" since=""/> <fsummary>Full name of a file located in the code path.</fsummary> <desc> <p>Searches the code path for <c><anno>Filename</anno></c>, a file of @@ -893,7 +893,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="clash" arity="0"/> + <name name="clash" arity="0" since=""/> <fsummary>Search for modules with identical names.</fsummary> <desc> <p>Searches all directories in the code path for module names with @@ -901,7 +901,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="module_status" arity="1"/> + <name name="module_status" arity="1" since="OTP 20.0"/> <fsummary>Return the status of the module in relation to object file on disk.</fsummary> <desc> <p>Returns:</p> @@ -934,7 +934,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="modified_modules" arity="0"/> + <name name="modified_modules" arity="0" since="OTP 20.0"/> <fsummary>Return a list of all modules modified on disk.</fsummary> <desc> <p>Returns the list of all currently loaded modules for which @@ -943,7 +943,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="is_module_native" arity="1"/> + <name name="is_module_native" arity="1" since=""/> <fsummary>Test if a module has native code.</fsummary> <desc> <p>Returns:</p> @@ -961,7 +961,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </func> <func> - <name name="get_mode" arity="0"/> + <name name="get_mode" arity="0" since="OTP R16B"/> <fsummary>The mode of the code server.</fsummary> <desc> <p>Returns an atom describing the mode of the code server: diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml index 884cb32c0c..e308b06f3c 100644 --- a/lib/kernel/doc/src/disk_log.xml +++ b/lib/kernel/doc/src/disk_log.xml @@ -34,7 +34,7 @@ <rev>D</rev> <file>disk_log.sgml</file> </header> - <module>disk_log</module> + <module since="">disk_log</module> <modulesummary>A disk-based term logging facility.</modulesummary> <description> <p><c>disk_log</c> is a disk-based term logger that enables @@ -238,7 +238,7 @@ </datatypes> <funcs> <func> - <name name="accessible_logs" arity="0"/> + <name name="accessible_logs" arity="0" since=""/> <fsummary>Return the accessible disk logs on the current node.</fsummary> <desc> <p>Returns the names of the disk logs accessible on the current node. @@ -248,8 +248,8 @@ </desc> </func> <func> - <name name="alog" arity="2"/> - <name name="balog" arity="2"/> + <name name="alog" arity="2" since=""/> + <name name="balog" arity="2" since=""/> <fsummary>Asynchronously log an item on to a disk log.</fsummary> <type variable="Log"/> <type variable="Term" name_i="1"/> @@ -275,8 +275,8 @@ </desc> </func> <func> - <name name="alog_terms" arity="2"/> - <name name="balog_terms" arity="2"/> + <name name="alog_terms" arity="2" since=""/> + <name name="balog_terms" arity="2" since=""/> <fsummary>Asynchronously log many items on to a disk log.</fsummary> <type variable="Log"/> <type variable="TermList" name_i="1"/> @@ -303,8 +303,8 @@ </desc> </func> <func> - <name name="block" arity="1"/> - <name name="block" arity="2"/> + <name name="block" arity="1" since=""/> + <name name="block" arity="2" since=""/> <fsummary>Block a disk log.</fsummary> <type name="block_error_rsn"/> <desc> @@ -330,21 +330,21 @@ </desc> </func> <func> - <name name="change_header" arity="2"/> + <name name="change_header" arity="2" since=""/> <fsummary>Change option head or head_func for an owner of a disk log.</fsummary> <desc> <p>Changes the value of option <c>head</c> or <c>head_func</c> for an owner of a disk log.</p> </desc> </func> <func> - <name name="change_notify" arity="3"/> + <name name="change_notify" arity="3" since=""/> <fsummary>Change option notify for an owner of a disk log.</fsummary> <desc> <p>Changes the value of option <c>notify</c> for an owner of a disk log. </p> </desc> </func> <func> - <name name="change_size" arity="2"/> + <name name="change_size" arity="2" since=""/> <fsummary>Change the size of an open disk log.</fsummary> <desc> <p>Changes the size of an open log. @@ -384,10 +384,10 @@ </desc> </func> <func> - <name name="chunk" arity="2"/> - <name name="chunk" arity="3"/> - <name name="bchunk" arity="2"/> - <name name="bchunk" arity="3"/> + <name name="chunk" arity="2" since=""/> + <name name="chunk" arity="3" since=""/> + <name name="bchunk" arity="2" since=""/> + <name name="bchunk" arity="3" since=""/> <fsummary>Read a chunk of items written to a disk log.</fsummary> <type variable="Log"/> <type variable="Continuation"/> @@ -447,7 +447,7 @@ </desc> </func> <func> - <name name="chunk_info" arity="1"/> + <name name="chunk_info" arity="1" since=""/> <fsummary>Return information about a chunk continuation of a disk log.</fsummary> <desc> <p>Returns the pair <c>{node, <anno>Node</anno>}</c>, @@ -457,7 +457,7 @@ </desc> </func> <func> - <name name="chunk_step" arity="3"/> + <name name="chunk_step" arity="3" since=""/> <fsummary>Step forward or backward among the wrap log files of a disk log.</fsummary> <desc> <p>Can be used with <c>chunk/2,3</c> and <c>bchunk/2,3</c> @@ -480,7 +480,7 @@ </desc> </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a disk log.</fsummary> <type name="close_error_rsn"/> <desc> @@ -505,7 +505,7 @@ </desc> </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Return an English description of a disk log error reply.</fsummary> <desc> <p>Given the error returned by any function in this module, @@ -517,7 +517,7 @@ </desc> </func> <func> - <name name="inc_wrap_file" arity="1"/> + <name name="inc_wrap_file" arity="1" since=""/> <fsummary>Change to the next wrap log file of a disk log.</fsummary> <type name="inc_wrap_error_rsn"/> <type name="invalid_header"/> @@ -534,7 +534,7 @@ </desc> </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since=""/> <fsummary>Return information about a disk log.</fsummary> <type name="dlog_info"/> <desc> @@ -685,8 +685,8 @@ </desc> </func> <func> - <name name="lclose" arity="1"/> - <name name="lclose" arity="2"/> + <name name="lclose" arity="1" since=""/> + <name name="lclose" arity="2" since=""/> <fsummary>Close a disk log on one node.</fsummary> <type name="lclose_error_rsn"/> <desc> @@ -704,8 +704,8 @@ </desc> </func> <func> - <name name="log" arity="2"/> - <name name="blog" arity="2"/> + <name name="log" arity="2" since=""/> + <name name="blog" arity="2" since=""/> <fsummary>Log an item onto a disk log.</fsummary> <type variable="Log"/> <type variable="Term" name_i="1"/> @@ -739,8 +739,8 @@ </desc> </func> <func> - <name name="log_terms" arity="2"/> - <name name="blog_terms" arity="2"/> + <name name="log_terms" arity="2" since=""/> + <name name="blog_terms" arity="2" since=""/> <fsummary>Log many items onto a disk log.</fsummary> <type variable="Log"/> <type variable="TermList" name_i="1"/> @@ -768,7 +768,7 @@ </desc> </func> <func> - <name name="open" arity="1"/> + <name name="open" arity="1" since=""/> <fsummary>Open a disk log file.</fsummary> <type name="dlog_options"/> <type name="dlog_option"/> @@ -1041,7 +1041,7 @@ </desc> </func> <func> - <name name="pid2name" arity="1"/> + <name name="pid2name" arity="1" since=""/> <fsummary>Return the name of the disk log handled by a pid.</fsummary> <desc> <p>Returns the log name @@ -1053,9 +1053,9 @@ </desc> </func> <func> - <name name="reopen" arity="2"/> - <name name="reopen" arity="3"/> - <name name="breopen" arity="3"/> + <name name="reopen" arity="2" since=""/> + <name name="reopen" arity="3" since=""/> + <name name="breopen" arity="3" since=""/> <fsummary>Reopen a disk log and save the old log.</fsummary> <type variable="Log"/> <type variable="File" name_i="1"/> @@ -1087,7 +1087,7 @@ </desc> </func> <func> - <name name="sync" arity="1"/> + <name name="sync" arity="1" since=""/> <fsummary>Flush the contents of a disk log to the disk.</fsummary> <type name="sync_error_rsn"/> <desc> @@ -1097,9 +1097,9 @@ </desc> </func> <func> - <name name="truncate" arity="1"/> - <name name="truncate" arity="2"/> - <name name="btruncate" arity="2"/> + <name name="truncate" arity="1" since=""/> + <name name="truncate" arity="2" since=""/> + <name name="btruncate" arity="2" since=""/> <fsummary>Truncate a disk log.</fsummary> <type variable="Log"/> <type variable="Head" name_i="2"/> @@ -1129,7 +1129,7 @@ </desc> </func> <func> - <name name="unblock" arity="1"/> + <name name="unblock" arity="1" since=""/> <fsummary>Unblock a disk log.</fsummary> <type name="unblock_error_rsn"/> <desc> diff --git a/lib/kernel/doc/src/erl_boot_server.xml b/lib/kernel/doc/src/erl_boot_server.xml index 4109251387..89f9855c49 100644 --- a/lib/kernel/doc/src/erl_boot_server.xml +++ b/lib/kernel/doc/src/erl_boot_server.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>erl_boot_server</module> + <module since="">erl_boot_server</module> <modulesummary>Boot server for other Erlang machines.</modulesummary> <description> <p>This server is used to assist diskless Erlang nodes that fetch @@ -52,14 +52,14 @@ </description> <funcs> <func> - <name name="add_slave" arity="1"/> + <name name="add_slave" arity="1" since=""/> <fsummary>Add a slave to the list of allowed slaves.</fsummary> <desc> <p>Adds a <c><anno>Slave</anno></c> node to the list of allowed slave hosts.</p> </desc> </func> <func> - <name name="delete_slave" arity="1"/> + <name name="delete_slave" arity="1" since=""/> <fsummary>Delete a slave from the list of allowed slaves.</fsummary> <desc> <p>Deletes a <c><anno>Slave</anno></c> node from the list of allowed slave @@ -67,7 +67,7 @@ </desc> </func> <func> - <name name="start" arity="1"/> + <name name="start" arity="1" since=""/> <fsummary>Start the boot server.</fsummary> <desc> <p>Starts the boot server. <c><anno>Slaves</anno></c> is a list of @@ -76,7 +76,7 @@ </desc> </func> <func> - <name name="start_link" arity="1"/> + <name name="start_link" arity="1" since=""/> <fsummary>Start the boot server and link to the the caller.</fsummary> <desc> <p>Starts the boot server and links to the caller. This function @@ -85,7 +85,7 @@ </desc> </func> <func> - <name name="which_slaves" arity="0"/> + <name name="which_slaves" arity="0" since=""/> <fsummary>Return the current list of allowed slave hosts.</fsummary> <desc> <p>Returns the current list of allowed slave hosts.</p> diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml index 75114e015c..f2d5e1b397 100644 --- a/lib/kernel/doc/src/erl_ddll.xml +++ b/lib/kernel/doc/src/erl_ddll.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>erl_ddll</module> + <module since="">erl_ddll</module> <modulesummary>Dynamic driver loader and linker.</modulesummary> <description> <p>This module provides an interface for loading @@ -196,7 +196,7 @@ </datatypes> <funcs> <func> - <name name="demonitor" arity="1"/> + <name name="demonitor" arity="1" since=""/> <fsummary>Remove a monitor for a driver.</fsummary> <desc> <p>Removes a driver monitor in much the same way as @@ -212,7 +212,7 @@ </desc> </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Format an error descriptor.</fsummary> <desc> <p>Takes an <c><anno>ErrorDesc</anno></c> returned by load, unload, or @@ -229,7 +229,7 @@ </desc> </func> <func> - <name name="info" arity="0"/> + <name name="info" arity="0" since=""/> <fsummary>Retrieve information about all drivers.</fsummary> <desc> <p>Returns a list of tuples <c>{<anno>DriverName</anno>, <anno>InfoList</anno>}</c>, @@ -240,7 +240,7 @@ </desc> </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since=""/> <fsummary>Retrieve information about one driver.</fsummary> <desc> <p>Returns a list of tuples <c>{<anno>Tag</anno>, <anno>Value</anno>}</c>, @@ -266,7 +266,7 @@ </desc> </func> <func> - <name name="info" arity="2"/> + <name name="info" arity="2" since=""/> <fsummary>Retrieve specific information about one driver.</fsummary> <desc> <p>Returns specific information about one aspect of a driver. @@ -328,7 +328,7 @@ </desc> </func> <func> - <name name="load" arity="2"/> + <name name="load" arity="2" since=""/> <fsummary>Load a driver.</fsummary> <desc> <p>Loads and links the dynamic driver <c><anno>Name</anno></c>. @@ -390,7 +390,7 @@ </desc> </func> <func> - <name name="load_driver" arity="2"/> + <name name="load_driver" arity="2" since=""/> <fsummary>Load a driver.</fsummary> <desc> <p>Works essentially as <c>load/2</c>, but loads the driver @@ -413,7 +413,7 @@ </desc> </func> <func> - <name name="loaded_drivers" arity="0"/> + <name name="loaded_drivers" arity="0" since=""/> <fsummary>List loaded drivers.</fsummary> <desc> <p>Returns a list of all the available drivers, both @@ -425,7 +425,7 @@ </desc> </func> <func> - <name name="monitor" arity="2"/> + <name name="monitor" arity="2" since=""/> <fsummary>Create a monitor for a driver.</fsummary> <desc> <p>Creates a driver monitor and works in many @@ -588,7 +588,7 @@ </desc> </func> <func> - <name name="reload" arity="2"/> + <name name="reload" arity="2" since=""/> <fsummary>Replace a driver.</fsummary> <desc> <p>Reloads the driver named <c><anno>Name</anno></c> from a possibly @@ -626,7 +626,7 @@ </desc> </func> <func> - <name name="reload_driver" arity="2"/> + <name name="reload_driver" arity="2" since=""/> <fsummary>Replace a driver.</fsummary> <desc> <p>Works exactly as <seealso marker="#reload/2"><c>reload/2</c></seealso>, @@ -644,7 +644,7 @@ </desc> </func> <func> - <name name="try_load" arity="3"/> + <name name="try_load" arity="3" since=""/> <fsummary>Load a driver.</fsummary> <desc> <p>Provides more control than the @@ -931,7 +931,7 @@ </desc> </func> <func> - <name name="try_unload" arity="2"/> + <name name="try_unload" arity="2" since=""/> <fsummary>Unload a driver.</fsummary> <desc> <p>This is the low-level function to unload (or decrement @@ -1116,7 +1116,7 @@ </desc> </func> <func> - <name name="unload" arity="1"/> + <name name="unload" arity="1" since=""/> <fsummary>Unload a driver.</fsummary> <desc> <p>Unloads, or at least dereferences the driver named @@ -1143,7 +1143,7 @@ </desc> </func> <func> - <name name="unload_driver" arity="1"/> + <name name="unload_driver" arity="1" since=""/> <fsummary>Unload a driver.</fsummary> <desc> <p>Unloads, or at least dereferences the driver named diff --git a/lib/kernel/doc/src/erl_epmd.xml b/lib/kernel/doc/src/erl_epmd.xml index 8b076cd2d7..2adbf11a28 100644 --- a/lib/kernel/doc/src/erl_epmd.xml +++ b/lib/kernel/doc/src/erl_epmd.xml @@ -28,7 +28,7 @@ <date>2018-02-19</date> <rev>A</rev> </header> - <module>erl_epmd</module> + <module since="OTP R14B">erl_epmd</module> <modulesummary> Erlang interface towards epmd </modulesummary> @@ -41,7 +41,7 @@ <funcs> <func> - <name name="start_link" arity="0"/> + <name name="start_link" arity="0" since="OTP 21.0"/> <fsummary>Callback for erl_distribution supervisor.</fsummary> <desc> <p>This function is invoked as this module is added as a child of the @@ -50,8 +50,8 @@ </func> <func> - <name name="register_node" arity="2"/> - <name name="register_node" arity="3"/> + <name name="register_node" arity="2" since="OTP 21.0"/> + <name name="register_node" arity="3" since="OTP 21.0"/> <fsummary>Registers the node with <c>epmd</c>.</fsummary> <desc> <p>Registers the node with <c>epmd</c> and tells epmd what port will be @@ -62,8 +62,8 @@ </func> <func> - <name name="port_please" arity="2"/> - <name name="port_please" arity="3"/> + <name name="port_please" arity="2" since="OTP 21.0"/> + <name name="port_please" arity="3" since="OTP 21.0"/> <fsummary>Returns the port number for a given node.</fsummary> <desc> <p>Requests the distribution port for the given node of an EPMD @@ -73,7 +73,7 @@ </func> <func> - <name name="address_please" arity="3"/> + <name name="address_please" arity="3" since="OTP 21.0"/> <fsummary>Returns address and port.</fsummary> <desc> <p>Called by the distribution module. Resolves the <c>Host</c> to an IP @@ -84,7 +84,7 @@ </func> <func> - <name name="names" arity="1"/> + <name name="names" arity="1" since="OTP 21.0"/> <fsummary>Names of Erlang nodes at a host.</fsummary> <desc> <p>Called by <seealso marker="net_adm"><c>net_adm:names/0</c></seealso>. diff --git a/lib/kernel/doc/src/error_handler.xml b/lib/kernel/doc/src/error_handler.xml index e5639487dc..eb01e87aee 100644 --- a/lib/kernel/doc/src/error_handler.xml +++ b/lib/kernel/doc/src/error_handler.xml @@ -30,7 +30,7 @@ <date></date> <rev></rev> </header> - <module>error_handler</module> + <module since="">error_handler</module> <modulesummary>Default system error handler.</modulesummary> <description> <p>This module defines what happens when certain types @@ -38,7 +38,7 @@ </description> <funcs> <func> - <name name="raise_undef_exception" arity="3"/> + <name name="raise_undef_exception" arity="3" since="OTP R16B"/> <fsummary>Raise an undef exception.</fsummary> <type_desc variable="Args"> A (possibly empty) list of arguments <c>Arg1,..,ArgN</c> @@ -51,7 +51,7 @@ </desc> </func> <func> - <name name="undefined_function" arity="3"/> + <name name="undefined_function" arity="3" since=""/> <fsummary>Called when an undefined function is encountered.</fsummary> <type_desc variable="Args"> A (possibly empty) list of arguments <c>Arg1,..,ArgN</c> @@ -93,7 +93,7 @@ </desc> </func> <func> - <name name="undefined_lambda" arity="3"/> + <name name="undefined_lambda" arity="3" since=""/> <fsummary>Called when an undefined lambda (fun) is encountered.</fsummary> <type_desc variable="Args"> A (possibly empty) list of arguments <c>Arg1,..,ArgN</c> diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml index c3d68fd79f..c170b4fa34 100644 --- a/lib/kernel/doc/src/error_logger.xml +++ b/lib/kernel/doc/src/error_logger.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>error_logger</module> + <module since="">error_logger</module> <modulesummary>Erlang error logger.</modulesummary> <description> @@ -76,8 +76,8 @@ </datatypes> <funcs> <func> - <name name="add_report_handler" arity="1"/> - <name name="add_report_handler" arity="2"/> + <name name="add_report_handler" arity="1" since=""/> + <name name="add_report_handler" arity="2" since=""/> <fsummary>Add an event handler to the error logger.</fsummary> <desc> <p>Adds a new event handler to the error logger. The event @@ -96,7 +96,7 @@ </desc> </func> <func> - <name name="delete_report_handler" arity="1"/> + <name name="delete_report_handler" arity="1" since=""/> <fsummary>Delete an event handler from the error logger.</fsummary> <desc> <p>Deletes an event handler from the error logger by calling @@ -108,9 +108,9 @@ </desc> </func> <func> - <name name="error_msg" arity="1"/> - <name name="error_msg" arity="2"/> - <name name="format" arity="2"/> + <name name="error_msg" arity="1" since=""/> + <name name="error_msg" arity="2" since=""/> + <name name="format" arity="2" since=""/> <fsummary>Log a standard error event.</fsummary> <desc> <p>Log a standard error event. The <c><anno>Format</anno></c> @@ -142,7 +142,7 @@ ok</pre> </desc> </func> <func> - <name name="error_report" arity="1"/> + <name name="error_report" arity="1" since=""/> <fsummary>Log a standard error event.</fsummary> <desc> <p>Log a standard error event. Error logger forwards the event @@ -169,7 +169,7 @@ ok</pre> </desc> </func> <func> - <name name="error_report" arity="2"/> + <name name="error_report" arity="2" since=""/> <fsummary>Log a user-defined error event.</fsummary> <desc> <p>Log a user-defined error event. Error logger forwards the @@ -191,7 +191,7 @@ ok</pre> </desc> </func> <func> - <name name="get_format_depth" arity="0"/> + <name name="get_format_depth" arity="0" since="OTP 20.0"/> <fsummary>Get the value of the Kernel application variable <c>error_logger_format_depth</c>.</fsummary> <desc> @@ -211,8 +211,8 @@ ok</pre> </desc> </func> <func> - <name name="info_msg" arity="1"/> - <name name="info_msg" arity="2"/> + <name name="info_msg" arity="1" since=""/> + <name name="info_msg" arity="2" since=""/> <fsummary>Log a standard information event.</fsummary> <desc> <p>Log a standard information event. The <c><anno>Format</anno></c> @@ -244,7 +244,7 @@ ok</pre> </desc> </func> <func> - <name name="info_report" arity="1"/> + <name name="info_report" arity="1" since=""/> <fsummary>Log a standard information event.</fsummary> <desc> <p>Log a standard information event. Error logger forwards the @@ -271,7 +271,7 @@ ok</pre> </desc> </func> <func> - <name name="info_report" arity="2"/> + <name name="info_report" arity="2" since=""/> <fsummary>Log a user-defined information event.</fsummary> <desc> <p>Log a user-defined information event. Error logger forwards @@ -294,9 +294,9 @@ ok</pre> </desc> </func> <func> - <name name="logfile" arity="1" clause_i="1"/> - <name name="logfile" arity="1" clause_i="2"/> - <name name="logfile" arity="1" clause_i="3"/> + <name name="logfile" arity="1" clause_i="1" since=""/> + <name name="logfile" arity="1" clause_i="2" since=""/> + <name name="logfile" arity="1" clause_i="3" since=""/> <fsummary>Enable or disable error printouts to a file.</fsummary> <type variable="Filename"/> <type variable="OpenReason" name_i="1"/> @@ -346,7 +346,7 @@ ok</pre> </desc> </func> <func> - <name name="tty" arity="1"/> + <name name="tty" arity="1" since=""/> <fsummary>Enable or disable printouts to the terminal.</fsummary> <desc> <p>Enables (<c><anno>Flag</anno> == true</c>) or disables @@ -363,7 +363,7 @@ ok</pre> </desc> </func> <func> - <name name="warning_map" arity="0"/> + <name name="warning_map" arity="0" since=""/> <fsummary>Return the current mapping for warning events.</fsummary> <desc> <p>Returns the current mapping for warning events. Events sent @@ -400,8 +400,8 @@ ok</pre> </desc> </func> <func> - <name name="warning_msg" arity="1"/> - <name name="warning_msg" arity="2"/> + <name name="warning_msg" arity="1" since=""/> + <name name="warning_msg" arity="2" since=""/> <fsummary>Log a standard warning event.</fsummary> <desc> <p>Log a standard warning event. The <c><anno>Format</anno></c> @@ -429,7 +429,7 @@ ok</pre> </desc> </func> <func> - <name name="warning_report" arity="1"/> + <name name="warning_report" arity="1" since=""/> <fsummary>Log a standard warning event.</fsummary> <desc> <p>Log a standard warning event. Error logger forwards the event @@ -446,7 +446,7 @@ ok</pre> </desc> </func> <func> - <name name="warning_report" arity="2"/> + <name name="warning_report" arity="2" since=""/> <fsummary>Log a user-defined warning event.</fsummary> <desc> <p>Log a user-defined warning event. Error logger forwards the diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 9acaf6b41e..fc25e83d40 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>file</module> + <module since="">file</module> <modulesummary>File interface module.</modulesummary> <description> <p>This module provides an interface to the file system.</p> @@ -186,7 +186,7 @@ <funcs> <func> - <name name="advise" arity="4"/> + <name name="advise" arity="4" since="OTP R14B"/> <fsummary>Predeclare an access pattern for file data.</fsummary> <type name="posix_file_advise"/> <desc> @@ -197,7 +197,7 @@ </desc> </func> <func> - <name name="allocate" arity="3"/> + <name name="allocate" arity="3" since="OTP R16B"/> <fsummary>Allocate file space.</fsummary> <desc> <p><c>allocate/3</c> can be used to preallocate space for a file.</p> @@ -209,7 +209,7 @@ </desc> </func> <func> - <name name="change_group" arity="2"/> + <name name="change_group" arity="2" since=""/> <fsummary>Change group of a file.</fsummary> <desc> <p>Changes group of a file. See @@ -217,7 +217,7 @@ </desc> </func> <func> - <name name="change_mode" arity="2"/> + <name name="change_mode" arity="2" since="OTP R14B"/> <fsummary>Change permissions of a file.</fsummary> <desc> <p>Changes permissions of a file. See @@ -225,7 +225,7 @@ </desc> </func> <func> - <name name="change_owner" arity="2"/> + <name name="change_owner" arity="2" since=""/> <fsummary>Change owner of a file.</fsummary> <desc> <p>Changes owner of a file. See @@ -233,7 +233,7 @@ </desc> </func> <func> - <name name="change_owner" arity="3"/> + <name name="change_owner" arity="3" since=""/> <fsummary>Change owner and group of a file.</fsummary> <desc> <p>Changes owner and group of a file. See @@ -241,7 +241,7 @@ </desc> </func> <func> - <name name="change_time" arity="2"/> + <name name="change_time" arity="2" since=""/> <fsummary>Change the modification time of a file.</fsummary> <desc> <p>Changes the modification and access times of a file. See @@ -249,7 +249,7 @@ </desc> </func> <func> - <name name="change_time" arity="3"/> + <name name="change_time" arity="3" since=""/> <fsummary>Change the modification and last access time of a file.</fsummary> <desc> <p>Changes the modification and last access times of a file. See @@ -257,7 +257,7 @@ </desc> </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a file.</fsummary> <desc> <p>Closes the file referenced by <c><anno>IoDevice</anno></c>. It mostly @@ -270,7 +270,7 @@ </desc> </func> <func> - <name name="consult" arity="1"/> + <name name="consult" arity="1" since=""/> <fsummary>Read Erlang terms from a file.</fsummary> <desc> <p>Reads Erlang terms, separated by '.', from @@ -308,8 +308,8 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="copy" arity="2"/> - <name name="copy" arity="3"/> + <name name="copy" arity="2" since=""/> + <name name="copy" arity="3" since=""/> <fsummary>Copy file contents.</fsummary> <desc> <p>Copies <c><anno>ByteCount</anno></c> bytes from @@ -346,7 +346,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="datasync" arity="1"/> + <name name="datasync" arity="1" since="OTP R14B"/> <fsummary>Synchronize the in-memory data of a file, ignoring most of its metadata, with that on the physical medium.</fsummary> <desc> <p>Ensures that any buffers kept by the operating system @@ -369,7 +369,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="del_dir" arity="1"/> + <name name="del_dir" arity="1" since=""/> <fsummary>Delete a directory.</fsummary> <desc> <p>Tries to delete directory <c><anno>Dir</anno></c>. @@ -405,7 +405,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="delete" arity="1"/> + <name name="delete" arity="1" since=""/> <fsummary>Delete a file.</fsummary> <desc> <p>Tries to delete file <c><anno>Filename</anno></c>. @@ -442,7 +442,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="eval" arity="1"/> + <name name="eval" arity="1" since=""/> <fsummary>Evaluate Erlang expressions in a file.</fsummary> <desc> <p>Reads and evaluates Erlang expressions, separated by '.' (or @@ -476,7 +476,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="eval" arity="2"/> + <name name="eval" arity="2" since=""/> <fsummary>Evaluate Erlang expressions in a file.</fsummary> <desc> <p>The same as <c>eval/1</c>, but the variable bindings @@ -486,7 +486,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Return a descriptive string for an error reason.</fsummary> <desc> <p>Given the error reason returned by any function in this @@ -494,7 +494,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="get_cwd" arity="0"/> + <name name="get_cwd" arity="0" since=""/> <fsummary>Get the current working directory.</fsummary> <desc> <p>Returns <c>{ok, <anno>Dir</anno>}</c>, where <c><anno>Dir</anno></c> @@ -516,7 +516,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="get_cwd" arity="1"/> + <name name="get_cwd" arity="1" since=""/> <fsummary>Get the current working directory for the specified drive.</fsummary> <desc> <p>Returns <c>{ok, <anno>Dir</anno>}</c> or @@ -547,7 +547,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="list_dir" arity="1"/> + <name name="list_dir" arity="1" since=""/> <fsummary>List files in a directory.</fsummary> <desc> <p>Lists all files in a directory, <em>except</em> files @@ -578,7 +578,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="list_dir_all" arity="1"/> + <name name="list_dir_all" arity="1" since="OTP R16B"/> <fsummary>List all files in a directory.</fsummary> <desc> <p><marker id="list_dir_all"/>Lists all the files in a directory, @@ -603,7 +603,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="make_dir" arity="1"/> + <name name="make_dir" arity="1" since=""/> <fsummary>Make a directory.</fsummary> <desc> <p>Tries to create directory <c><anno>Dir</anno></c>. Missing parent @@ -637,7 +637,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="make_link" arity="2"/> + <name name="make_link" arity="2" since=""/> <fsummary>Make a hard link to a file.</fsummary> <desc> <p>Makes a hard link from <c><anno>Existing</anno></c> to @@ -666,7 +666,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="make_symlink" arity="2"/> + <name name="make_symlink" arity="2" since=""/> <fsummary>Make a symbolic link to a file or directory.</fsummary> <desc> <p>Creates a symbolic link <c><anno>New</anno></c> to @@ -702,7 +702,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="native_name_encoding" arity="0"/> + <name name="native_name_encoding" arity="0" since="OTP R14B01"/> <fsummary>Return the configured filename encoding of the VM.</fsummary> <desc> <p><marker id="native_name_encoding"/>Returns @@ -714,7 +714,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="open" arity="2"/> + <name name="open" arity="2" since=""/> <fsummary>Open a file.</fsummary> <desc> <p>Opens file <c><anno>File</anno></c> in the mode determined @@ -997,7 +997,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_consult" arity="2"/> + <name name="path_consult" arity="2" since=""/> <fsummary>Read Erlang terms from a file.</fsummary> <desc> <p>Searches the path <c><anno>Path</anno></c> (a list of directory @@ -1039,7 +1039,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_eval" arity="2"/> + <name name="path_eval" arity="2" since=""/> <fsummary>Evaluate Erlang expressions in a file.</fsummary> <desc> <p>Searches the path <c><anno>Path</anno></c> (a list of directory @@ -1085,7 +1085,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_open" arity="3"/> + <name name="path_open" arity="3" since=""/> <fsummary>Open a file.</fsummary> <desc> <p>Searches the path <c><anno>Path</anno></c> (a list of directory @@ -1114,7 +1114,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_script" arity="2"/> + <name name="path_script" arity="2" since=""/> <fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary> <desc> <p>Searches the path <c><anno>Path</anno></c> (a list of directory @@ -1158,7 +1158,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_script" arity="3"/> + <name name="path_script" arity="3" since=""/> <fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary> <desc> <p>The same as <c>path_script/2</c> but the variable bindings @@ -1168,7 +1168,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pid2name" arity="1"/> + <name name="pid2name" arity="1" since=""/> <fsummary>Return the name of the file handled by a pid.</fsummary> <desc> <p>If <c><anno>Pid</anno></c> is an I/O device, that is, a pid returned from @@ -1193,7 +1193,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="position" arity="2"/> + <name name="position" arity="2" since=""/> <fsummary>Set position in a file.</fsummary> <desc> <p>Sets the position of the file referenced by <c><anno>IoDevice</anno></c> @@ -1245,7 +1245,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pread" arity="2"/> + <name name="pread" arity="2" since=""/> <fsummary>Read from a file at certain positions.</fsummary> <desc> <p>Performs a sequence of <c>pread/3</c> in one operation, @@ -1263,7 +1263,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pread" arity="3"/> + <name name="pread" arity="3" since=""/> <fsummary>Read from a file at a certain position.</fsummary> <desc> <p>Combines <c>position/2</c> and <c>read/2</c> in one @@ -1283,7 +1283,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pwrite" arity="2"/> + <name name="pwrite" arity="2" since=""/> <fsummary>Write to a file at certain positions.</fsummary> <desc> <p>Performs a sequence of <c>pwrite/3</c> in one operation, @@ -1298,7 +1298,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pwrite" arity="3"/> + <name name="pwrite" arity="3" since=""/> <fsummary>Write to a file at a certain position.</fsummary> <desc> <p>Combines <c>position/2</c> and <c>write/2</c> in one @@ -1317,7 +1317,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read" arity="2"/> + <name name="read" arity="2" since=""/> <fsummary>Read from a file.</fsummary> <desc> <p>Reads <c><anno>Number</anno></c> bytes/characters from the file @@ -1371,7 +1371,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_file" arity="1"/> + <name name="read_file" arity="1" since=""/> <fsummary>Read a file.</fsummary> <desc> <p>Returns <c>{ok, <anno>Binary</anno>}</c>, where @@ -1407,8 +1407,8 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_file_info" arity="1"/> - <name name="read_file_info" arity="2"/> + <name name="read_file_info" arity="1" since=""/> + <name name="read_file_info" arity="2" since="OTP R15B"/> <fsummary>Retrieve information about a file.</fsummary> <desc> <p>Retrieves information about a file. Returns @@ -1562,7 +1562,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_line" arity="1"/> + <name name="read_line" arity="1" since=""/> <fsummary>Read a line from a file.</fsummary> <desc> <p>Reads a line of bytes/characters from the file referenced by @@ -1619,7 +1619,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_link" arity="1"/> + <name name="read_link" arity="1" since=""/> <fsummary>See what a link is pointing to.</fsummary> <desc> <p><marker id="read_link_all"/>Returns @@ -1649,7 +1649,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_link_all" arity="1"/> + <name name="read_link_all" arity="1" since="OTP R16B"/> <fsummary>See what a link is pointing to.</fsummary> <desc> <p>Returns <c>{ok, <anno>Filename</anno>}</c> if @@ -1677,8 +1677,8 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_link_info" arity="1"/> - <name name="read_link_info" arity="2"/> + <name name="read_link_info" arity="1" since=""/> + <name name="read_link_info" arity="2" since="OTP R15B"/> <fsummary>Retrieve information about a link or file.</fsummary> <desc> <p>Works like @@ -1699,7 +1699,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="rename" arity="2"/> + <name name="rename" arity="2" since=""/> <fsummary>Rename a file.</fsummary> <desc> <p>Tries to rename the file <c><anno>Source</anno></c> to @@ -1762,7 +1762,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="script" arity="1"/> + <name name="script" arity="1" since=""/> <fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary> <desc> <p>Reads and evaluates Erlang expressions, separated by '.' (or @@ -1797,7 +1797,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="script" arity="2"/> + <name name="script" arity="2" since=""/> <fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary> <desc> <p>The same as <c>script/1</c> but the variable bindings @@ -1807,7 +1807,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="sendfile" arity="2"/> + <name name="sendfile" arity="2" since="OTP R15B"/> <fsummary>Send a file to a socket.</fsummary> <desc> <p>Sends the file <c>Filename</c> to <c>Socket</c>. @@ -1816,7 +1816,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="sendfile" arity="5"/> + <name name="sendfile" arity="5" since="OTP R15B"/> <fsummary>Send a file to a socket.</fsummary> <type name="sendfile_option"/> <desc> @@ -1843,7 +1843,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="set_cwd" arity="1"/> + <name name="set_cwd" arity="1" since=""/> <fsummary>Set the current working directory.</fsummary> <desc> <p>Sets the current working directory of the file server to @@ -1890,7 +1890,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="sync" arity="1"/> + <name name="sync" arity="1" since=""/> <fsummary>Synchronize the in-memory state of a file with that on the physical medium.</fsummary> <desc> <p>Ensures that any buffers kept by the operating system @@ -1906,7 +1906,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="truncate" arity="1"/> + <name name="truncate" arity="1" since=""/> <fsummary>Truncate a file.</fsummary> <desc> <p>Truncates the file referenced by <c><anno>IoDevice</anno></c> at @@ -1915,7 +1915,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="write" arity="2"/> + <name name="write" arity="2" since=""/> <fsummary>Write to a file.</fsummary> <desc> <p>Writes <c><anno>Bytes</anno></c> to the file referenced by @@ -1941,7 +1941,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="write_file" arity="2"/> + <name name="write_file" arity="2" since=""/> <fsummary>Write a file.</fsummary> <desc> <p>Writes the contents of the <c>iodata</c> term <c><anno>Bytes</anno></c> @@ -1978,7 +1978,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="write_file" arity="3"/> + <name name="write_file" arity="3" since=""/> <fsummary>Write a file.</fsummary> <desc> <p>Same as <c>write_file/2</c>, but takes a third argument @@ -1989,8 +1989,8 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="write_file_info" arity="2"/> - <name name="write_file_info" arity="3"/> + <name name="write_file_info" arity="2" since=""/> + <name name="write_file_info" arity="3" since="OTP R15B"/> <fsummary>Change file information.</fsummary> <desc> <p>Changes file information. Returns <c>ok</c> if successful, diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index 1e08b25f66..f70d6c24db 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>gen_sctp.xml</file> </header> - <module>gen_sctp</module> + <module since="">gen_sctp</module> <modulesummary>Functions for communicating with sockets using the SCTP protocol.</modulesummary> <description> @@ -100,7 +100,7 @@ <funcs> <func> - <name name="abort" arity="2"/> + <name name="abort" arity="2" since=""/> <fsummary>Abnormally terminate the association specified by <c>Assoc</c>, without flushing of unsent data.</fsummary> <desc> @@ -113,7 +113,7 @@ </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close the socket and all associations on it.</fsummary> <desc> <p>Closes the socket and all associations on it. The unsent @@ -128,7 +128,7 @@ </func> <func> - <name name="connect" arity="4"/> + <name name="connect" arity="4" since=""/> <fsummary>Same as <c>connect(Socket, Addr, Port, Opts, infinity)</c>.</fsummary> <desc> <p>Same as <c>connect(<anno>Socket</anno>, <anno>Addr</anno>, @@ -137,7 +137,7 @@ </func> <func> - <name name="connect" arity="5"/> + <name name="connect" arity="5" since=""/> <fsummary>Establish a new association for socket <c>Socket</c>, with a peer (SCTP server socket).</fsummary> <desc> @@ -213,7 +213,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="connect_init" arity="4"/> + <name name="connect_init" arity="4" since="OTP R13B04"/> <fsummary>Same as <c>connect_init(Socket, Addr, Port, Opts, infinity)</c>..</fsummary> <desc> <p>Same as <c>connect_init(<anno>Socket</anno>, <anno>Addr</anno>, @@ -222,7 +222,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="connect_init" arity="5"/> + <name name="connect_init" arity="5" since="OTP R13B04"/> <fsummary>Initiate a new association for socket <c>Socket</c>, with a peer (SCTP server socket).</fsummary> <desc> @@ -248,7 +248,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="controlling_process" arity="2"/> + <name name="controlling_process" arity="2" since=""/> <fsummary>Assign a new controlling process pid to the socket.</fsummary> <desc> <p>Assigns a new controlling process <c><anno>Pid</anno></c> to @@ -259,7 +259,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="eof" arity="2"/> + <name name="eof" arity="2" since=""/> <fsummary>Gracefully terminate the association specified by <c>Assoc</c>, with flushing of all unsent data.</fsummary> <desc> @@ -272,7 +272,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="error_string" arity="1"/> + <name name="error_string" arity="1" since=""/> <fsummary>Translate an SCTP error number into a string.</fsummary> <desc> <p>Translates an SCTP error number from, for example, @@ -283,8 +283,8 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="listen" arity="2" clause_i="1"/> - <name name="listen" arity="2" clause_i="2"/> + <name name="listen" arity="2" clause_i="1" since=""/> + <name name="listen" arity="2" clause_i="2" since="OTP R15B"/> <fsummary>Set up a socket to listen.</fsummary> <desc> <p>Sets up a socket to listen on the IP address and port number @@ -300,10 +300,10 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="open" arity="0"/> - <name name="open" arity="1" clause_i="1"/> - <name name="open" arity="1" clause_i="2"/> - <name name="open" arity="2"/> + <name name="open" arity="0" since=""/> + <name name="open" arity="1" clause_i="1" since=""/> + <name name="open" arity="1" clause_i="2" since=""/> + <name name="open" arity="2" since=""/> <fsummary>Create an SCTP socket and binds it to local addresses.</fsummary> <desc> <p>Creates an SCTP socket and binds it to the local addresses @@ -366,7 +366,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="peeloff" arity="2"/> + <name name="peeloff" arity="2" since="OTP R15B"/> <fsummary>Peel off a type <c>stream</c> socket from a type <c>seqpacket</c> one.</fsummary> <desc> @@ -387,8 +387,8 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="recv" arity="1"/> - <name name="recv" arity="2"/> + <name name="recv" arity="1" since=""/> + <name name="recv" arity="2" since=""/> <fsummary>Receive a message from a socket.</fsummary> <desc> <p>Receives the <c><anno>Data</anno></c> message from any association @@ -532,7 +532,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="send" arity="3"/> + <name name="send" arity="3" since=""/> <fsummary>Send a message using an <c>#sctp_sndrcvinfo{}</c>record.</fsummary> <desc> <p>Sends the <c><anno>Data</anno></c> message with all sending @@ -547,7 +547,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="send" arity="4"/> + <name name="send" arity="4" since=""/> <fsummary>Send a message over an existing association and specified stream.</fsummary> <desc> diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index 24d63693fd..fc16473393 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -27,7 +27,7 @@ <date>1997-10-24</date> <rev>A</rev> </header> - <module>gen_tcp</module> + <module since="">gen_tcp</module> <modulesummary>Interface to TCP/IP sockets.</modulesummary> <description> <p>This module provides functions for communicating @@ -116,8 +116,8 @@ do_recv(Sock, Bs) -> <funcs> <func> - <name name="accept" arity="1"/> - <name name="accept" arity="2"/> + <name name="accept" arity="1" since=""/> + <name name="accept" arity="2" since=""/> <fsummary>Accept an incoming connection request on a listening socket.</fsummary> <type_desc variable="ListenSocket">Returned by <seealso marker="#listen/2"><c>listen/2</c></seealso>. @@ -163,7 +163,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a TCP socket.</fsummary> <desc> <p>Closes a TCP socket.</p> @@ -188,8 +188,8 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="connect" arity="3"/> - <name name="connect" arity="4"/> + <name name="connect" arity="3" since=""/> + <name name="connect" arity="4" since=""/> <fsummary>Connect to a TCP port.</fsummary> <desc> <p>Connects to a server on TCP port <c><anno>Port</anno></c> on the host @@ -268,7 +268,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="controlling_process" arity="2"/> + <name name="controlling_process" arity="2" since=""/> <fsummary>Change controlling process of a socket.</fsummary> <desc> <p>Assigns a new controlling process <c><anno>Pid</anno></c> to @@ -292,7 +292,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="listen" arity="2"/> + <name name="listen" arity="2" since=""/> <fsummary>Set up a socket to listen on a port.</fsummary> <desc> <p>Sets up a socket to listen on port <c><anno>Port</anno></c> on @@ -349,8 +349,8 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="recv" arity="2"/> - <name name="recv" arity="3"/> + <name name="recv" arity="2" since=""/> + <name name="recv" arity="3" since=""/> <fsummary>Receive a packet from a passive socket.</fsummary> <type_desc variable="HttpPacket">See the description of <c>HttpPacket</c> in @@ -375,7 +375,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="send" arity="2"/> + <name name="send" arity="2" since=""/> <fsummary>Send a packet.</fsummary> <desc> <p>Sends a packet on a socket.</p> @@ -386,7 +386,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="shutdown" arity="2"/> + <name name="shutdown" arity="2" since=""/> <fsummary>Asynchronously close a socket.</fsummary> <desc> <p>Closes a socket in one or two directions.</p> diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml index 840ca3c188..d20fc1fdfd 100644 --- a/lib/kernel/doc/src/gen_udp.xml +++ b/lib/kernel/doc/src/gen_udp.xml @@ -28,7 +28,7 @@ <date>1997-12-03</date> <rev>A</rev> </header> - <module>gen_udp</module> + <module since="">gen_udp</module> <modulesummary>Interface to UDP sockets.</modulesummary> <description> <p>This module provides functions for communicating @@ -53,7 +53,7 @@ <funcs> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a UDP socket.</fsummary> <desc> <p>Closes a UDP socket.</p> @@ -61,7 +61,7 @@ </func> <func> - <name name="controlling_process" arity="2"/> + <name name="controlling_process" arity="2" since=""/> <fsummary>Change controlling process of a socket.</fsummary> <desc> <p>Assigns a new controlling process <c><anno>Pid</anno></c> to @@ -77,8 +77,8 @@ </func> <func> - <name name="open" arity="1"/> - <name name="open" arity="2"/> + <name name="open" arity="1" since=""/> + <name name="open" arity="2" since=""/> <fsummary>Associate a UDP port number with the process calling it.</fsummary> <desc> <p>Associates a UDP port number (<c><anno>Port</anno></c>) with the @@ -189,8 +189,8 @@ </func> <func> - <name name="recv" arity="2"/> - <name name="recv" arity="3"/> + <name name="recv" arity="2" since=""/> + <name name="recv" arity="3" since=""/> <fsummary>Receive a packet from a passive socket.</fsummary> <desc> <p> @@ -213,7 +213,7 @@ </func> <func> - <name name="send" arity="4"/> + <name name="send" arity="4" since=""/> <fsummary>Send a packet.</fsummary> <desc> <p> diff --git a/lib/kernel/doc/src/global.xml b/lib/kernel/doc/src/global.xml index 4442741f54..dfe71de5ce 100644 --- a/lib/kernel/doc/src/global.xml +++ b/lib/kernel/doc/src/global.xml @@ -28,7 +28,7 @@ <date>1997-11-17</date> <rev></rev> </header> - <module>global</module> + <module since="">global</module> <modulesummary>A global name registration facility.</modulesummary> <description> <p>This module consists of the following services:</p> @@ -100,8 +100,8 @@ <funcs> <func> - <name name="del_lock" arity="1"/> - <name name="del_lock" arity="2"/> + <name name="del_lock" arity="1" since=""/> + <name name="del_lock" arity="2" since=""/> <fsummary>Delete a lock.</fsummary> <desc> <p>Deletes the lock <c><anno>Id</anno></c> synchronously.</p> @@ -109,7 +109,7 @@ </func> <func> - <name name="notify_all_name" arity="3"/> + <name name="notify_all_name" arity="3" since=""/> <fsummary>Name resolving function that notifies both pids.</fsummary> <desc> <p>Can be used as a name resolving function for @@ -123,7 +123,7 @@ </func> <func> - <name name="random_exit_name" arity="3"/> + <name name="random_exit_name" arity="3" since=""/> <fsummary>Name resolving function that kills one pid.</fsummary> <desc> <p>Can be used as a name resolving function for @@ -136,7 +136,7 @@ </func> <func> - <name name="random_notify_name" arity="3"/> + <name name="random_notify_name" arity="3" since=""/> <fsummary>Name resolving function that notifies one pid.</fsummary> <desc> <p>Can be used as a name resolving function for @@ -150,8 +150,8 @@ </func> <func> - <name name="re_register_name" arity="2"/> - <name name="re_register_name" arity="3"/> + <name name="re_register_name" arity="2" since=""/> + <name name="re_register_name" arity="3" since=""/> <fsummary>Atomically re-register a name.</fsummary> <type name="method"/> <type_desc name="method">{<c>Module</c>, <c>Function</c>} @@ -167,8 +167,8 @@ </func> <func> - <name name="register_name" arity="2"/> - <name name="register_name" arity="3"/> + <name name="register_name" arity="2" since=""/> + <name name="register_name" arity="3" since=""/> <fsummary>Globally register a name for a pid.</fsummary> <type name="method"/> <type_desc name="method">{<c>Module</c>, <c>Function</c>} is also @@ -221,7 +221,7 @@ </func> <func> - <name name="registered_names" arity="0"/> + <name name="registered_names" arity="0" since=""/> <fsummary>All globally registered names.</fsummary> <desc> <p>Returns a list of all globally registered names.</p> @@ -229,7 +229,7 @@ </func> <func> - <name name="send" arity="2"/> + <name name="send" arity="2" since=""/> <fsummary>Send a message to a globally registered pid.</fsummary> <desc> <p>Sends message <c><anno>Msg</anno></c> to the pid globally registered @@ -241,9 +241,9 @@ </func> <func> - <name name="set_lock" arity="1"/> - <name name="set_lock" arity="2"/> - <name name="set_lock" arity="3"/> + <name name="set_lock" arity="1" since=""/> + <name name="set_lock" arity="2" since=""/> + <name name="set_lock" arity="3" since=""/> <fsummary>Set a lock on the specified nodes.</fsummary> <type name="id"/> <type name="retries"/> @@ -287,7 +287,7 @@ </func> <func> - <name name="sync" arity="0"/> + <name name="sync" arity="0" since=""/> <fsummary>Synchronize the global name server.</fsummary> <desc> <p>Synchronizes the global name server with all nodes known to @@ -302,9 +302,9 @@ </func> <func> - <name name="trans" arity="2"/> - <name name="trans" arity="3"/> - <name name="trans" arity="4"/> + <name name="trans" arity="2" since=""/> + <name name="trans" arity="3" since=""/> + <name name="trans" arity="4" since=""/> <fsummary>Micro transaction facility.</fsummary> <type name="retries"/> <type name="trans_fun"/> @@ -322,7 +322,7 @@ </func> <func> - <name name="unregister_name" arity="1"/> + <name name="unregister_name" arity="1" since=""/> <fsummary>Remove a globally registered name for a pid.</fsummary> <desc> <p>Removes the globally registered name <c><anno>Name</anno></c> from @@ -331,7 +331,7 @@ </func> <func> - <name name="whereis_name" arity="1"/> + <name name="whereis_name" arity="1" since=""/> <fsummary>Get the pid with a specified globally registered name.</fsummary> <desc> <p>Returns the pid with the globally registered name diff --git a/lib/kernel/doc/src/global_group.xml b/lib/kernel/doc/src/global_group.xml index 8f947b9adf..74d15cd476 100644 --- a/lib/kernel/doc/src/global_group.xml +++ b/lib/kernel/doc/src/global_group.xml @@ -28,7 +28,7 @@ <date>1998-12-18</date> <rev>B</rev> </header> - <module>global_group</module> + <module since="">global_group</module> <modulesummary>Grouping nodes to global name registration groups.</modulesummary> <description> <p>This module makes it possible to partition the nodes of a @@ -105,7 +105,7 @@ <funcs> <func> - <name name="global_groups" arity="0"/> + <name name="global_groups" arity="0" since=""/> <fsummary>Return the global group names.</fsummary> <desc> <p>Returns a tuple containing the name of the global group that @@ -116,7 +116,7 @@ </func> <func> - <name name="info" arity="0"/> + <name name="info" arity="0" since=""/> <fsummary>Information about global groups.</fsummary> <type name="info_item"/> <type name="sync_state"/> @@ -173,7 +173,7 @@ </func> <func> - <name name="monitor_nodes" arity="1"/> + <name name="monitor_nodes" arity="1" since=""/> <fsummary>Subscribe to node status changes.</fsummary> <desc> <p>Depending on <c><anno>Flag</anno></c>, the calling process @@ -187,7 +187,7 @@ </func> <func> - <name name="own_nodes" arity="0"/> + <name name="own_nodes" arity="0" since=""/> <fsummary>Return the group nodes.</fsummary> <desc> <p>Returns the names of all group nodes, regardless of their @@ -196,7 +196,7 @@ </func> <func> - <name name="registered_names" arity="1"/> + <name name="registered_names" arity="1" since=""/> <fsummary>Return globally registered names.</fsummary> <desc> <p>Returns a list of all names that are globally registered @@ -205,8 +205,8 @@ </func> <func> - <name name="send" arity="2"/> - <name name="send" arity="3"/> + <name name="send" arity="2" since=""/> + <name name="send" arity="3" since=""/> <fsummary>Send a message to a globally registered pid.</fsummary> <desc> <p>Searches for <c><anno>Name</anno></c>, globally registered on @@ -224,7 +224,7 @@ </func> <func> - <name name="sync" arity="0"/> + <name name="sync" arity="0" since=""/> <fsummary>Synchronize the group nodes.</fsummary> <desc> <p>Synchronizes the group nodes, that is, the global name @@ -242,8 +242,8 @@ </func> <func> - <name name="whereis_name" arity="1"/> - <name name="whereis_name" arity="2"/> + <name name="whereis_name" arity="1" since=""/> + <name name="whereis_name" arity="2" since=""/> <fsummary>Get the pid with a specified globally registered name.</fsummary> <desc> <p>Searches for <c><anno>Name</anno></c>, globally registered on diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml index ad1a2ffeb9..4243b1ffe8 100644 --- a/lib/kernel/doc/src/heart.xml +++ b/lib/kernel/doc/src/heart.xml @@ -28,7 +28,7 @@ <date>1998-01-28</date> <rev>A</rev> </header> - <module>heart</module> + <module since="">heart</module> <modulesummary>Heartbeat monitoring of an Erlang runtime system.</modulesummary> <description> <p>This modules contains the interface to the <c>heart</c> process. @@ -119,7 +119,7 @@ <funcs> <func> - <name name="set_cmd" arity="1"/> + <name name="set_cmd" arity="1" since=""/> <fsummary>Set a temporary reboot command.</fsummary> <desc> <p>Sets a temporary reboot command. This command is used if @@ -136,7 +136,7 @@ </func> <func> - <name name="clear_cmd" arity="0"/> + <name name="clear_cmd" arity="0" since=""/> <fsummary>Clear the temporary boot command.</fsummary> <desc> <p>Clears the temporary boot command. If the system terminates, @@ -145,7 +145,7 @@ </func> <func> - <name name="get_cmd" arity="0"/> + <name name="get_cmd" arity="0" since=""/> <fsummary>Get the temporary reboot command.</fsummary> <desc> <p>Gets the temporary reboot command. If the command is cleared, @@ -154,7 +154,7 @@ </func> <func> - <name name="set_callback" arity="2"/> + <name name="set_callback" arity="2" since="OTP 18.3"/> <fsummary>Set a validation callback</fsummary> <desc> <p> This validation callback will be executed before any @@ -166,14 +166,14 @@ </desc> </func> <func> - <name name="clear_callback" arity="0"/> + <name name="clear_callback" arity="0" since="OTP 18.3"/> <fsummary>Clear the validation callback</fsummary> <desc> <p>Removes the validation callback call before heartbeats.</p> </desc> </func> <func> - <name name="get_callback" arity="0"/> + <name name="get_callback" arity="0" since="OTP 18.3"/> <fsummary>Get the validation callback</fsummary> <desc> <p>Get the validation callback. If the callback is cleared, <c>none</c> will be returned.</p> @@ -181,7 +181,7 @@ </func> <func> - <name name="set_options" arity="1"/> + <name name="set_options" arity="1" since="OTP 18.3"/> <fsummary>Set a list of options</fsummary> <desc> <p> Valid options <c>set_options</c> are: </p> @@ -199,7 +199,7 @@ </desc> </func> <func> - <name name="get_options" arity="0"/> + <name name="get_options" arity="0" since="OTP 18.3"/> <fsummary>Get the temporary reboot command</fsummary> <desc> <p>Returns <c>{ok, Options}</c> where <c>Options</c> is a list of current options enabled for heart. diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 87b08e4e36..104c698591 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -28,7 +28,7 @@ <date>1998-02-04</date> <rev>A</rev> </header> - <module>inet</module> + <module since="">inet</module> <modulesummary>Access to TCP/IP protocols.</modulesummary> <description> <p>This module provides access to TCP/IP protocols.</p> @@ -298,7 +298,7 @@ fe80::204:acff:fe17:bf38 <funcs> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a socket of any type.</fsummary> <desc> <p>Closes a socket of any type.</p> @@ -306,7 +306,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Return a descriptive string for an error reason.</fsummary> <desc> <p>Returns a diagnostic error string. For possible POSIX values and @@ -316,7 +316,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="get_rc" arity="0"/> + <name name="get_rc" arity="0" since=""/> <fsummary>Return a list of IP configuration parameters.</fsummary> <desc> <p> @@ -335,7 +335,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="getaddr" arity="2"/> + <name name="getaddr" arity="2" since=""/> <fsummary>Return the IP address for a host.</fsummary> <desc> <p>Returns the IP address for <c><anno>Host</anno></c> as a tuple of @@ -345,7 +345,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="getaddrs" arity="2"/> + <name name="getaddrs" arity="2" since=""/> <fsummary>Return the IP addresses for a host.</fsummary> <desc> <p>Returns a list of all IP addresses for <c><anno>Host</anno></c>. @@ -355,7 +355,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="gethostbyaddr" arity="1"/> + <name name="gethostbyaddr" arity="1" since=""/> <fsummary>Return a hostent record for the host with the specified address.</fsummary> <desc> @@ -364,7 +364,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="gethostbyname" arity="1"/> + <name name="gethostbyname" arity="1" since=""/> <fsummary>Return a hostent record for the host with the specified name. </fsummary> <desc> @@ -376,7 +376,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="gethostbyname" arity="2"/> + <name name="gethostbyname" arity="2" since=""/> <fsummary>Return a hostent record for the host with the specified name. </fsummary> <desc> @@ -386,7 +386,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="gethostname" arity="0"/> + <name name="gethostname" arity="0" since=""/> <fsummary>Return the local hostname.</fsummary> <desc> <p>Returns the local hostname. Never fails.</p> @@ -394,7 +394,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="getifaddrs" arity="0"/> + <name name="getifaddrs" arity="0" since="OTP R14B01"/> <fsummary>Return a list of interfaces and their addresses.</fsummary> <desc> <p> @@ -416,7 +416,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name>getifaddrs(Opts) -> + <name since="OTP 21.2">getifaddrs(Opts) -> {ok, [{Ifname, Ifopts}]} | {error, Posix} </name> <fsummary>Return a list of interfaces and their addresses.</fsummary> @@ -459,7 +459,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="getopts" arity="2"/> + <name name="getopts" arity="2" since=""/> <fsummary>Get one or more options for a socket.</fsummary> <desc> <p>Gets one or more options for a socket. For a list of available @@ -529,8 +529,8 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="getstat" arity="1"/> - <name name="getstat" arity="2"/> + <name name="getstat" arity="1" since=""/> + <name name="getstat" arity="2" since=""/> <fsummary>Get one or more statistic options for a socket.</fsummary> <type name="stat_option"/> <desc> @@ -586,9 +586,9 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="i" arity="0" /> - <name name="i" arity="1" /> - <name name="i" arity="2" /> + <name name="i" arity="0" since="OTP 21.0"/> + <name name="i" arity="1" since="OTP 21.0"/> + <name name="i" arity="2" since="OTP 21.0"/> <fsummary>Displays information and statistics about sockets on the terminal</fsummary> <desc> <p> @@ -641,7 +641,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="ntoa" arity="1" /> + <name name="ntoa" arity="1" since="OTP R16B02"/> <fsummary>Convert IPv6/IPV4 address to ASCII.</fsummary> <desc> <p>Parses an @@ -651,7 +651,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_address" arity="1" /> + <name name="parse_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv4 or IPv6 address.</fsummary> <desc> <p>Parses an IPv4 or IPv6 address string and returns an @@ -662,7 +662,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_ipv4_address" arity="1" /> + <name name="parse_ipv4_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv4 address.</fsummary> <desc> <p>Parses an IPv4 address string and returns an @@ -672,7 +672,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_ipv4strict_address" arity="1" /> + <name name="parse_ipv4strict_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv4 address strict.</fsummary> <desc> <p>Parses an IPv4 address string containing four fields, that is, @@ -683,7 +683,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_ipv6_address" arity="1" /> + <name name="parse_ipv6_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv6 address.</fsummary> <desc> <p>Parses an IPv6 address string and returns an @@ -694,7 +694,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_ipv6strict_address" arity="1" /> + <name name="parse_ipv6strict_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv6 address strict.</fsummary> <desc> <p>Parses an IPv6 address string and returns an @@ -704,7 +704,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="ipv4_mapped_ipv6_address" arity="1" /> + <name name="ipv4_mapped_ipv6_address" arity="1" since="OTP 21.0"/> <fsummary>Convert to and from IPv4-mapped IPv6 address.</fsummary> <desc> <p> @@ -717,7 +717,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_strict_address" arity="1" /> + <name name="parse_strict_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv4 or IPv6 address strict.</fsummary> <desc> <p>Parses an IPv4 or IPv6 address string and returns an @@ -728,7 +728,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="peername" arity="1"/> + <name name="peername" arity="1" since=""/> <fsummary>Return the address and port for the other end of a connection. </fsummary> <desc> @@ -741,7 +741,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="peernames" arity="1"/> + <name name="peernames" arity="1" since="OTP R16B03"/> <fsummary>Return all address/port numbers for the other end of a connection.</fsummary> <desc> @@ -755,7 +755,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="peernames" arity="2"/> + <name name="peernames" arity="2" since="OTP R16B03"/> <fsummary>Return all address/port numbers for the other end of a connection.</fsummary> <desc> @@ -774,7 +774,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="port" arity="1"/> + <name name="port" arity="1" since=""/> <fsummary>Return the local port number for a socket.</fsummary> <desc> <p>Returns the local port number for a socket.</p> @@ -782,7 +782,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="setopts" arity="2"/> + <name name="setopts" arity="2" since=""/> <fsummary>Set one or more options for a socket.</fsummary> <desc> <p>Sets one or more options for a socket.</p> @@ -1486,7 +1486,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code> </func> <func> - <name name="sockname" arity="1"/> + <name name="sockname" arity="1" since=""/> <fsummary>Return the local address and port number for a socket. </fsummary> <desc> @@ -1499,7 +1499,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code> </func> <func> - <name name="socknames" arity="1"/> + <name name="socknames" arity="1" since="OTP R16B03"/> <fsummary>Return all local address/port numbers for a socket.</fsummary> <desc> <p>Equivalent to @@ -1509,7 +1509,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code> </func> <func> - <name name="socknames" arity="2"/> + <name name="socknames" arity="2" since="OTP R16B03"/> <fsummary>Return all local address/port numbers for a socket.</fsummary> <desc> <p>Returns a list of all local address/port number pairs for a socket diff --git a/lib/kernel/doc/src/inet_res.xml b/lib/kernel/doc/src/inet_res.xml index 351d86a93a..1904e371f7 100644 --- a/lib/kernel/doc/src/inet_res.xml +++ b/lib/kernel/doc/src/inet_res.xml @@ -28,7 +28,7 @@ <date>2009-09-11</date> <rev>A</rev> </header> - <module>inet_res</module> + <module since="">inet_res</module> <modulesummary>A rudimentary DNS client.</modulesummary> <description> <p>This module performs DNS name resolving to recursive name servers.</p> @@ -185,8 +185,8 @@ inet_dns:record_type(_) -> undefined.</pre> <funcs> <func> - <name name="getbyname" arity="2"/> - <name name="getbyname" arity="3"/> + <name name="getbyname" arity="2" since=""/> + <name name="getbyname" arity="3" since=""/> <fsummary>Resolve a DNS record of the specified type for the specified host.</fsummary> <desc> @@ -205,8 +205,8 @@ inet_dns:record_type(_) -> undefined.</pre> </func> <func> - <name name="gethostbyaddr" arity="1"/> - <name name="gethostbyaddr" arity="2"/> + <name name="gethostbyaddr" arity="1" since=""/> + <name name="gethostbyaddr" arity="2" since=""/> <fsummary>Return a hostent record for the host with the specified address.</fsummary> <desc> @@ -217,9 +217,9 @@ inet_dns:record_type(_) -> undefined.</pre> </func> <func> - <name name="gethostbyname" arity="1"/> - <name name="gethostbyname" arity="2"/> - <name name="gethostbyname" arity="3"/> + <name name="gethostbyname" arity="1" since=""/> + <name name="gethostbyname" arity="2" since=""/> + <name name="gethostbyname" arity="3" since=""/> <fsummary>Return a hostent record for the host with the specified name. </fsummary> <desc> @@ -235,9 +235,9 @@ inet_dns:record_type(_) -> undefined.</pre> </func> <func> - <name name="lookup" arity="3"/> - <name name="lookup" arity="4"/> - <name name="lookup" arity="5"/> + <name name="lookup" arity="3" since=""/> + <name name="lookup" arity="4" since=""/> + <name name="lookup" arity="5" since=""/> <fsummary>Resolve the DNS data for the record of the specified type and class for the specified name.</fsummary> <desc> @@ -257,9 +257,9 @@ inet_dns:record_type(_) -> undefined.</pre> </func> <func> - <name name="resolve" arity="3"/> - <name name="resolve" arity="4"/> - <name name="resolve" arity="5"/> + <name name="resolve" arity="3" since=""/> + <name name="resolve" arity="4" since=""/> + <name name="resolve" arity="5" since=""/> <fsummary>Resolve a DNS record of the specified type and class for the specified name.</fsummary> <desc> @@ -326,9 +326,9 @@ example_lookup(Name, Class, Type) -> <funcs> <func> - <name name="nslookup" arity="3"/> - <name name="nslookup" arity="4" clause_i="1"/> - <name name="nslookup" arity="4" clause_i="2"/> + <name name="nslookup" arity="3" since=""/> + <name name="nslookup" arity="4" clause_i="1" since=""/> + <name name="nslookup" arity="4" clause_i="2" since=""/> <fsummary>Resolve a DNS record of the specified type and class for the specified name.</fsummary> <type variable="Name"/> @@ -344,8 +344,8 @@ example_lookup(Name, Class, Type) -> </func> <func> - <name name="nnslookup" arity="4"/> - <name name="nnslookup" arity="5"/> + <name name="nnslookup" arity="4" since=""/> + <name name="nnslookup" arity="5" since=""/> <fsummary>Resolve a DNS record of the specified type and class for the specified name.</fsummary> <desc> diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml index 556f25f96a..0668676096 100644 --- a/lib/kernel/doc/src/logger.xml +++ b/lib/kernel/doc/src/logger.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger.xml</file> </header> - <module>logger</module> + <module since="OTP 21.0">logger</module> <modulesummary>API module for Logger, the standard logging facility in Erlang/OTP.</modulesummary> @@ -245,6 +245,12 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </desc> </datatype> <datatype> + <name name="olp_config"/> + <desc> + <p></p> + </desc> + </datatype> + <datatype> <name name="primary_config"/> <desc> <p>Primary configuration data for Logger. The following @@ -334,9 +340,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </section> <funcs> <func> - <name>emergency(StringOrReport[,Metadata])</name> - <name>emergency(Format,Args[,Metadata])</name> - <name>emergency(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">emergency(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">emergency(Format,Args[,Metadata])</name> + <name since="OTP 21.0">emergency(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>emergency</c>.</fsummary> <desc> <p>Equivalent to @@ -345,9 +351,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>alert(StringOrReport[,Metadata])</name> - <name>alert(Format,Args[,Metadata])</name> - <name>alert(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">alert(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">alert(Format,Args[,Metadata])</name> + <name since="OTP 21.0">alert(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>alert</c>.</fsummary> <desc> <p>Equivalent to @@ -356,9 +362,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>critical(StringOrReport[,Metadata])</name> - <name>critical(Format,Args[,Metadata])</name> - <name>critical(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">critical(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">critical(Format,Args[,Metadata])</name> + <name since="OTP 21.0">critical(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>critical</c>.</fsummary> <desc> <p>Equivalent to @@ -367,9 +373,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>error(StringOrReport[,Metadata])</name> - <name>error(Format,Args[,Metadata])</name> - <name>error(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">error(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">error(Format,Args[,Metadata])</name> + <name since="OTP 21.0">error(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>error</c>.</fsummary> <desc> <p>Equivalent to @@ -378,9 +384,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>warning(StringOrReport[,Metadata])</name> - <name>warning(Format,Args[,Metadata])</name> - <name>warning(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">warning(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">warning(Format,Args[,Metadata])</name> + <name since="OTP 21.0">warning(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>warning</c>.</fsummary> <desc> <p>Equivalent to @@ -389,9 +395,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>notice(StringOrReport[,Metadata])</name> - <name>notice(Format,Args[,Metadata])</name> - <name>notice(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">notice(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">notice(Format,Args[,Metadata])</name> + <name since="OTP 21.0">notice(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>notice</c>.</fsummary> <desc> <p>Equivalent to @@ -400,9 +406,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>info(StringOrReport[,Metadata])</name> - <name>info(Format,Args[,Metadata])</name> - <name>info(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">info(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">info(Format,Args[,Metadata])</name> + <name since="OTP 21.0">info(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>info</c>.</fsummary> <desc> <p>Equivalent to @@ -411,9 +417,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>debug(StringOrReport[,Metadata])</name> - <name>debug(Format,Args[,Metadata])</name> - <name>debug(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">debug(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">debug(Format,Args[,Metadata])</name> + <name since="OTP 21.0">debug(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>debug</c>.</fsummary> <desc> <p>Equivalent to @@ -422,12 +428,12 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name name="log" arity="2"/> - <name name="log" arity="3" clause_i="1"/> - <name name="log" arity="3" clause_i="2"/> - <name name="log" arity="3" clause_i="3"/> - <name name="log" arity="4" clause_i="1"/> - <name name="log" arity="4" clause_i="2"/> + <name name="log" arity="2" since="OTP 21.0"/> + <name name="log" arity="3" clause_i="1" since="OTP 21.0"/> + <name name="log" arity="3" clause_i="2" since="OTP 21.0"/> + <name name="log" arity="3" clause_i="3" since="OTP 21.0"/> + <name name="log" arity="4" clause_i="1" since="OTP 21.0"/> + <name name="log" arity="4" clause_i="2" since="OTP 21.0"/> <fsummary>Logs the given message.</fsummary> <type variable="Level"/> <type variable="StringOrReport" name_i="1"/> @@ -448,7 +454,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </section> <funcs> <func> - <name name="add_handler" arity="3"/> + <name name="add_handler" arity="3" since="OTP 21.0"/> <fsummary>Add a handler with the given configuration.</fsummary> <desc> <p>Add a handler with the given configuration.</p> @@ -459,7 +465,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name name="add_handler_filter" arity="3"/> + <name name="add_handler_filter" arity="3" since="OTP 21.0"/> <fsummary>Add a filter to the specified handler.</fsummary> <desc> <p>Add a filter to the specified handler.</p> @@ -500,7 +506,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name name="add_handlers" arity="1" clause_i="1"/> + <name name="add_handlers" arity="1" clause_i="1" since="OTP 21.0"/> <fsummary>Set up log handlers from the application's configuration parameters.</fsummary> <desc> @@ -510,7 +516,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name name="add_handlers" arity="1" clause_i="2"/> + <name name="add_handlers" arity="1" clause_i="2" since="OTP 21.0"/> <fsummary>Setup logger handlers.</fsummary> <type name="config_handler"/> <desc> @@ -553,7 +559,7 @@ start(_, []) -> </func> <func> - <name name="add_primary_filter" arity="2"/> + <name name="add_primary_filter" arity="2" since="OTP 21.0"/> <fsummary>Add a primary filter to Logger.</fsummary> <desc> <p>Add a primary filter to Logger.</p> @@ -594,16 +600,16 @@ start(_, []) -> </func> <func> - <name name="get_config" arity="0"/> + <name name="get_config" arity="0" since="OTP 21.0"/> <fsummary>Look up the current Logger configuration</fsummary> <desc> - <p>Look up all current Logger configuration, including primary - and handler configuration, and module level settings.</p> + <p>Look up all current Logger configuration, including primary, + handler, and proxy configuration, and module level settings.</p> </desc> </func> <func> - <name name="get_handler_config" arity="0"/> + <name name="get_handler_config" arity="0" since="OTP 21.0"/> <fsummary>Look up the current configuration for all handlers.</fsummary> <desc> <p>Look up the current configuration for all handlers.</p> @@ -611,7 +617,7 @@ start(_, []) -> </func> <func> - <name name="get_handler_config" arity="1"/> + <name name="get_handler_config" arity="1" since="OTP 21.0"/> <fsummary>Look up the current configuration for the given handler.</fsummary> <desc> @@ -620,7 +626,7 @@ start(_, []) -> </func> <func> - <name name="get_handler_ids" arity="0"/> + <name name="get_handler_ids" arity="0" since="OTP 21.0"/> <fsummary>Look up the identities for all installed handlers.</fsummary> <desc> <p>Look up the identities for all installed handlers.</p> @@ -628,7 +634,7 @@ start(_, []) -> </func> <func> - <name name="get_primary_config" arity="0"/> + <name name="get_primary_config" arity="0" since="OTP 21.0"/> <fsummary>Look up the current primary configuration for Logger.</fsummary> <desc> <p>Look up the current primary configuration for Logger.</p> @@ -636,7 +642,18 @@ start(_, []) -> </func> <func> - <name name="get_module_level" arity="0"/> + <name name="get_proxy_config" arity="0" since="OTP 21.3"/> + <fsummary>Look up the current configuration for the Logger proxy.</fsummary> + <desc> + <p>Look up the current configuration for the Logger proxy.</p> + <p>For more information about the proxy, see + section <seealso marker="logger_chapter#proxy">Logger + Proxy</seealso> in the Kernel User's Guide.</p> + </desc> + </func> + + <func> + <name name="get_module_level" arity="0" since="OTP 21.0"/> <fsummary>Look up all current module levels.</fsummary> <desc> <p>Look up all current module levels. Returns a list @@ -648,7 +665,7 @@ start(_, []) -> </func> <func> - <name name="get_module_level" arity="1"/> + <name name="get_module_level" arity="1" since="OTP 21.0"/> <fsummary>Look up the current level for the given modules.</fsummary> <desc> <p>Look up the current level for the given modules. Returns a @@ -660,7 +677,7 @@ start(_, []) -> </func> <func> - <name name="get_process_metadata" arity="0"/> + <name name="get_process_metadata" arity="0" since="OTP 21.0"/> <fsummary>Retrieve data set with set_process_metadata/1.</fsummary> <desc> <p>Retrieve data set @@ -672,7 +689,7 @@ start(_, []) -> </func> <func> - <name name="remove_handler" arity="1"/> + <name name="remove_handler" arity="1" since="OTP 21.0"/> <fsummary>Remove the handler with the specified identity.</fsummary> <desc> <p>Remove the handler identified by <c><anno>HandlerId</anno></c>.</p> @@ -680,7 +697,7 @@ start(_, []) -> </func> <func> - <name name="remove_handler_filter" arity="2"/> + <name name="remove_handler_filter" arity="2" since="OTP 21.0"/> <fsummary>Remove a filter from the specified handler.</fsummary> <desc> <p>Remove the filter identified @@ -690,7 +707,7 @@ start(_, []) -> </func> <func> - <name name="remove_primary_filter" arity="1"/> + <name name="remove_primary_filter" arity="1" since="OTP 21.0"/> <fsummary>Remove a primary filter from Logger.</fsummary> <desc> <p>Remove the primary filter identified @@ -699,7 +716,7 @@ start(_, []) -> </func> <func> - <name name="set_application_level" arity="2"/> + <name name="set_application_level" arity="2" since="OTP 21.1"/> <fsummary>Set the log level for all modules in the specified application.</fsummary> <desc> <p>Set the log level for all the modules of the specified application.</p> @@ -710,7 +727,7 @@ start(_, []) -> </func> <func> - <name name="set_handler_config" arity="2"/> + <name name="set_handler_config" arity="2" since="OTP 21.0"/> <fsummary>Set configuration data for the specified handler.</fsummary> <desc> <p>Set configuration data for the specified handler. This @@ -731,11 +748,11 @@ start(_, []) -> </func> <func> - <name name="set_handler_config" arity="3" clause_i="1"/> - <name name="set_handler_config" arity="3" clause_i="2"/> - <name name="set_handler_config" arity="3" clause_i="3"/> - <name name="set_handler_config" arity="3" clause_i="4"/> - <name name="set_handler_config" arity="3" clause_i="5"/> + <name name="set_handler_config" arity="3" clause_i="1" since="OTP 21.0"/> + <name name="set_handler_config" arity="3" clause_i="2" since="OTP 21.0"/> + <name name="set_handler_config" arity="3" clause_i="3" since="OTP 21.0"/> + <name name="set_handler_config" arity="3" clause_i="4" since="OTP 21.0"/> + <name name="set_handler_config" arity="3" clause_i="5" since="OTP 21.0"/> <fsummary>Add or update configuration data for the specified handler.</fsummary> <type variable="HandlerId"/> @@ -767,7 +784,7 @@ start(_, []) -> </func> <func> - <name name="set_primary_config" arity="1"/> + <name name="set_primary_config" arity="1" since="OTP 21.0"/> <fsummary>Set primary configuration data for Logger.</fsummary> <desc> <p>Set primary configuration data for Logger. This @@ -785,9 +802,9 @@ start(_, []) -> </func> <func> - <name name="set_primary_config" arity="2" clause_i="1"/> - <name name="set_primary_config" arity="2" clause_i="2"/> - <name name="set_primary_config" arity="2" clause_i="3"/> + <name name="set_primary_config" arity="2" clause_i="1" since="OTP 21.0"/> + <name name="set_primary_config" arity="2" clause_i="2" since="OTP 21.0"/> + <name name="set_primary_config" arity="2" clause_i="3" since="OTP 21.0"/> <fsummary>Add or update primary configuration data for Logger.</fsummary> <type variable="Level" name_i="1"/> <type variable="FilterDefault" name_i="2"/> @@ -801,7 +818,28 @@ start(_, []) -> </func> <func> - <name name="set_module_level" arity="2"/> + <name name="set_proxy_config" arity="1" since="OTP 21.3"/> + <fsummary>Set configuration data for the Logger proxy.</fsummary> + <desc> + <p>Set configuration data for the Logger proxy. This + overwrites the current proxy configuration. Keys that are not + specified in the <c><anno>Config</anno></c> map gets default + values.</p> + <p>To modify the existing configuration, + use <seealso marker="#update_proxy_config-1"> + <c>update_proxy_config/1</c></seealso>, or, if a more + complex merge is needed, read the current configuration + with <seealso marker="#get_proxy_config-0"><c>get_proxy_config/0</c> + </seealso>, then do the merge before writing the new + configuration back with this function.</p> + <p>For more information about the proxy, see + section <seealso marker="logger_chapter#proxy">Logger + Proxy</seealso> in the Kernel User's Guide.</p> + </desc> + </func> + + <func> + <name name="set_module_level" arity="2" since="OTP 21.0"/> <fsummary>Set the log level for the specified modules.</fsummary> <desc> <p>Set the log level for the specified modules.</p> @@ -841,7 +879,7 @@ start(_, []) -> </func> <func> - <name name="set_process_metadata" arity="1"/> + <name name="set_process_metadata" arity="1" since="OTP 21.0"/> <fsummary>Set metadata to use when logging from current process.</fsummary> <desc> <p>Set metadata which Logger shall automatically insert in @@ -860,7 +898,7 @@ start(_, []) -> </func> <func> - <name name="unset_application_level" arity="1"/> + <name name="unset_application_level" arity="1" since="OTP 21.1"/> <fsummary>Unset the log level for all modules in the specified application.</fsummary> <desc> <p>Unset the log level for all the modules of the specified application.</p> @@ -871,7 +909,7 @@ start(_, []) -> </func> <func> - <name name="unset_module_level" arity="0"/> + <name name="unset_module_level" arity="0" since="OTP 21.0"/> <fsummary>Remove module specific log settings for all modules.</fsummary> <desc> <p>Remove module specific log settings. After this, the @@ -880,7 +918,7 @@ start(_, []) -> </func> <func> - <name name="unset_module_level" arity="1"/> + <name name="unset_module_level" arity="1" since="OTP 21.0"/> <fsummary>Remove module specific log settings for the given modules.</fsummary> <desc> @@ -890,7 +928,7 @@ start(_, []) -> </func> <func> - <name name="unset_process_metadata" arity="0"/> + <name name="unset_process_metadata" arity="0" since="OTP 21.0"/> <fsummary>Delete data set with set_process_metadata/1.</fsummary> <desc> <p>Delete data set @@ -902,7 +940,7 @@ start(_, []) -> </func> <func> - <name name="update_formatter_config" arity="2"/> + <name name="update_formatter_config" arity="2" since="OTP 21.0"/> <fsummary>Update the formatter configuration for the specified handler.</fsummary> <desc> <p>Update the formatter configuration for the specified handler.</p> @@ -917,7 +955,7 @@ start(_, []) -> </func> <func> - <name name="update_formatter_config" arity="3"/> + <name name="update_formatter_config" arity="3" since="OTP 21.0"/> <fsummary>Update the formatter configuration for the specified handler.</fsummary> <desc> <p>Update the formatter configuration for the specified handler.</p> @@ -928,7 +966,7 @@ start(_, []) -> </func> <func> - <name name="update_handler_config" arity="2"/> + <name name="update_handler_config" arity="2" since="OTP 21.0"/> <fsummary>Update configuration data for the specified handler.</fsummary> <desc> <p>Update configuration data for the specified handler. This function @@ -944,11 +982,11 @@ logger:set_handler_config(HandlerId, maps:merge(Old, Config)). </func> <func> - <name name="update_handler_config" arity="3" clause_i="1"/> - <name name="update_handler_config" arity="3" clause_i="2"/> - <name name="update_handler_config" arity="3" clause_i="3"/> - <name name="update_handler_config" arity="3" clause_i="4"/> - <name name="update_handler_config" arity="3" clause_i="5"/> + <name name="update_handler_config" arity="3" clause_i="1" since="OTP 21.2"/> + <name name="update_handler_config" arity="3" clause_i="2" since="OTP 21.2"/> + <name name="update_handler_config" arity="3" clause_i="3" since="OTP 21.2"/> + <name name="update_handler_config" arity="3" clause_i="4" since="OTP 21.2"/> + <name name="update_handler_config" arity="3" clause_i="5" since="OTP 21.2"/> <fsummary>Add or update configuration data for the specified handler.</fsummary> <type variable="HandlerId"/> @@ -980,7 +1018,7 @@ logger:set_handler_config(HandlerId, maps:merge(Old, Config)). </func> <func> - <name name="update_primary_config" arity="1"/> + <name name="update_primary_config" arity="1" since="OTP 21.0"/> <fsummary>Update primary configuration data for Logger.</fsummary> <desc> <p>Update primary configuration data for Logger. This function @@ -996,7 +1034,7 @@ logger:set_primary_config(maps:merge(Old, Config)). </func> <func> - <name name="update_process_metadata" arity="1"/> + <name name="update_process_metadata" arity="1" since="OTP 21.0"/> <fsummary>Set or update metadata to use when logging from current process.</fsummary> <desc> @@ -1013,6 +1051,25 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </seealso>.</p> </desc> </func> + + <func> + <name name="update_proxy_config" arity="1" since="OTP 21.3"/> + <fsummary>Update configuration data for the Logger proxy.</fsummary> + <desc> + <p>Update configuration data for the Logger proxy. This function + behaves as if it was implemented as follows:</p> + <code type="erl"> +Old = logger:get_proxy_config(), +logger:set_proxy_config(maps:merge(Old, Config)). + </code> + <p>To overwrite the existing configuration without any merge, + use <seealso marker="#set_proxy_config-1"><c>set_proxy_config/1</c> + </seealso>.</p> + <p>For more information about the proxy, see + section <seealso marker="logger_chapter#proxy">Logger + Proxy</seealso> in the Kernel User's Guide.</p> + </desc> + </func> </funcs> <section> @@ -1021,7 +1078,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </section> <funcs> <func> - <name name="compare_levels" arity="2"/> + <name name="compare_levels" arity="2" since="OTP 21.0"/> <fsummary>Compare the severity of two log levels.</fsummary> <desc> <p>Compare the severity of two log levels. Returns <c>gt</c> @@ -1032,7 +1089,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name name="format_report" arity="1"/> + <name name="format_report" arity="1" since="OTP 21.0"/> <fsummary>Convert a log message on report form to {Format, Args}.</fsummary> <desc> <p>Convert a log message on report form to <c>{Format, @@ -1062,7 +1119,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). <funcs> <func> - <name>HModule:adding_handler(Config1) -> {ok, Config2} | {error, + <name since="OTP 21.0">HModule:adding_handler(Config1) -> {ok, Config2} | {error, Reason}</name> <fsummary>An instance of this handler is about to be added.</fsummary> <type> @@ -1088,7 +1145,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name>HModule:changing_config(SetOrUpdate, OldConfig, NewConfig) -> {ok, Config} | {error, Reason}</name> + <name since="OTP 21.2">HModule:changing_config(SetOrUpdate, OldConfig, NewConfig) -> {ok, Config} | {error, Reason}</name> <fsummary>The configuration for this handler is about to change.</fsummary> <type> <v>SetOrUpdate = set | update</v> @@ -1126,7 +1183,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name>HModule:filter_config(Config) -> FilteredConfig</name> + <name since="OTP 21.2">HModule:filter_config(Config) -> FilteredConfig</name> <fsummary>Remove internal data from configuration.</fsummary> <type> <v>Config = FilteredConfig = @@ -1146,7 +1203,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name>HModule:log(LogEvent, Config) -> void()</name> + <name since="OTP 21.0">HModule:log(LogEvent, Config) -> void()</name> <fsummary>Log the given log event.</fsummary> <type> <v>LogEvent = @@ -1169,7 +1226,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name>HModule:removing_handler(Config) -> ok</name> + <name since="OTP 21.0">HModule:removing_handler(Config) -> ok</name> <fsummary>The given handler is about to be removed.</fsummary> <type> <v>Config = @@ -1197,7 +1254,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). <funcs> <func> - <name>FModule:check_config(FConfig) -> ok | {error, Reason}</name> + <name since="OTP 21.0">FModule:check_config(FConfig) -> ok | {error, Reason}</name> <fsummary>Validate the given formatter configuration.</fsummary> <type> <v>FConfig = @@ -1228,7 +1285,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </desc> </func> <func> - <name>FModule:format(LogEvent, FConfig) -> FormattedLogEntry</name> + <name since="OTP 21.0">FModule:format(LogEvent, FConfig) -> FormattedLogEntry</name> <fsummary>Format the given log event.</fsummary> <type> <v>LogEvent = diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml index 458e61cef5..5ed7397135 100644 --- a/lib/kernel/doc/src/logger_chapter.xml +++ b/lib/kernel/doc/src/logger_chapter.xml @@ -693,8 +693,10 @@ logger:debug(#{got => connection_request, id => Id, state => State}, with <seealso marker="#logger_sasl_compatible"> <c>logger_sasl_compatible</c></seealso>.</p> <p>With this parameter, you can modify or disable the default - handler, add custom handlers and primary logger filters, and - set log levels per module.</p> + handler, add custom handlers and primary logger filters, set + log levels per module, and modify + the <seealso marker="#proxy">proxy</seealso> + configuration.</p> <p><c>Config</c> is any (zero or more) of the following:</p> <taglist> <tag><c>{handler, default, undefined}</c></tag> @@ -746,6 +748,14 @@ logger:debug(#{got => connection_request, id => Id, state => State}, <p>for each <c>Module</c>.</p> <p>Multiple entries of this type are allowed.</p> </item> + <tag><c>{proxy, ProxyConfig}</c></tag> + <item> + <p>Sets the proxy configuration, equivalent to calling</p> + <pre><seealso marker="logger#set_proxy_config/1"> + logger:set_proxy_config(ProxyConfig) + </seealso></pre> + <p>Only one entry of this type is allowed.</p> + </item> </taglist> <p>See section <seealso marker="#config_examples">Configuration @@ -1334,9 +1344,50 @@ logger:add_handler(my_disk_log_h, logger_disk_log_h, </section> <section> + <marker id="proxy"/> + <title>Logger Proxy</title> + <p>The Logger proxy is an Erlang process which is part of the + Kernel application's supervision tree. During startup, the proxy + process registers itself as the <c>system_logger</c>, meaning + that log events produced by the emulator are sent to this + process.</p> + <p>When a log event is issued on a process which has its group + leader on a remote node, Logger automatically forwards the log + event to the group leader's node. To achieve this, it first + sends the log event as an Erlang message from the original + client process to the proxy on the local node, and the proxy in + turn forwards the event to the proxy on the remote node.</p> + <p>When receiving a log event, either from the emulator or from a + remote node, the proxy calls the Logger API to log the event.</p> + <p>The proxy process is overload protected in the same way as + described in + section <seealso marker="#overload_protection">Protecting the + Handler from Overload</seealso>, but with the following default + values:</p> + <code> + #{sync_mode_qlen => 500, + drop_mode_qlen => 1000, + flush_qlen => 5000, + burst_limit_enable => false, + overload_kill_enable => false}</code> + <p>For log events from the emulator, synchronous message passing + mode is not applicable, since all messages are passed + asynchronously by the emulator. Drop mode is achieved by setting + the <c>system_logger</c> to <c>undefined</c>, forcing the + emulator to drop events until it is set back to the proxy pid + again.</p> + <p>The proxy uses <seealso marker="erts:erlang#send_nosuspend/2"> + <c>erlang:send_nosuspend/2</c></seealso> when sending log + events to a remote node. If the message could not be sent + without suspending the sender, it is dropped. This is to avoid + blocking the proxy process.</p> + </section> + + <section> <title>See Also</title> <p> <seealso marker="disk_log"><c>disk_log(3)</c></seealso>, + <seealso marker="erts:erlang"><c>erlang(3)</c></seealso>, <seealso marker="error_logger"><c>error_logger(3)</c></seealso>, <seealso marker="logger"><c>logger(3)</c></seealso>, <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c></seealso>, diff --git a/lib/kernel/doc/src/logger_disk_log_h.xml b/lib/kernel/doc/src/logger_disk_log_h.xml index d9b941a0a9..5b2374690e 100644 --- a/lib/kernel/doc/src/logger_disk_log_h.xml +++ b/lib/kernel/doc/src/logger_disk_log_h.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger_disk_log_h.xml</file> </header> - <module>logger_disk_log_h</module> + <module since="OTP 21.0">logger_disk_log_h</module> <modulesummary>A disk_log based handler for Logger</modulesummary> <description> @@ -148,7 +148,7 @@ erl -kernel logger '[{handler,default,logger_disk_log_h, <funcs> <func> - <name name="filesync" arity="1" clause_i="1"/> + <name name="filesync" arity="1" clause_i="1" since="OTP 21.0"/> <fsummary>Writes buffered data to disk.</fsummary> <desc> <p>Write buffered data to disk.</p> diff --git a/lib/kernel/doc/src/logger_filters.xml b/lib/kernel/doc/src/logger_filters.xml index 90f1fcc270..0a02342864 100644 --- a/lib/kernel/doc/src/logger_filters.xml +++ b/lib/kernel/doc/src/logger_filters.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger_filters.xml</file> </header> - <module>logger_filters</module> + <module since="OTP 21.0">logger_filters</module> <modulesummary>Filters to use with Logger.</modulesummary> <description> @@ -51,7 +51,7 @@ <funcs> <func> - <name name="domain" arity="2"/> + <name name="domain" arity="2" since="OTP 21.0"/> <fsummary>Filter log events based on the domain field in metadata.</fsummary> <desc> @@ -152,7 +152,7 @@ ok</code> </func> <func> - <name name="level" arity="2"/> + <name name="level" arity="2" since="OTP 21.0"/> <fsummary>Filter log events based on the log level.</fsummary> <desc> <p>This filter provides a way of filtering log events based @@ -212,7 +212,7 @@ ok</code> </func> <func> - <name name="progress" arity="2"/> + <name name="progress" arity="2" since="OTP 21.0"/> <fsummary>Filter progress reports from supervisor and application_controller.</fsummary> <desc> <p>This filter matches all progress reports @@ -227,7 +227,7 @@ ok</code> </func> <func> - <name name="remote_gl" arity="2"/> + <name name="remote_gl" arity="2" since="OTP 21.0"/> <fsummary>Filter events with group leader on remote node.</fsummary> <desc> <p>This filter matches all events originating from a process diff --git a/lib/kernel/doc/src/logger_formatter.xml b/lib/kernel/doc/src/logger_formatter.xml index d066e263df..6dc83d24e1 100644 --- a/lib/kernel/doc/src/logger_formatter.xml +++ b/lib/kernel/doc/src/logger_formatter.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger_formatter.xml</file> </header> - <module>logger_formatter</module> + <module since="OTP 21.0">logger_formatter</module> <modulesummary>Default formatter for Logger.</modulesummary> <description> @@ -289,7 +289,7 @@ exit_reason: "It crashed"</code> <funcs> <func> - <name name="check_config" arity="1"/> + <name name="check_config" arity="1" since="OTP 21.0"/> <fsummary>Validates the given formatter configuration.</fsummary> <desc> <p>The function is called by Logger when the formatter @@ -310,7 +310,7 @@ exit_reason: "It crashed"</code> </desc> </func> <func> - <name name="format" arity="2"/> + <name name="format" arity="2" since="OTP 21.0"/> <fsummary>Formats the given message.</fsummary> <desc> <p>This the formatter callback function to be called from diff --git a/lib/kernel/doc/src/logger_std_h.xml b/lib/kernel/doc/src/logger_std_h.xml index e156f5719b..fcd180abd6 100644 --- a/lib/kernel/doc/src/logger_std_h.xml +++ b/lib/kernel/doc/src/logger_std_h.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger_std_h.xml</file> </header> - <module>logger_std_h</module> + <module since="OTP 21.0">logger_std_h</module> <modulesummary>Standard handler for Logger.</modulesummary> <description> @@ -121,7 +121,7 @@ erl -kernel logger '[{handler,default,logger_std_h, <funcs> <func> - <name name="filesync" arity="1" clause_i="1"/> + <name name="filesync" arity="1" clause_i="1" since="OTP 21.0"/> <fsummary>Writes buffered data to disk.</fsummary> <desc> <p>Write buffered data to disk.</p> diff --git a/lib/kernel/doc/src/net_adm.xml b/lib/kernel/doc/src/net_adm.xml index 6957a3b5e4..c3e1619f1b 100644 --- a/lib/kernel/doc/src/net_adm.xml +++ b/lib/kernel/doc/src/net_adm.xml @@ -28,7 +28,7 @@ <date>1996-09-10</date> <rev>A</rev> </header> - <module>net_adm</module> + <module since="">net_adm</module> <modulesummary>Various Erlang net administration routines.</modulesummary> <description> <p>This module contains various network utility functions.</p> @@ -36,7 +36,7 @@ <funcs> <func> - <name name="dns_hostname" arity="1"/> + <name name="dns_hostname" arity="1" since=""/> <fsummary>Official name of a host.</fsummary> <desc> <p>Returns the official name of <c><anno>Host</anno></c>, or @@ -46,7 +46,7 @@ </func> <func> - <name name="host_file" arity="0"/> + <name name="host_file" arity="0" since=""/> <fsummary>Read file <c>.hosts.erlang</c>.</fsummary> <desc> <p>Reads file <c>.hosts.erlang</c>, see section @@ -58,7 +58,7 @@ </func> <func> - <name name="localhost" arity="0"/> + <name name="localhost" arity="0" since=""/> <fsummary>Name of the local host.</fsummary> <desc> <p>Returns the name of the local host. If Erlang was started @@ -68,8 +68,8 @@ </func> <func> - <name name="names" arity="0"/> - <name name="names" arity="1"/> + <name name="names" arity="0" since=""/> + <name name="names" arity="1" since=""/> <fsummary>Names of Erlang nodes at a host.</fsummary> <desc> <p>Similar to <c>epmd -names</c>, see @@ -86,7 +86,7 @@ </func> <func> - <name name="ping" arity="1"/> + <name name="ping" arity="1" since=""/> <fsummary>Set up a connection to a node.</fsummary> <desc> <p>Sets up a connection to <c><anno>Node</anno></c>. Returns @@ -95,8 +95,8 @@ </func> <func> - <name name="world" arity="0"/> - <name name="world" arity="1"/> + <name name="world" arity="0" since=""/> + <name name="world" arity="1" since=""/> <fsummary>Lookup and connect to all nodes at all hosts in <c>.hosts.erlang</c>.</fsummary> <type name="verbosity"/> @@ -117,8 +117,8 @@ </func> <func> - <name name="world_list" arity="1"/> - <name name="world_list" arity="2"/> + <name name="world_list" arity="1" since=""/> + <name name="world_list" arity="2" since=""/> <fsummary>Lookup and connect to all nodes at specified hosts.</fsummary> <type name="verbosity"/> <desc> diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml index bfbe7a6470..419d3cad84 100644 --- a/lib/kernel/doc/src/net_kernel.xml +++ b/lib/kernel/doc/src/net_kernel.xml @@ -28,7 +28,7 @@ <date>1996-09-10</date> <rev>A</rev> </header> - <module>net_kernel</module> + <module since="">net_kernel</module> <modulesummary>Erlang networking kernel.</modulesummary> <description> <p>The net kernel is a system process, registered as @@ -81,7 +81,7 @@ $ <input>erl -sname foobar</input></pre> <funcs> <func> - <name name="allow" arity="1"/> + <name name="allow" arity="1" since=""/> <fsummary>Permit access to a specified set of nodes</fsummary> <desc> <p>Permits access to the specified set of nodes.</p> @@ -98,7 +98,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="connect_node" arity="1"/> + <name name="connect_node" arity="1" since=""/> <fsummary>Establish a connection to a node.</fsummary> <desc> <p>Establishes a connection to <c><anno>Node</anno></c>. Returns @@ -110,7 +110,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="get_net_ticktime" arity="0"/> + <name name="get_net_ticktime" arity="0" since=""/> <fsummary>Get <c>net_ticktime</c>.</fsummary> <desc> <p>Gets <c>net_ticktime</c> (see @@ -131,7 +131,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="getopts" arity="2"/> + <name name="getopts" arity="2" since="OTP 19.1"/> <fsummary>Get distribution socket options.</fsummary> <desc> <p>Get one or more options for the distribution socket @@ -146,8 +146,8 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="monitor_nodes" arity="1"/> - <name name="monitor_nodes" arity="2"/> + <name name="monitor_nodes" arity="1" since=""/> + <name name="monitor_nodes" arity="2" since=""/> <fsummary>Subscribe to node status change messages.</fsummary> <desc> <p>The calling process subscribes or unsubscribes to node @@ -267,8 +267,8 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="set_net_ticktime" arity="1"/> - <name name="set_net_ticktime" arity="2"/> + <name name="set_net_ticktime" arity="1" since=""/> + <name name="set_net_ticktime" arity="2" since=""/> <fsummary>Set <c>net_ticktime</c>.</fsummary> <desc> <p>Sets <c>net_ticktime</c> (see @@ -324,7 +324,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="setopts" arity="2"/> + <name name="setopts" arity="2" since="OTP 19.1"/> <fsummary>Set distribution socket options.</fsummary> <desc> <p>Set one or more options for distribution sockets. @@ -345,9 +345,9 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name>start([Name]) -> {ok, pid()} | {error, Reason}</name> - <name>start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name> - <name>start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name> + <name since="">start([Name]) -> {ok, pid()} | {error, Reason}</name> + <name since="">start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name> + <name since="">start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name> <fsummary>Turn an Erlang runtime system into a distributed node.</fsummary> <type> <v>Name = atom()</v> @@ -364,7 +364,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="stop" arity="0"/> + <name name="stop" arity="0" since=""/> <fsummary>Turn a node into a non-distributed Erlang runtime system.</fsummary> <desc> <p>Turns a distributed node into a non-distributed node. For diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml index c95e615c6b..0500e4cfb3 100644 --- a/lib/kernel/doc/src/os.xml +++ b/lib/kernel/doc/src/os.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>os</module> + <module since="">os</module> <modulesummary>Operating system-specific functions.</modulesummary> <description> <p>The functions in this module are operating system-specific. @@ -134,8 +134,8 @@ <funcs> <func> - <name name="cmd" arity="1"/> - <name name="cmd" arity="2"/> + <name name="cmd" arity="1" since=""/> + <name name="cmd" arity="2" since="OTP 20.2.3"/> <fsummary>Execute a command in a shell of the target OS.</fsummary> <desc> <p>Executes <c><anno>Command</anno></c> in a command shell of the @@ -173,8 +173,8 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="find_executable" arity="1"/> - <name name="find_executable" arity="2"/> + <name name="find_executable" arity="1" since=""/> + <name name="find_executable" arity="2" since=""/> <fsummary>Absolute filename of a program.</fsummary> <desc> <p>These two functions look up an executable program, with the @@ -190,7 +190,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="getenv" arity="0"/> + <name name="getenv" arity="0" since=""/> <fsummary>List all environment variables.</fsummary> <desc> <p>Returns a list of all environment variables. @@ -205,7 +205,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="getenv" arity="1"/> + <name name="getenv" arity="1" since=""/> <fsummary>Get the value of an environment variable.</fsummary> <desc> <p>Returns the <c><anno>Value</anno></c> of the environment variable @@ -220,7 +220,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="getenv" arity="2"/> + <name name="getenv" arity="2" since="OTP 18.0"/> <fsummary>Get the value of an environment variable.</fsummary> <desc> <p>Returns the <c><anno>Value</anno></c> of the environment variable @@ -235,7 +235,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="getpid" arity="0"/> + <name name="getpid" arity="0" since=""/> <fsummary>Return the process identifier of the emulator process.</fsummary> <desc> @@ -251,7 +251,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="putenv" arity="2"/> + <name name="putenv" arity="2" since=""/> <fsummary>Set a new value for an environment variable.</fsummary> <desc> <p>Sets a new <c><anno>Value</anno></c> for environment variable @@ -277,7 +277,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="set_signal" arity="2"/> + <name name="set_signal" arity="2" since="OTP 20.0"/> <fsummary>Enables or disables handling of OS signals.</fsummary> <desc> <p>Enables or disables OS signals.</p> @@ -304,7 +304,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="system_time" arity="0"/> + <name name="system_time" arity="0" since="OTP 18.0"/> <fsummary>Current OS system time.</fsummary> <desc> <p>Returns the current @@ -317,7 +317,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="system_time" arity="1"/> + <name name="system_time" arity="1" since="OTP 18.0"/> <fsummary>Current OS system time.</fsummary> <desc> <p>Returns the current @@ -332,7 +332,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="timestamp" arity="0"/> + <name name="timestamp" arity="0" since=""/> <fsummary>Current OS system time on the <c>erlang:timestamp/0</c> format.</fsummary> <type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc> <desc> @@ -373,7 +373,7 @@ calendar:now_to_universal_time(TS), </func> <func> - <name name="perf_counter" arity="0"/> + <name name="perf_counter" arity="0" since="OTP 19.0"/> <fsummary>Returns a performance counter</fsummary> <desc> <p>Returns the current performance counter value in <c>perf_counter</c> @@ -383,7 +383,7 @@ calendar:now_to_universal_time(TS), </desc> </func> <func> - <name name="perf_counter" arity="1"/> + <name name="perf_counter" arity="1" since="OTP 19.0"/> <fsummary>Returns a performance counter</fsummary> <desc><p>Returns a performance counter that can be used as a very fast and high resolution timestamp. This counter is read directly from the hardware or operating @@ -397,7 +397,7 @@ calendar:now_to_universal_time(TS), </desc> </func> <func> - <name name="type" arity="0"/> + <name name="type" arity="0" since=""/> <fsummary>Return the OS family and, in some cases, the OS name of the current OS.</fsummary> <desc> @@ -417,7 +417,7 @@ calendar:now_to_universal_time(TS), </func> <func> - <name name="unsetenv" arity="1"/> + <name name="unsetenv" arity="1" since="OTP R16B03"/> <fsummary>Delete an environment variable.</fsummary> <desc> <p>Deletes the environment variable <c><anno>VarName</anno></c>.</p> @@ -429,7 +429,7 @@ calendar:now_to_universal_time(TS), </func> <func> - <name name="version" arity="0"/> + <name name="version" arity="0" since=""/> <fsummary>Return the OS versions.</fsummary> <desc> <p>Returns the OS version. diff --git a/lib/kernel/doc/src/pg2.xml b/lib/kernel/doc/src/pg2.xml index 0631b317b4..058d711756 100644 --- a/lib/kernel/doc/src/pg2.xml +++ b/lib/kernel/doc/src/pg2.xml @@ -32,7 +32,7 @@ <rev>A2</rev> <file>pg2.xml</file> </header> - <module>pg2</module> + <module since="">pg2</module> <modulesummary>Distributed named process groups.</modulesummary> <description> <p>This module implements process groups. Each message can be sent @@ -66,7 +66,7 @@ <funcs> <func> - <name name="create" arity="1"/> + <name name="create" arity="1" since=""/> <fsummary>Create a new, empty process group.</fsummary> <desc> <p>Creates a new, empty process group. The group is globally @@ -75,7 +75,7 @@ </func> <func> - <name name="delete" arity="1"/> + <name name="delete" arity="1" since=""/> <fsummary>Delete a process group.</fsummary> <desc> <p>Deletes a process group.</p> @@ -83,7 +83,7 @@ </func> <func> - <name name="get_closest_pid" arity="1"/> + <name name="get_closest_pid" arity="1" since=""/> <fsummary>Common dispatch function.</fsummary> <desc> <p>A useful dispatch function that can be used from @@ -93,7 +93,7 @@ </func> <func> - <name name="get_local_members" arity="1"/> + <name name="get_local_members" arity="1" since=""/> <fsummary>Return all local processes in a group.</fsummary> <desc> <p>Returns all processes running on the local node in the @@ -104,7 +104,7 @@ </func> <func> - <name name="get_members" arity="1"/> + <name name="get_members" arity="1" since=""/> <fsummary>Return all processes in a group.</fsummary> <desc> <p>Returns all processes in the group <c>Name</c>. This @@ -114,7 +114,7 @@ </func> <func> - <name name="join" arity="2"/> + <name name="join" arity="2" since=""/> <fsummary>Join a process to a group.</fsummary> <desc> <p>Joins the process <c>Pid</c> to the group <c>Name</c>. @@ -124,7 +124,7 @@ </func> <func> - <name name="leave" arity="2"/> + <name name="leave" arity="2" since=""/> <fsummary>Make a process leave a group.</fsummary> <desc> <p>Makes the process <c>Pid</c> leave the group <c>Name</c>. @@ -134,8 +134,8 @@ </func> <func> - <name name="start" arity="0"/> - <name name="start_link" arity="0"/> + <name name="start" arity="0" since=""/> + <name name="start_link" arity="0" since=""/> <fsummary>Start the <c>pg2</c> server.</fsummary> <desc> <p>Starts the <c>pg2</c> server. Normally, the server does not need @@ -149,7 +149,7 @@ </func> <func> - <name name="which_groups" arity="0"/> + <name name="which_groups" arity="0" since=""/> <fsummary>Return a list of all known groups.</fsummary> <desc> <p>Returns a list of all known groups.</p> diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml index fab616e630..c55454506e 100644 --- a/lib/kernel/doc/src/rpc.xml +++ b/lib/kernel/doc/src/rpc.xml @@ -28,7 +28,7 @@ <date>1996-09-10</date> <rev>A</rev> </header> - <module>rpc</module> + <module since="">rpc</module> <modulesummary>Remote Procedure Call services.</modulesummary> <description> <p>This module contains services similar to Remote @@ -51,7 +51,7 @@ <funcs> <func> - <name name="abcast" arity="2"/> + <name name="abcast" arity="2" since=""/> <fsummary>Broadcast a message asynchronously to a registered process on all nodes.</fsummary> <desc> @@ -61,7 +61,7 @@ </func> <func> - <name name="abcast" arity="3"/> + <name name="abcast" arity="3" since=""/> <fsummary>Broadcast a message asynchronously to a registered process on specific nodes.</fsummary> <desc> @@ -72,7 +72,7 @@ </func> <func> - <name name="async_call" arity="4"/> + <name name="async_call" arity="4" since=""/> <fsummary>Evaluate a function call on a node, asynchronous version.</fsummary> <desc> @@ -98,7 +98,7 @@ </func> <func> - <name name="block_call" arity="4"/> + <name name="block_call" arity="4" since=""/> <fsummary>Evaluate a function call on a node in the RPC server's context.</fsummary> <desc> @@ -115,7 +115,7 @@ </func> <func> - <name name="block_call" arity="5"/> + <name name="block_call" arity="5" since=""/> <fsummary>Evaluate a function call on a node in the RPC server's context.</fsummary> <desc> @@ -127,7 +127,7 @@ </func> <func> - <name name="call" arity="4"/> + <name name="call" arity="4" since=""/> <fsummary>Evaluate a function call on a node.</fsummary> <desc> <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, @@ -138,7 +138,7 @@ </func> <func> - <name name="call" arity="5"/> + <name name="call" arity="5" since=""/> <fsummary>Evaluate a function call on a node.</fsummary> <desc> <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, @@ -158,7 +158,7 @@ </func> <func> - <name name="cast" arity="4"/> + <name name="cast" arity="4" since=""/> <fsummary>Run a function on a node ignoring the result.</fsummary> <desc> <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, @@ -171,7 +171,7 @@ </func> <func> - <name name="eval_everywhere" arity="3"/> + <name name="eval_everywhere" arity="3" since=""/> <fsummary>Run a function on all nodes, ignoring the result.</fsummary> <desc> <p>Equivalent to <c>eval_everywhere([node()|nodes()], @@ -181,7 +181,7 @@ </func> <func> - <name name="eval_everywhere" arity="4"/> + <name name="eval_everywhere" arity="4" since=""/> <fsummary>Run a function on specific nodes, ignoring the result.</fsummary> <desc> @@ -192,7 +192,7 @@ </func> <func> - <name name="multi_server_call" arity="2"/> + <name name="multi_server_call" arity="2" since=""/> <fsummary>Interact with the servers on a number of nodes.</fsummary> <desc> <p>Equivalent to <c>multi_server_call([node()|nodes()], @@ -201,7 +201,7 @@ </func> <func> - <name name="multi_server_call" arity="3"/> + <name name="multi_server_call" arity="3" since=""/> <fsummary>Interact with the servers on a number of nodes.</fsummary> <desc> <p>Can be used when interacting with servers called @@ -224,7 +224,7 @@ </func> <func> - <name name="multicall" arity="3"/> + <name name="multicall" arity="3" since=""/> <fsummary>Evaluate a function call on a number of nodes.</fsummary> <desc> <p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>, @@ -233,7 +233,7 @@ </func> <func> - <name name="multicall" arity="4" clause_i="1"/> + <name name="multicall" arity="4" clause_i="1" since=""/> <fsummary>Evaluate a function call on a number of nodes.</fsummary> <desc> <p>Equivalent to <c>multicall(<anno>Nodes</anno>, <anno>Module</anno>, @@ -242,7 +242,7 @@ </func> <func> - <name name="multicall" arity="4" clause_i="2"/> + <name name="multicall" arity="4" clause_i="2" since=""/> <fsummary>Evaluate a function call on a number of nodes.</fsummary> <desc> <p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>, @@ -252,7 +252,7 @@ </func> <func> - <name name="multicall" arity="5"/> + <name name="multicall" arity="5" since=""/> <fsummary>Evaluate a function call on a number of nodes.</fsummary> <desc> <p>In contrast to an RPC, a multicall is an RPC that is sent @@ -288,7 +288,7 @@ </func> <func> - <name name="nb_yield" arity="1"/> + <name name="nb_yield" arity="1" since=""/> <fsummary>Deliver the result of evaluating a function call on a node (non-blocking).</fsummary> <desc> @@ -297,7 +297,7 @@ </func> <func> - <name name="nb_yield" arity="2"/> + <name name="nb_yield" arity="2" since=""/> <fsummary>Deliver the result of evaluating a function call on a node (non-blocking).</fsummary> <desc> @@ -315,7 +315,7 @@ </func> <func> - <name name="parallel_eval" arity="1"/> + <name name="parallel_eval" arity="1" since=""/> <fsummary>Evaluate many function calls on all nodes in parallel.</fsummary> <desc> @@ -328,7 +328,7 @@ </func> <func> - <name name="pinfo" arity="1"/> + <name name="pinfo" arity="1" since=""/> <fsummary>Information about a process.</fsummary> <desc> <p>Location transparent version of the BIF @@ -337,8 +337,8 @@ </func> <func> - <name name="pinfo" arity="2" clause_i="1"/> - <name name="pinfo" arity="2" clause_i="2"/> + <name name="pinfo" arity="2" clause_i="1" since=""/> + <name name="pinfo" arity="2" clause_i="2" since=""/> <fsummary>Information about a process.</fsummary> <desc> <p>Location transparent version of the BIF @@ -347,7 +347,7 @@ </func> <func> - <name name="pmap" arity="3"/> + <name name="pmap" arity="3" since=""/> <fsummary>Parallel evaluation of mapping a function over a list.</fsummary> <desc> @@ -360,7 +360,7 @@ </func> <func> - <name name="sbcast" arity="2"/> + <name name="sbcast" arity="2" since=""/> <fsummary>Broadcast a message synchronously to a registered process on all nodes.</fsummary> <desc> @@ -370,7 +370,7 @@ </func> <func> - <name name="sbcast" arity="3"/> + <name name="sbcast" arity="3" since=""/> <fsummary>Broadcast a message synchronously to a registered process on specific nodes.</fsummary> <desc> @@ -391,7 +391,7 @@ </func> <func> - <name name="server_call" arity="4"/> + <name name="server_call" arity="4" since=""/> <fsummary>Interact with a server on a node.</fsummary> <desc> <p>Can be used when interacting with a server called @@ -410,7 +410,7 @@ </func> <func> - <name name="yield" arity="1"/> + <name name="yield" arity="1" since=""/> <fsummary>Deliver the result of evaluating a function call on a node (blocking).</fsummary> <desc> diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml index 1a4a74419a..aa29223dd0 100644 --- a/lib/kernel/doc/src/seq_trace.xml +++ b/lib/kernel/doc/src/seq_trace.xml @@ -28,7 +28,7 @@ <date>1998-04-16</date> <rev>A</rev> </header> - <module>seq_trace</module> + <module since="">seq_trace</module> <modulesummary>Sequential tracing of messages.</modulesummary> <description> <p>Sequential tracing makes it possible to trace all messages @@ -51,7 +51,7 @@ </datatypes> <funcs> <func> - <name name="set_token" arity="1"/> + <name name="set_token" arity="1" since=""/> <fsummary>Set the trace token</fsummary> <desc> <p>Sets the trace token for the calling process to <c><anno>Token</anno></c>. @@ -71,7 +71,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="set_token" arity="2"/> + <name name="set_token" arity="2" since=""/> <fsummary>Set a component of the trace token</fsummary> <type name="component"/> <type name="flag"/> @@ -158,7 +158,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="get_token" arity="0"/> + <name name="get_token" arity="0" since=""/> <fsummary>Return the value of the trace token</fsummary> <desc> <p>Returns the value of the trace token for the calling process. @@ -169,7 +169,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="get_token" arity="1"/> + <name name="get_token" arity="1" since=""/> <fsummary>Return the value of a trace token component</fsummary> <type name="component"/> <type name="flag"/> @@ -182,7 +182,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="print" arity="1"/> + <name name="print" arity="1" since=""/> <fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary> <desc> <p>Puts the Erlang term <c><anno>TraceInfo</anno></c> into the sequential @@ -192,7 +192,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="print" arity="2"/> + <name name="print" arity="2" since=""/> <fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary> <desc> <p>Same as <c>print/1</c> with the additional condition that @@ -201,7 +201,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="reset_trace" arity="0"/> + <name name="reset_trace" arity="0" since=""/> <fsummary>Stop all sequential tracing on the local node</fsummary> <desc> <p>Sets the trace token to empty for all processes on the @@ -213,7 +213,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="set_system_tracer" arity="1"/> + <name name="set_system_tracer" arity="1" since=""/> <fsummary>Set the system tracer</fsummary> <type name="tracer"/> <desc> @@ -227,7 +227,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="get_system_tracer" arity="0"/> + <name name="get_system_tracer" arity="0" since=""/> <fsummary>Return the pid() or port() of the current system tracer.</fsummary> <type name="tracer"/> <desc> diff --git a/lib/kernel/doc/src/wrap_log_reader.xml b/lib/kernel/doc/src/wrap_log_reader.xml index 7fb9c1c023..5f37e7ec5f 100644 --- a/lib/kernel/doc/src/wrap_log_reader.xml +++ b/lib/kernel/doc/src/wrap_log_reader.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>wrap_log_reader.sgml</file> </header> - <module>wrap_log_reader</module> + <module since="">wrap_log_reader</module> <modulesummary>A service to read internally formatted wrap disk logs. </modulesummary> <description> @@ -65,8 +65,8 @@ <funcs> <func> - <name name="chunk" arity="1"/> - <name name="chunk" arity="2"/> + <name name="chunk" arity="1" since=""/> + <name name="chunk" arity="2" since=""/> <fsummary>Read a chunk of objects written to a wrap log.</fsummary> <type name="chunk_ret"/> <desc> @@ -105,7 +105,7 @@ </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a log.</fsummary> <desc> <p>Closes a log file properly.</p> @@ -113,8 +113,8 @@ </func> <func> - <name name="open" arity="1"/> - <name name="open" arity="2"/> + <name name="open" arity="1" since=""/> + <name name="open" arity="2" since=""/> <fsummary>Open a log file.</fsummary> <type name="open_ret"/> <desc> diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile index 57f17defc8..3d1506ea08 100644 --- a/lib/kernel/src/Makefile +++ b/lib/kernel/src/Makefile @@ -118,6 +118,8 @@ MODULES = \ logger_h_common \ logger_filters \ logger_formatter \ + logger_olp \ + logger_proxy \ logger_server \ logger_simple_h \ logger_sup \ @@ -151,7 +153,7 @@ INTERNAL_HRL_FILES= application_master.hrl disk_log.hrl \ inet_dns.hrl inet_res.hrl \ inet_boot.hrl inet_config.hrl inet_int.hrl \ inet_dns_record_adts.hrl \ - logger_internal.hrl logger_h_common.hrl + logger_internal.hrl logger_olp.hrl logger_h_common.hrl ERL_FILES= $(MODULES:%=%.erl) @@ -279,6 +281,8 @@ $(EBIN)/logger_config.beam: logger_internal.hrl ../include/logger.hrl $(EBIN)/logger_disk_log_h.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl ../include/file.hrl $(EBIN)/logger_filters.beam: logger_internal.hrl ../include/logger.hrl $(EBIN)/logger_formatter.beam: logger_internal.hrl ../include/logger.hrl +$(EBIN)/logger_olp.beam: logger_olp.hrl logger_internal.hrl +$(EBIN)/logger_proxy.beam: logger_internal.hrl $(EBIN)/logger_server.beam: logger_internal.hrl ../include/logger.hrl $(EBIN)/logger_simple_h.beam: logger_internal.hrl ../include/logger.hrl $(EBIN)/logger_std_h.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl ../include/file.hrl diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl index b7e8868911..7a14e2635c 100644 --- a/lib/kernel/src/erl_epmd.erl +++ b/lib/kernel/src/erl_epmd.erl @@ -77,8 +77,8 @@ stop() -> %% -spec port_please(Name, Host) -> {ok, Port, Version} | noport when - Name :: string(), - Host :: inet:ip_address(), + Name :: atom() | string(), + Host :: atom() | string() | inet:ip_address(), Port :: non_neg_integer(), Version :: non_neg_integer(). @@ -86,8 +86,8 @@ port_please(Node, Host) -> port_please(Node, Host, infinity). -spec port_please(Name, Host, Timeout) -> {ok, Port, Version} | noport when - Name :: string(), - Host :: inet:ip_address(), + Name :: atom() | string(), + Host :: atom() | string() | inet:ip_address(), Timeout :: non_neg_integer() | infinity, Port :: non_neg_integer(), Version :: non_neg_integer(). diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src index fe073621c8..a1d9e8e215 100644 --- a/lib/kernel/src/kernel.app.src +++ b/lib/kernel/src/kernel.app.src @@ -68,6 +68,8 @@ logger_formatter, logger_h_common, logger_handler_watcher, + logger_olp, + logger_proxy, logger_server, logger_simple_h, logger_std_h, diff --git a/lib/kernel/src/logger.erl b/lib/kernel/src/logger.erl index 6762998d4f..abdd9a9ceb 100644 --- a/lib/kernel/src/logger.erl +++ b/lib/kernel/src/logger.erl @@ -43,11 +43,14 @@ get_module_level/0, get_module_level/1, set_primary_config/1, set_primary_config/2, set_handler_config/2, set_handler_config/3, + set_proxy_config/1, update_primary_config/1, update_handler_config/2, update_handler_config/3, + update_proxy_config/1, update_formatter_config/2, update_formatter_config/3, get_primary_config/0, get_handler_config/1, get_handler_config/0, get_handler_ids/0, get_config/0, + get_proxy_config/0, add_handlers/1]). %% Private configuration @@ -122,6 +125,18 @@ {filters,log | stop,[{filter_id(),filter()}]} | {module_level,level(),[module()]}]. +-type olp_config() :: #{sync_mode_qlen => non_neg_integer(), + drop_mode_qlen => pos_integer(), + flush_qlen => pos_integer(), + burst_limit_enable => boolean(), + burst_limit_max_count => pos_integer(), + burst_limit_window_time => pos_integer(), + overload_kill_enable => boolean(), + overload_kill_qlen => pos_integer(), + overload_kill_mem_size => pos_integer(), + overload_kill_restart_after => + non_neg_integer() | infinity}. + -export_type([log_event/0, level/0, report/0, @@ -137,7 +152,8 @@ filter_arg/0, filter_return/0, config_handler/0, - formatter_config/0]). + formatter_config/0, + olp_config/0]). %%%----------------------------------------------------------------- %%% API @@ -390,6 +406,7 @@ set_primary_config(Key,Value) -> set_primary_config(Config) -> logger_server:set_config(primary,Config). + -spec set_handler_config(HandlerId,level,Level) -> Return when HandlerId :: handler_id(), Level :: level() | all | none, @@ -419,6 +436,11 @@ set_handler_config(HandlerId,Key,Value) -> set_handler_config(HandlerId,Config) -> logger_server:set_config(HandlerId,Config). +-spec set_proxy_config(Config) -> ok | {error,term()} when + Config :: olp_config(). +set_proxy_config(Config) -> + logger_server:set_config(proxy,Config). + -spec update_primary_config(Config) -> ok | {error,term()} when Config :: primary_config(). update_primary_config(Config) -> @@ -453,6 +475,11 @@ update_handler_config(HandlerId,Key,Value) -> update_handler_config(HandlerId,Config) -> logger_server:update_config(HandlerId,Config). +-spec update_proxy_config(Config) -> ok | {error,term()} when + Config :: olp_config(). +update_proxy_config(Config) -> + logger_server:update_config(proxy,Config). + -spec get_primary_config() -> Config when Config :: primary_config(). get_primary_config() -> @@ -486,6 +513,12 @@ get_handler_ids() -> {ok,#{handlers:=HandlerIds}} = logger_config:get(?LOGGER_TABLE,primary), HandlerIds. +-spec get_proxy_config() -> Config when + Config :: olp_config(). +get_proxy_config() -> + {ok,Config} = logger_config:get(?LOGGER_TABLE,proxy), + Config. + -spec update_formatter_config(HandlerId,FormatterConfig) -> ok | {error,term()} when HandlerId :: handler_id(), @@ -606,10 +639,12 @@ unset_process_metadata() -> -spec get_config() -> #{primary=>primary_config(), handlers=>[handler_config()], + proxy=>olp_config(), module_levels=>[{module(),level() | all | none}]}. get_config() -> #{primary=>get_primary_config(), handlers=>get_handler_config(), + proxy=>get_proxy_config(), module_levels=>lists:keysort(1,get_module_level())}. -spec internal_init_logger() -> ok | {error,term()}. @@ -672,6 +707,17 @@ init_kernel_handlers(Env) -> %% This function is responsible for resolving the handler config %% and then starting the correct handlers. This is done after the %% kernel supervisor tree has been started as it needs the logger_sup. +add_handlers(kernel) -> + Env = get_logger_env(kernel), + case get_proxy_opts(Env) of + undefined -> + add_handlers(kernel,Env); + Opts -> + case set_proxy_config(Opts) of + ok -> add_handlers(kernel,Env); + {error, Reason} -> {error,{bad_proxy_config,Reason}} + end + end; add_handlers(App) when is_atom(App) -> add_handlers(App,get_logger_env(App)); add_handlers(HandlerConfig) -> @@ -729,6 +775,8 @@ check_logger_config(kernel,[{filters,_,_}|Env]) -> check_logger_config(kernel,Env); check_logger_config(kernel,[{module_level,_,_}|Env]) -> check_logger_config(kernel,Env); +check_logger_config(kernel,[{proxy,_}|Env]) -> + check_logger_config(kernel,Env); check_logger_config(_,Bad) -> throw(Bad). @@ -784,6 +832,13 @@ get_primary_filters(Env) -> _ -> throw({multiple_filters,Env}) end. +get_proxy_opts(Env) -> + case [P || P={proxy,_} <- Env] of + [{proxy,Opts}] -> Opts; + [] -> undefined; + _ -> throw({multiple_proxies,Env}) + end. + %% This function looks at the kernel logger environment %% and updates it so that the correct logger is configured init_default_config(Type,Env) when Type==standard_io; @@ -880,30 +935,30 @@ log_allowed(Location,Level,Msg,Meta0) when is_map(Meta0) -> maps:merge(Location,maps:merge(proc_meta(),Meta0))), case node(maps:get(gl,Meta)) of Node when Node=/=node() -> - log_remote(Node,Level,Msg,Meta), - do_log_allowed(Level,Msg,Meta); + log_remote(Node,Level,Msg,Meta); _ -> - do_log_allowed(Level,Msg,Meta) - end. + ok + end, + do_log_allowed(Level,Msg,Meta,tid()). -do_log_allowed(Level,{Format,Args}=Msg,Meta) +do_log_allowed(Level,{Format,Args}=Msg,Meta,Tid) when ?IS_LEVEL(Level), is_list(Format), is_list(Args), is_map(Meta) -> - logger_backend:log_allowed(#{level=>Level,msg=>Msg,meta=>Meta},tid()); -do_log_allowed(Level,Report,Meta) + logger_backend:log_allowed(#{level=>Level,msg=>Msg,meta=>Meta},Tid); +do_log_allowed(Level,Report,Meta,Tid) when ?IS_LEVEL(Level), ?IS_REPORT(Report), is_map(Meta) -> logger_backend:log_allowed(#{level=>Level,msg=>{report,Report},meta=>Meta}, - tid()); -do_log_allowed(Level,String,Meta) + Tid); +do_log_allowed(Level,String,Meta,Tid) when ?IS_LEVEL(Level), ?IS_STRING(String), is_map(Meta) -> logger_backend:log_allowed(#{level=>Level,msg=>{string,String},meta=>Meta}, - tid()). + Tid). tid() -> ets:whereis(?LOGGER_TABLE). @@ -913,7 +968,7 @@ log_remote(Node,Level,Msg,Meta) -> log_remote(Node,{log,Level,Msg,Meta}). log_remote(Node,Request) -> - {logger,Node} ! Request, + logger_proxy:log({remote,Node,Request}), ok. add_default_metadata(Meta) -> diff --git a/lib/kernel/src/logger_config.erl b/lib/kernel/src/logger_config.erl index 5e9faf332c..5024d20cfe 100644 --- a/lib/kernel/src/logger_config.erl +++ b/lib/kernel/src/logger_config.erl @@ -66,6 +66,8 @@ get(Tid,What) -> case ets:lookup(Tid,table_key(What)) of [{_,_,Config}] -> {ok,Config}; + [{_,Config}] when What=:=proxy -> + {ok,Config}; [] -> {error,{not_found,What}} end. @@ -79,10 +81,15 @@ get(Tid,What,Level) -> [Data] -> {ok,Data} end. +create(Tid,proxy,Config) -> + ets:insert(Tid,{table_key(proxy),Config}); create(Tid,What,Config) -> LevelInt = level_to_int(maps:get(level,Config)), ets:insert(Tid,{table_key(What),LevelInt,Config}). +set(Tid,proxy,Config) -> + ets:insert(Tid,{table_key(proxy),Config}), + ok; set(Tid,What,Config) -> LevelInt = level_to_int(maps:get(level,Config)), %% Should do this only if the level has actually changed. Possibly @@ -148,5 +155,6 @@ int_to_level(?LOG_ALL) -> all. %%%----------------------------------------------------------------- %%% Internal +table_key(proxy) -> ?PROXY_KEY; table_key(primary) -> ?PRIMARY_KEY; table_key(HandlerId) -> {?HANDLER_KEY,HandlerId}. diff --git a/lib/kernel/src/logger_disk_log_h.erl b/lib/kernel/src/logger_disk_log_h.erl index 41e0d51a9d..47b39da900 100644 --- a/lib/kernel/src/logger_disk_log_h.erl +++ b/lib/kernel/src/logger_disk_log_h.erl @@ -24,7 +24,7 @@ -include("logger_h_common.hrl"). %%% API --export([info/1, filesync/1, reset/1]). +-export([filesync/1]). %% logger_h_common callbacks -export([init/2, check_config/4, reset_state/2, @@ -47,25 +47,6 @@ filesync(Name) -> logger_h_common:filesync(?MODULE,Name). -%%%----------------------------------------------------------------- -%%% --spec info(Name) -> Info | {error,Reason} when - Name :: atom(), - Info :: term(), - Reason :: handler_busy | {badarg,term()}. - -info(Name) -> - logger_h_common:info(?MODULE,Name). - -%%%----------------------------------------------------------------- -%%% --spec reset(Name) -> ok | {error,Reason} when - Name :: atom(), - Reason :: handler_busy | {badarg,term()}. - -reset(Name) -> - logger_h_common:reset(?MODULE,Name). - %%%=================================================================== %%% logger callbacks %%%=================================================================== diff --git a/lib/kernel/src/logger_h_common.erl b/lib/kernel/src/logger_h_common.erl index 74a2d158fc..e69f6de38d 100644 --- a/lib/kernel/src/logger_h_common.erl +++ b/lib/kernel/src/logger_h_common.erl @@ -24,11 +24,11 @@ -include("logger_internal.hrl"). %% API --export([start_link/1, info/2, filesync/2, reset/2]). +-export([filesync/2]). -%% gen_server and proc_lib callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). +%% logger_olp callbacks +-export([init/1, handle_load/2, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3, notify/2, reset_state/1]). %% logger callbacks -export([log/2, adding_handler/1, removing_handler/1, changing_config/3, @@ -37,52 +37,45 @@ %% Library functions for handlers -export([error_notify/1]). -%%%----------------------------------------------------------------- --define(CONFIG_KEYS,[sync_mode_qlen, - drop_mode_qlen, - flush_qlen, - burst_limit_enable, - burst_limit_max_count, - burst_limit_window_time, - overload_kill_enable, - overload_kill_qlen, - overload_kill_mem_size, - overload_kill_restart_after, - filesync_repeat_interval]). --define(READ_ONLY_KEYS,[handler_pid,mode_tab]). +-define(OLP_KEYS,[sync_mode_qlen, + drop_mode_qlen, + flush_qlen, + burst_limit_enable, + burst_limit_max_count, + burst_limit_window_time, + overload_kill_enable, + overload_kill_qlen, + overload_kill_mem_size, + overload_kill_restart_after]). + +-define(COMMON_KEYS,[filesync_repeat_interval]). + +-define(READ_ONLY_KEYS,[olp]). %%%----------------------------------------------------------------- %%% API %% This function is called by the logger_sup supervisor -start_link(Args) -> - proc_lib:start_link(?MODULE,init,[Args]). - filesync(Module, Name) -> call(Module, Name, filesync). -info(Module, Name) -> - call(Module, Name, info). - -reset(Module, Name) -> - call(Module, Name, reset). - %%%----------------------------------------------------------------- %%% Handler being added adding_handler(#{id:=Name,module:=Module}=Config) -> HConfig0 = maps:get(config, Config, #{}), - HandlerConfig0 = maps:without(?CONFIG_KEYS,HConfig0), + HandlerConfig0 = maps:without(?OLP_KEYS++?COMMON_KEYS,HConfig0), case Module:check_config(Name,set,undefined,HandlerConfig0) of {ok,HandlerConfig} -> - ModifiedCommon = maps:with(?CONFIG_KEYS,HandlerConfig), - CommonConfig0 = maps:with(?CONFIG_KEYS,HConfig0), + ModifiedCommon = maps:with(?COMMON_KEYS,HandlerConfig), + CommonConfig0 = maps:with(?COMMON_KEYS,HConfig0), CommonConfig = maps:merge( maps:merge(get_default_config(), CommonConfig0), ModifiedCommon), case check_config(CommonConfig) of ok -> HConfig = maps:merge(CommonConfig,HandlerConfig), - start(Config#{config => HConfig}); + OlpOpts = maps:with(?OLP_KEYS,HConfig0), + start(OlpOpts, Config#{config => HConfig}); {error,Faulty} -> {error,{invalid_config,Module,Faulty}} end; @@ -92,11 +85,11 @@ adding_handler(#{id:=Name,module:=Module}=Config) -> %%%----------------------------------------------------------------- %%% Handler being removed -removing_handler(#{id:=Name, module:=Module}) -> +removing_handler(#{id:=Name, module:=Module, config:=#{olp:=Olp}}) -> case whereis(?name_to_reg_name(Module,Name)) of undefined -> ok; - Pid -> + _Pid -> %% We don't want to do supervisor:terminate_child here %% since we need to distinguish this explicit stop from a %% system termination in order to avoid circular attempts @@ -106,7 +99,7 @@ removing_handler(#{id:=Name, module:=Module}) -> %% the restart type is temporary, which means that the %% child specification is automatically removed from the %% supervisor when the process dies. - _ = gen_server:call(Pid, stop), + _ = logger_olp:stop(Olp), ok end. @@ -116,34 +109,52 @@ changing_config(SetOrUpdate, #{id:=Name,config:=OldHConfig,module:=Module}, NewConfig0) -> NewHConfig0 = maps:get(config, NewConfig0, #{}), - OldHandlerConfig = maps:without(?CONFIG_KEYS++?READ_ONLY_KEYS,OldHConfig), - NewHandlerConfig0 = maps:without(?CONFIG_KEYS++?READ_ONLY_KEYS,NewHConfig0), + NoHandlerKeys = ?OLP_KEYS++?COMMON_KEYS++?READ_ONLY_KEYS, + OldHandlerConfig = maps:without(NoHandlerKeys,OldHConfig), + NewHandlerConfig0 = maps:without(NoHandlerKeys,NewHConfig0), case Module:check_config(Name, SetOrUpdate, OldHandlerConfig,NewHandlerConfig0) of {ok, NewHandlerConfig} -> - ModifiedCommon = maps:with(?CONFIG_KEYS,NewHandlerConfig), - NewCommonConfig0 = maps:with(?CONFIG_KEYS,NewHConfig0), + ModifiedCommon = maps:with(?COMMON_KEYS,NewHandlerConfig), + NewCommonConfig0 = maps:with(?COMMON_KEYS,NewHConfig0), + OldCommonConfig = maps:with(?COMMON_KEYS,OldHConfig), CommonDefault = case SetOrUpdate of set -> get_default_config(); update -> - maps:with(?CONFIG_KEYS,OldHConfig) + OldCommonConfig end, NewCommonConfig = maps:merge( maps:merge(CommonDefault,NewCommonConfig0), ModifiedCommon), case check_config(NewCommonConfig) of ok -> - ReadOnly = maps:with(?READ_ONLY_KEYS,OldHConfig), - NewHConfig = maps:merge( - maps:merge(NewCommonConfig,NewHandlerConfig), - ReadOnly), - NewConfig = NewConfig0#{config=>NewHConfig}, - HPid = maps:get(handler_pid,OldHConfig), - case call(HPid, {change_config,NewConfig}) of - ok -> {ok,NewConfig}; - Error -> Error + OlpDefault = + case SetOrUpdate of + set -> + logger_olp:get_default_opts(); + update -> + maps:with(?OLP_KEYS,OldHConfig) + end, + Olp = maps:get(olp,OldHConfig), + NewOlpOpts = maps:merge(OlpDefault, + maps:with(?OLP_KEYS,NewHConfig0)), + case logger_olp:set_opts(Olp,NewOlpOpts) of + ok -> + maybe_set_repeated_filesync(Olp,OldCommonConfig, + NewCommonConfig), + ReadOnly = maps:with(?READ_ONLY_KEYS,OldHConfig), + NewHConfig = + maps:merge( + maps:merge( + maps:merge(NewCommonConfig,NewHandlerConfig), + ReadOnly), + NewOlpOpts), + NewConfig = NewConfig0#{config=>NewHConfig}, + {ok,NewConfig}; + Error -> + Error end; {error,Faulty} -> {error,{invalid_config,Module,Faulty}} @@ -158,14 +169,12 @@ changing_config(SetOrUpdate, LogEvent :: logger:log_event(), Config :: logger:handler_config(). -log(LogEvent, Config = #{id := Name, - config := #{handler_pid := HPid, - mode_tab := ModeTab}}) -> +log(LogEvent, Config = #{config := #{olp:=Olp}}) -> %% if the handler has crashed, we must drop this event %% and hope the handler restarts so we can try again - true = is_process_alive(HPid), + true = is_process_alive(logger_olp:get_pid(Olp)), Bin = log_to_binary(LogEvent, Config), - call_cast_or_drop(Name, HPid, ModeTab, Bin). + logger_olp:load(Olp,Bin). %%%----------------------------------------------------------------- %%% Remove internal fields from configuration @@ -180,18 +189,23 @@ filter_config(#{config:=HConfig}=Config) -> %%% %%% The handler process is linked to logger_sup, which is part of the %%% kernel application's supervision tree. -start(#{id := Name} = Config0) -> +start(OlpOpts0, #{id := Name, module:=Module, config:=HConfig} = Config0) -> + RegName = ?name_to_reg_name(Module,Name), ChildSpec = #{id => Name, - start => {?MODULE, start_link, [Config0]}, + start => {logger_olp, start_link, [RegName,?MODULE, + Config0, OlpOpts0]}, restart => temporary, shutdown => 2000, type => worker, modules => [?MODULE]}, case supervisor:start_child(logger_sup, ChildSpec) of - {ok,Pid,Config} -> + {ok,Pid,Olp} -> ok = logger_handler_watcher:register_handler(Name,Pid), - {ok,Config}; + OlpOpts = logger_olp:get_opts(Olp), + {ok,Config0#{config=>(maps:merge(HConfig,OlpOpts))#{olp=>Olp}}}; + {error,{Reason,Ch}} when is_tuple(Ch), element(1,Ch)==child -> + {error,Reason}; Error -> Error end. @@ -200,103 +214,50 @@ start(#{id := Name} = Config0) -> %%% gen_server callbacks %%%=================================================================== -init(#{id := Name, module := Module, - formatter := Formatter, config := HConfig0} = Config0) -> - RegName = ?name_to_reg_name(Module,Name), - register(RegName, self()), +init(#{id := Name, module := Module, config := HConfig}) -> process_flag(trap_exit, true), - process_flag(message_queue_data, off_heap), ?init_test_hooks(), - ?start_observation(Name), - case Module:init(Name, HConfig0) of + case Module:init(Name, HConfig) of {ok,HState} -> - try ets:new(Name, [public]) of - ModeTab -> - ?set_mode(ModeTab, async), - T0 = ?timestamp(), - HConfig = HConfig0#{handler_pid => self(), - mode_tab => ModeTab}, - Config = Config0#{config => HConfig}, - proc_lib:init_ack({ok,self(),Config}), - %% Storing common config in state to avoid copying - %% (sending) the config data for each log message - CommonConfig = maps:with(?CONFIG_KEYS,HConfig), - State = - ?merge_with_stats( - CommonConfig#{id => Name, - module => Module, - mode_tab => ModeTab, - mode => async, - ctrl_sync_count => - ?CONTROLLER_SYNC_INTERVAL, - last_qlen => 0, - last_log_ts => T0, - last_op => sync, - burst_win_ts => T0, - burst_msg_count => 0, - formatter => Formatter, - handler_state => HState}), - State1 = set_repeated_filesync(State), - unset_restart_flag(State1), - gen_server:enter_loop(?MODULE, [], State1) - catch - _:Error -> - unregister(RegName), - error_notify({init_handler,Name,Error}), - proc_lib:init_ack(Error) - end; + %% Storing common config in state to avoid copying + %% (sending) the config data for each log message + CommonConfig = maps:with(?COMMON_KEYS,HConfig), + State = CommonConfig#{id => Name, + module => Module, + ctrl_sync_count => + ?CONTROLLER_SYNC_INTERVAL, + last_op => sync, + handler_state => HState}, + State1 = set_repeated_filesync(State), + {ok,State1}; Error -> - unregister(RegName), - error_notify({init_handler,Name,Error}), - proc_lib:init_ack(Error) + Error end. -%% This is the synchronous log event. -handle_call({log, Bin}, _From, State) -> - {Result,State1} = do_log(Bin, call, State), - %% Result == ok | dropped - {reply,Result, State1}; +%% This is the log event. +handle_load(Bin, #{id:=Name, + module:=Module, + handler_state:=HandlerState, + ctrl_sync_count := CtrlSync}=State) -> + if CtrlSync==0 -> + {_,HS1} = Module:write(Name, sync, Bin, HandlerState), + State#{handler_state => HS1, + ctrl_sync_count => ?CONTROLLER_SYNC_INTERVAL, + last_op=>write}; + true -> + {_,HS1} = Module:write(Name, async, Bin, HandlerState), + State#{handler_state => HS1, + ctrl_sync_count => CtrlSync-1, + last_op=>write} + end. handle_call(filesync, _From, State = #{id := Name, module := Module, handler_state := HandlerState}) -> {Result,HandlerState1} = Module:filesync(Name,sync,HandlerState), - {reply, Result, State#{handler_state=>HandlerState1, last_op=>sync}}; - -handle_call({change_config, #{formatter:=Formatter, config:=NewHConfig}}, _From, - State = #{filesync_repeat_interval := FSyncInt0}) -> - %% In the future, if handler_state must be updated due to config - %% change, then we need to add a callback to Module here. - CommonConfig = maps:with(?CONFIG_KEYS,NewHConfig), - State1 = maps:merge(State, CommonConfig), - State2 = - case maps:get(filesync_repeat_interval, NewHConfig) of - FSyncInt0 -> - State1; - _FSyncInt1 -> - set_repeated_filesync(cancel_repeated_filesync(State1)) - end, - {reply, ok, State2#{formatter:=Formatter}}; - -handle_call(info, _From, State) -> - {reply, State, State}; - -handle_call(reset, _From, - #{id:=Name,module:=Module,handler_state:=HandlerState}=State) -> - State1 = ?merge_with_stats(State), - {reply, ok, State1#{last_qlen => 0, - last_log_ts => ?timestamp(), - handler_state => Module:reset_state(Name,HandlerState)}}; - -handle_call(stop, _From, State) -> - {stop, {shutdown,stopped}, ok, State}. - -%% This is the asynchronous log event. -handle_cast({log, Bin}, State) -> - {_,State1} = do_log(Bin, cast, State), - {noreply, State1}; + {reply, Result, State#{handler_state=>HandlerState1, last_op=>sync}}. %% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this %% clause gets called repeatedly by the handler. In order to @@ -319,168 +280,83 @@ handle_cast(repeated_filesync, {_,HS} = Module:filesync(Name, async, HandlerState), State#{handler_state => HS, last_op => sync} end, - {noreply,set_repeated_filesync(State1)}. + {noreply,set_repeated_filesync(State1)}; + +handle_cast({set_repeated_filesync,FSyncInt},State) -> + State1 = State#{filesync_repeat_interval=>FSyncInt}, + State2 = set_repeated_filesync(cancel_repeated_filesync(State1)), + {noreply, State2}. handle_info(Info, #{id := Name, module := Module, handler_state := HandlerState} = State) -> {noreply,State#{handler_state => Module:handle_info(Name,Info,HandlerState)}}. -terminate(Reason, State = #{id := Name, - module := Module, - handler_state := HandlerState}) -> +terminate(overloaded=Reason, #{id:=Name}=State) -> + _ = log_handler_info(Name,"Handler ~p overloaded and stopping",[Name],State), + do_terminate(Reason,State), + ConfigResult = logger:get_handler_config(Name), + case ConfigResult of + {ok,#{module:=Module}=HConfig0} -> + spawn(fun() -> logger:remove_handler(Name) end), + HConfig = try Module:filter_config(HConfig0) + catch _:_ -> HConfig0 + end, + {ok,fun() -> logger:add_handler(Name,Module,HConfig) end}; + Error -> + error_notify({Name,restart_impossible,Error}), + Error + end; +terminate(Reason, State) -> + do_terminate(Reason, State). + +do_terminate(Reason, State = #{id := Name, + module := Module, + handler_state := HandlerState}) -> _ = cancel_repeated_filesync(State), _ = Module:terminate(Name, Reason, HandlerState), - ok = stop_or_restart(Name, Reason, State), - unregister(?name_to_reg_name(Module, Name)), ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. +reset_state(#{id:=Name, module:=Module, handler_state:=HandlerState} = State) -> + State#{handler_state=>Module:reset_state(Name, HandlerState)}. %%%----------------------------------------------------------------- %%% Internal functions call(Module, Name, Op) when is_atom(Name) -> - call(?name_to_reg_name(Module,Name), Op); + case logger_olp:call(?name_to_reg_name(Module,Name), Op) of + {error,busy} -> {error,handler_busy}; + Other -> Other + end; call(_, Name, Op) -> {error,{badarg,{Op,[Name]}}}. -call(Server, Msg) -> - try - gen_server:call(Server, Msg, ?DEFAULT_CALL_TIMEOUT) - catch - _:{timeout,_} -> {error,handler_busy} - end. - -%% check for overload between every event (and set Mode to async, -%% sync or drop accordingly), but never flush the whole mailbox -%% before LogWindowSize events have been handled -do_log(Bin, CallOrCast, State = #{id:=Name, mode:=Mode0}) -> - T1 = ?timestamp(), - - %% check if the handler is getting overloaded, or if it's - %% recovering from overload (the check must be done for each - %% event to react quickly to large bursts of events and - %% to ensure that the handler can never end up in drop mode - %% with an empty mailbox, which would stop operation) - {Mode1,QLen,Mem,State1} = check_load(State), - - if (Mode1 == drop) andalso (Mode0 =/= drop) -> - log_handler_info(Name, "Handler ~p switched to drop mode", - [Name], State); - (Mode0 == drop) andalso ((Mode1 == async) orelse (Mode1 == sync)) -> - log_handler_info(Name, "Handler ~p switched to ~w mode", - [Name,Mode1], State); - true -> - ok - end, - - %% kill the handler if it can't keep up with the load - kill_if_choked(Name, QLen, Mem, State), - - if Mode1 == flush -> - flush(Name, QLen, T1, State1); - true -> - write(Name, Mode1, T1, Bin, CallOrCast, State1) - end. - -%% this clause is called by do_log/3 after an overload check -%% has been performed, where QLen > FlushQLen -flush(Name, _QLen0, T1, State=#{last_log_ts := _T0, mode_tab := ModeTab}) -> - %% flush messages in the mailbox (a limited number in - %% order to not cause long delays) - NewFlushed = flush_log_events(?FLUSH_MAX_N), - - %% write info in log about flushed messages +notify({mode_change,Mode0,Mode1},#{id:=Name}=State) -> + log_handler_info(Name,"Handler ~p switched from ~p to ~p mode", + [Name,Mode0,Mode1], State); +notify({flushed,Flushed},#{id:=Name}=State) -> log_handler_info(Name, "Handler ~p flushed ~w log events", - [Name,NewFlushed], State), - - %% because of the receive loop when flushing messages, the - %% handler will be scheduled out often and the mailbox could - %% grow very large, so we'd better check the queue again here - {_,_QLen1} = process_info(self(), message_queue_len), - ?observe(Name,{max_qlen,_QLen1}), - - %% Add 1 for the current log event - ?observe(Name,{flushed,NewFlushed+1}), - - State1 = ?update_max_time(?diff_time(T1,_T0),State), - State2 = ?update_max_qlen(_QLen1,State1), - {dropped,?update_other(flushed,FLUSHED,NewFlushed, - State2#{mode => ?set_mode(ModeTab,async), - last_qlen => 0, - last_log_ts => T1})}. - -%% this clause is called to write to file -write(Name, Mode, T1, Bin, _CallOrCast, - State = #{module := Module, - handler_state := HandlerState, - mode_tab := ModeTab, - ctrl_sync_count := CtrlSync, - last_qlen := LastQLen, - last_log_ts := T0}) -> - %% check if we need to limit the number of writes - %% during a burst of log events - {DoWrite,State1} = limit_burst(State), - - %% only log synhrounously every ?CONTROLLER_SYNC_INTERVAL time, to - %% give the handler time between writes so it can keep up with - %% incoming messages - {Result,LastQLen1,HandlerState1} = - if DoWrite, CtrlSync == 0 -> - ?observe(Name,{_CallOrCast,1}), - {_,HS1} = Module:write(Name, sync, Bin, HandlerState), - {ok,element(2, process_info(self(), message_queue_len)),HS1}; - DoWrite -> - ?observe(Name,{_CallOrCast,1}), - {_,HS1} = Module:write(Name, async, Bin, HandlerState), - {ok,LastQLen,HS1}; - not DoWrite -> - ?observe(Name,{flushed,1}), - {dropped,LastQLen,HandlerState} - end, - - %% Check if the time since the previous log event is long enough - - %% and the queue length small enough - to assume the mailbox has - %% been emptied, and if so, do filesync operation and reset mode to - %% async. Note that this is the best we can do to detect an idle - %% handler without setting a timer after each log call/cast. If the - %% time between two consecutive log events is fast and no new - %% event comes in after the last one, idle state won't be detected! - Time = ?diff_time(T1,T0), - State2 = - if (LastQLen1 < ?FILESYNC_OK_QLEN) andalso - (Time > ?IDLE_DETECT_TIME_USEC) -> - {_,HS2} = Module:filesync(Name,async,HandlerState), - State1#{mode => ?change_mode(ModeTab, Mode, async), - burst_msg_count => 0, - handler_state => HS2}; - true -> - State1#{mode => Mode, handler_state => HandlerState1} - end, - State3 = ?update_calls_or_casts(_CallOrCast,1,State2), - State4 = ?update_max_qlen(LastQLen1,State3), - State5 = - ?update_max_time(Time, - State4#{last_qlen := LastQLen1, - last_log_ts => T1, - last_op => write, - ctrl_sync_count => - if CtrlSync==0 -> ?CONTROLLER_SYNC_INTERVAL; - true -> CtrlSync-1 - end}), - {Result,State5}. + [Name,Flushed], State); +notify(restart,#{id:=Name}=State) -> + log_handler_info(Name, "Handler ~p restarted", [Name], State); +notify(idle,#{id:=Name,module:=Module,handler_state:=HandlerState}=State) -> + {_,HS} = Module:filesync(Name,async,HandlerState), + State#{handler_state=>HS, last_op=>sync}. log_handler_info(Name, Format, Args, #{module:=Module, - formatter:=Formatter, - handler_state:=HandlerState}) -> - Config = #{formatter=>Formatter}, + handler_state:=HandlerState}=State) -> + Config = + case logger:get_handler_config(Name) of + {ok,Conf} -> Conf; + _ -> #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}} + end, Meta = #{time=>erlang:system_time(microsecond)}, Bin = log_to_binary(#{level => notice, msg => {Format,Args}, meta => Meta}, Config), - _ = Module:write(Name, async, Bin, HandlerState), - ok. + {_,HS} = Module:write(Name, async, Bin, HandlerState), + State#{handler_state=>HS, last_op=>write}. %%%----------------------------------------------------------------- %%% Convert log data on any form to binary @@ -540,42 +416,8 @@ string_to_binary(String) -> %%%----------------------------------------------------------------- %%% Check that the configuration term is valid check_config(Config) when is_map(Config) -> - case check_common_config(maps:to_list(Config)) of - ok -> - case overload_levels_ok(Config) of - true -> - ok; - false -> - Faulty = maps:with([sync_mode_qlen, - drop_mode_qlen, - flush_qlen],Config), - {error,{invalid_levels,Faulty}} - end; - Error -> - Error - end. + check_common_config(maps:to_list(Config)). -check_common_config([{sync_mode_qlen,N}|Config]) when is_integer(N) -> - check_common_config(Config); -check_common_config([{drop_mode_qlen,N}|Config]) when is_integer(N) -> - check_common_config(Config); -check_common_config([{flush_qlen,N}|Config]) when is_integer(N) -> - check_common_config(Config); -check_common_config([{burst_limit_enable,Bool}|Config]) when is_boolean(Bool) -> - check_common_config(Config); -check_common_config([{burst_limit_max_count,N}|Config]) when is_integer(N) -> - check_common_config(Config); -check_common_config([{burst_limit_window_time,N}|Config]) when is_integer(N) -> - check_common_config(Config); -check_common_config([{overload_kill_enable,Bool}|Config]) when is_boolean(Bool) -> - check_common_config(Config); -check_common_config([{overload_kill_qlen,N}|Config]) when is_integer(N) -> - check_common_config(Config); -check_common_config([{overload_kill_mem_size,N}|Config]) when is_integer(N) -> - check_common_config(Config); -check_common_config([{overload_kill_restart_after,NorA}|Config]) - when is_integer(NorA); NorA == infinity -> - check_common_config(Config); check_common_config([{filesync_repeat_interval,NorA}|Config]) when is_integer(NorA); NorA == no_repeat -> check_common_config(Config); @@ -585,156 +427,7 @@ check_common_config([]) -> ok. get_default_config() -> - #{sync_mode_qlen => ?SYNC_MODE_QLEN, - drop_mode_qlen => ?DROP_MODE_QLEN, - flush_qlen => ?FLUSH_QLEN, - burst_limit_enable => ?BURST_LIMIT_ENABLE, - burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT, - burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME, - overload_kill_enable => ?OVERLOAD_KILL_ENABLE, - overload_kill_qlen => ?OVERLOAD_KILL_QLEN, - overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE, - overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER, - filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}. - -%%%----------------------------------------------------------------- -%%% Overload Protection -call_cast_or_drop(_Name, HandlerPid, ModeTab, Bin) -> - %% If the handler process is getting overloaded, the log event - %% will be synchronous instead of asynchronous (slows down the - %% logging tempo of a process doing lots of logging. If the - %% handler is choked, drop mode is set and no event will be sent. - try ?get_mode(ModeTab) of - async -> - gen_server:cast(HandlerPid, {log,Bin}); - sync -> - case call(HandlerPid, {log,Bin}) of - ok -> - ok; - _Other -> - %% dropped or {error,handler_busy} - ?observe(_Name,{dropped,1}), - ok - end; - drop -> - ?observe(_Name,{dropped,1}) - catch - %% if the ETS table doesn't exist (maybe because of a - %% handler restart), we can only drop the event - _:_ -> ?observe(_Name,{dropped,1}) - end, - ok. - -set_restart_flag(#{id := Name, module := Module} = State) -> - log_handler_info(Name, "Handler ~p overloaded and stopping", [Name], State), - Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])), - spawn(fun() -> - register(Flag, self()), - timer:sleep(infinity) - end), - ok. - -unset_restart_flag(#{id := Name, module := Module} = State) -> - Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])), - case whereis(Flag) of - undefined -> - ok; - Pid -> - exit(Pid, kill), - log_handler_info(Name, "Handler ~p restarted", [Name], State) - end. - -check_load(State = #{id:=_Name, mode_tab := ModeTab, mode := Mode, - sync_mode_qlen := SyncModeQLen, - drop_mode_qlen := DropModeQLen, - flush_qlen := FlushQLen}) -> - {_,Mem} = process_info(self(), memory), - ?observe(_Name,{max_mem,Mem}), - {_,QLen} = process_info(self(), message_queue_len), - ?observe(_Name,{max_qlen,QLen}), - %% When the handler process gets scheduled in, it's impossible - %% to predict the QLen. We could jump "up" arbitrarily from say - %% async to sync, async to drop, sync to flush, etc. However, when - %% the handler process manages the log events (without flushing), - %% one after the other, we will move "down" from drop to sync and - %% from sync to async. This way we don't risk getting stuck in - %% drop or sync mode with an empty mailbox. - {Mode1,_NewDrops,_NewFlushes} = - if - QLen >= FlushQLen -> - {flush, 0,1}; - QLen >= DropModeQLen -> - %% Note that drop mode will force log events to - %% be dropped on the client side (never sent get to - %% the handler). - IncDrops = if Mode == drop -> 0; true -> 1 end, - {?change_mode(ModeTab, Mode, drop), IncDrops,0}; - QLen >= SyncModeQLen -> - {?change_mode(ModeTab, Mode, sync), 0,0}; - true -> - {?change_mode(ModeTab, Mode, async), 0,0} - end, - State1 = ?update_other(drops,DROPS,_NewDrops,State), - {Mode1, QLen, Mem, - ?update_other(flushes,FLUSHES,_NewFlushes, - State1#{last_qlen => QLen})}. - -limit_burst(#{burst_limit_enable := false}=State) -> - {true,State}; -limit_burst(#{burst_win_ts := BurstWinT0, - burst_msg_count := BurstMsgCount, - burst_limit_window_time := BurstLimitWinTime, - burst_limit_max_count := BurstLimitMaxCnt} = State) -> - if (BurstMsgCount >= BurstLimitMaxCnt) -> - %% the limit for allowed messages has been reached - BurstWinT1 = ?timestamp(), - case ?diff_time(BurstWinT1,BurstWinT0) of - BurstCheckTime when BurstCheckTime < (BurstLimitWinTime*1000) -> - %% we're still within the burst time frame - {false,?update_other(burst_drops,BURSTS,1,State)}; - _BurstCheckTime -> - %% burst time frame passed, reset counters - {true,State#{burst_win_ts => BurstWinT1, - burst_msg_count => 0}} - end; - true -> - %% the limit for allowed messages not yet reached - {true,State#{burst_win_ts => BurstWinT0, - burst_msg_count => BurstMsgCount+1}} - end. - -kill_if_choked(Name, QLen, Mem, State = #{overload_kill_enable := KillIfOL, - overload_kill_qlen := OLKillQLen, - overload_kill_mem_size := OLKillMem}) -> - if KillIfOL andalso - ((QLen > OLKillQLen) orelse (Mem > OLKillMem)) -> - set_restart_flag(State), - exit({shutdown,{overloaded,Name,QLen,Mem}}); - true -> - ok - end. - -flush_log_events(Limit) -> - process_flag(priority, high), - Flushed = flush_log_events(0, Limit), - process_flag(priority, normal), - Flushed. - -flush_log_events(Limit, Limit) -> - Limit; -flush_log_events(N, Limit) -> - %% flush log events but leave other events, such as - %% filesync, info and change_config, so that these - %% have a chance to be processed even under heavy load - receive - {'$gen_cast',{log,_}} -> - flush_log_events(N+1, Limit); - {'$gen_call',{Pid,MRef},{log,_}} -> - Pid ! {MRef, dropped}, - flush_log_events(N+1, Limit) - after - 0 -> N - end. + #{filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}. set_repeated_filesync(#{filesync_repeat_interval:=FSyncInt} = State) when is_integer(FSyncInt) -> @@ -752,51 +445,12 @@ cancel_repeated_filesync(State) -> error -> State end. - -stop_or_restart(Name, {shutdown,Reason={overloaded,_Name,_QLen,_Mem}}, - #{overload_kill_restart_after := RestartAfter}) -> - %% If we're terminating because of an overload situation (see - %% kill_if_choked/4), we need to remove the handler and set a - %% restart timer. A separate process must perform this in order to - %% avoid deadlock. - HandlerPid = self(), - ConfigResult = logger:get_handler_config(Name), - RemoveAndRestart = - fun() -> - MRef = erlang:monitor(process, HandlerPid), - receive - {'DOWN',MRef,_,_,_} -> - ok - after 30000 -> - error_notify(Reason), - exit(HandlerPid, kill) - end, - case ConfigResult of - {ok,#{module:=HMod}=HConfig0} when is_integer(RestartAfter) -> - _ = logger:remove_handler(Name), - HConfig = try HMod:filter_config(HConfig0) - catch _:_ -> HConfig0 - end, - _ = timer:apply_after(RestartAfter, logger, add_handler, - [Name,HMod,HConfig]); - {ok,_} -> - _ = logger:remove_handler(Name); - {error,CfgReason} when is_integer(RestartAfter) -> - error_notify({Name,restart_impossible,CfgReason}); - {error,_} -> - ok - end - end, - spawn(RemoveAndRestart), - ok; -stop_or_restart(_Name, _Reason, _State) -> - ok. - -overload_levels_ok(HandlerConfig) -> - SMQL = maps:get(sync_mode_qlen, HandlerConfig, ?SYNC_MODE_QLEN), - DMQL = maps:get(drop_mode_qlen, HandlerConfig, ?DROP_MODE_QLEN), - FQL = maps:get(flush_qlen, HandlerConfig, ?FLUSH_QLEN), - (DMQL > 1) andalso (SMQL =< DMQL) andalso (DMQL =< FQL). - error_notify(Term) -> ?internal_log(error, Term). + +maybe_set_repeated_filesync(_Olp, + #{filesync_repeat_interval:=FSyncInt}, + #{filesync_repeat_interval:=FSyncInt}) -> + ok; +maybe_set_repeated_filesync(Olp,_,#{filesync_repeat_interval:=FSyncInt}) -> + logger_olp:cast(Olp,{set_repeated_filesync,FSyncInt}). diff --git a/lib/kernel/src/logger_h_common.hrl b/lib/kernel/src/logger_h_common.hrl index 261b0a6246..004a61d9d9 100644 --- a/lib/kernel/src/logger_h_common.hrl +++ b/lib/kernel/src/logger_h_common.hrl @@ -1,50 +1,22 @@ - -%%%----------------------------------------------------------------- -%%% Overload protection configuration - -%%! *** NOTE *** -%%! It's important that: -%%! SYNC_MODE_QLEN =< DROP_MODE_QLEN =< FLUSH_QLEN -%%! and that DROP_MODE_QLEN >= 2. -%%! Otherwise the handler could end up in drop mode with no new -%%! log requests to process. This would cause all future requests -%%! to be dropped (no switch to async mode would ever take place). - -%% This specifies the message_queue_len value where the log -%% requests switch from asynchronous casts to synchronous calls. --define(SYNC_MODE_QLEN, 10). -%% Above this message_queue_len, log requests will be dropped, -%% i.e. no log requests get sent to the handler process. --define(DROP_MODE_QLEN, 200). -%% Above this message_queue_len, the handler process will flush -%% its mailbox and only leave this number of messages in it. --define(FLUSH_QLEN, 1000). - -%% Never flush more than this number of messages in one go, -%% or the handler will be unresponsive for seconds (keep this -%% number as large as possible or the mailbox could grow large). --define(FLUSH_MAX_N, 5000). - -%% BURST_LIMIT_MAX_COUNT is the max number of log requests allowed -%% to be written within a BURST_LIMIT_WINDOW_TIME time frame. --define(BURST_LIMIT_ENABLE, true). --define(BURST_LIMIT_MAX_COUNT, 500). --define(BURST_LIMIT_WINDOW_TIME, 1000). - -%% This enables/disables the feature to automatically get the -%% handler terminated if it gets too loaded (and can't keep up). --define(OVERLOAD_KILL_ENABLE, false). -%% If the message_queue_len goes above this size even after -%% flushing has been performed, the handler is terminated. --define(OVERLOAD_KILL_QLEN, 20000). -%% If the memory usage exceeds this level --define(OVERLOAD_KILL_MEM_SIZE, 3000000). - -%% This is the default time that the handler will wait before -%% restarting and accepting new requests. The value 'infinity' -%% disables restarts. --define(OVERLOAD_KILL_RESTART_AFTER, 5000). -%%-define(OVERLOAD_KILL_RESTART_AFTER, infinity). +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2015. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% %% The handler sends asynchronous write requests to the process %% controlling the i/o device, but every once in this interval @@ -65,12 +37,6 @@ -define(FILESYNC_REPEAT_INTERVAL, 5000). %%-define(FILESYNC_REPEAT_INTERVAL, no_repeat). -%% This is the time after last message received that we think/hope -%% that the handler has an empty mailbox (no new log request has -%% come in). --define(IDLE_DETECT_TIME_MSEC, 100). --define(IDLE_DETECT_TIME_USEC, 100000). - %% Default disk log option values -define(DISK_LOG_TYPE, wrap). -define(DISK_LOG_MAX_NO_FILES, 10). @@ -83,43 +49,6 @@ list_to_atom(lists:concat([MODULE,"_",Name]))). %%%----------------------------------------------------------------- -%%% Overload protection macros - --define(timestamp(), erlang:monotonic_time(microsecond)). - --define(get_mode(Tid), - case ets:lookup(Tid, mode) of - [{mode,M}] -> M; - _ -> async - end). - --define(set_mode(Tid, M), - begin ets:insert(Tid, {mode,M}), M end). - --define(change_mode(Tid, M0, M1), - if M0 == M1 -> - M0; - true -> - ets:insert(Tid, {mode,M1}), - M1 - end). - --define(min(X1, X2), - if X2 == undefined -> X1; - X2 < X1 -> X2; - true -> X1 - end). - --define(max(X1, X2), - if - X2 == undefined -> X1; - X2 > X1 -> X2; - true -> X1 - end). - --define(diff_time(OS_T1, OS_T0), OS_T1-OS_T0). - -%%%----------------------------------------------------------------- %%% The test hook macros make it possible to observe and manipulate %%% internal handler functionality. When enabled, these macros will %%% slow down execution and therefore should not be include in code @@ -183,7 +112,6 @@ [{_,ERROR}] -> ERROR catch _:_ -> disk_log:sync(LOG) end). - -define(DEFAULT_CALL_TIMEOUT, 5000). -else. % DEFAULTS! -define(TEST_HOOKS_TAB, undefined). @@ -196,68 +124,4 @@ -define(file_datasync(DEVICE), file:datasync(DEVICE)). -define(disk_log_write(LOG, MODE, DATA), disk_log_write(LOG, MODE, DATA)). -define(disk_log_sync(LOG), disk_log:sync(LOG)). - -define(DEFAULT_CALL_TIMEOUT, 10000). --endif. - -%%%----------------------------------------------------------------- -%%% These macros enable statistics counters in the state of the -%%% handler which is useful for analysing the overload protection -%%% behaviour. These counters should not be included in code to be -%%% officially released (as some counters will grow very large -%%% over time). - -%%-define(SAVE_STATS, true). --ifdef(SAVE_STATS). - -define(merge_with_stats(STATE), - STATE#{flushes => 0, flushed => 0, drops => 0, - burst_drops => 0, casts => 0, calls => 0, - max_qlen => 0, max_time => 0}). - - -define(update_max_qlen(QLEN, STATE), - begin #{max_qlen := QLEN0} = STATE, - STATE#{max_qlen => ?max(QLEN0,QLEN)} end). - - -define(update_calls_or_casts(CALL_OR_CAST, INC, STATE), - case CALL_OR_CAST of - cast -> - #{casts := CASTS0} = STATE, - STATE#{casts => CASTS0+INC}; - call -> - #{calls := CALLS0} = STATE, - STATE#{calls => CALLS0+INC} - end). - - -define(update_max_time(TIME, STATE), - begin #{max_time := TIME0} = STATE, - STATE#{max_time => ?max(TIME0,TIME)} end). - - -define(update_other(OTHER, VAR, INCVAL, STATE), - begin #{OTHER := VAR} = STATE, - STATE#{OTHER => VAR+INCVAL} end). - --else. % DEFAULT! - -define(merge_with_stats(STATE), STATE). - -define(update_max_qlen(_QLEN, STATE), STATE). - -define(update_calls_or_casts(_CALL_OR_CAST, _INC, STATE), STATE). - -define(update_max_time(_TIME, STATE), STATE). - -define(update_other(_OTHER, _VAR, _INCVAL, STATE), STATE). --endif. - -%%%----------------------------------------------------------------- -%%% These macros enable callbacks that make it possible to analyse -%%% the overload protection behaviour from outside the handler -%%% process (including dropped requests on the client side). -%%% An external callback module (?OBSERVER_MOD) is required which -%%% is not part of the kernel application. For this reason, these -%%% callbacks should not be included in code to be officially released. - -%%-define(OBSERVER_MOD, logger_test). --ifdef(OBSERVER_MOD). - -define(start_observation(NAME), ?OBSERVER:start_observation(NAME)). - -define(observe(NAME,EVENT), ?OBSERVER:observe(NAME,EVENT)). - --else. % DEFAULT! - -define(start_observation(_NAME), ok). - -define(observe(_NAME,_EVENT), ok). -endif. -%%! <--- diff --git a/lib/kernel/src/logger_internal.hrl b/lib/kernel/src/logger_internal.hrl index d96a4ac78b..e53922e5d3 100644 --- a/lib/kernel/src/logger_internal.hrl +++ b/lib/kernel/src/logger_internal.hrl @@ -19,6 +19,7 @@ %% -include_lib("kernel/include/logger.hrl"). -define(LOGGER_TABLE,logger). +-define(PROXY_KEY,'$proxy_config$'). -define(PRIMARY_KEY,'$primary_config$'). -define(HANDLER_KEY,'$handler_config$'). -define(LOGGER_META_KEY,'$logger_metadata$'). @@ -40,12 +41,14 @@ -define(DEFAULT_LOGGER_CALL_TIMEOUT, infinity). --define(LOG_INTERNAL(Level,Report), +-define(LOG_INTERNAL(Level,Report),?DO_LOG_INTERNAL(Level,[Report])). +-define(LOG_INTERNAL(Level,Format,Args),?DO_LOG_INTERNAL(Level,[Format,Args])). +-define(DO_LOG_INTERNAL(Level,Data), case logger:allow(Level,?MODULE) of true -> %% Spawn this to avoid deadlocks - _ = spawn(logger,macro_log,[?LOCATION,Level,Report, - logger:add_default_metadata(#{})]), + _ = spawn(logger,macro_log,[?LOCATION,Level|Data]++ + [logger:add_default_metadata(#{})]), ok; false -> ok diff --git a/lib/kernel/src/logger_olp.erl b/lib/kernel/src/logger_olp.erl new file mode 100644 index 0000000000..009280a9c9 --- /dev/null +++ b/lib/kernel/src/logger_olp.erl @@ -0,0 +1,626 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2017-2018. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(logger_olp). +-behaviour(gen_server). + +-include("logger_olp.hrl"). +-include("logger_internal.hrl"). + +%% API +-export([start_link/4, load/2, info/1, reset/1, stop/1, restart/1, + set_opts/2, get_opts/1, get_default_opts/0, get_pid/1, + call/2, cast/2, get_ref/0, get_ref/1]). + +%% gen_server and proc_lib callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(OPT_KEYS,[sync_mode_qlen, + drop_mode_qlen, + flush_qlen, + burst_limit_enable, + burst_limit_max_count, + burst_limit_window_time, + overload_kill_enable, + overload_kill_qlen, + overload_kill_mem_size, + overload_kill_restart_after]). + +-export_type([olp_ref/0, options/0]). + +-opaque olp_ref() :: {atom(),pid(),ets:tid()}. + +-type options() :: logger:olp_config(). + +%%%----------------------------------------------------------------- +%%% API + +-spec start_link(Name,Module,Args,Options) -> {ok,Pid,Olp} | {error,Reason} when + Name :: atom(), + Module :: module(), + Args :: term(), + Options :: options(), + Pid :: pid(), + Olp :: olp_ref(), + Reason :: term(). +start_link(Name,Module,Args,Options0) when is_map(Options0) -> + Options = maps:merge(get_default_opts(),Options0), + case check_opts(Options) of + ok -> + proc_lib:start_link(?MODULE,init,[[Name,Module,Args,Options]]); + Error -> + Error + end. + +-spec load(Olp, Msg) -> ok when + Olp :: olp_ref(), + Msg :: term(). +load({_Name,Pid,ModeRef},Msg) -> + %% If the process is getting overloaded, the message will be + %% synchronous instead of asynchronous (slows down the tempo of a + %% process causing much load). If the process is choked, drop mode + %% is set and no message is sent. + try ?get_mode(ModeRef) of + async -> + gen_server:cast(Pid, {'$olp_load',Msg}); + sync -> + case call(Pid, {'$olp_load',Msg}) of + ok -> + ok; + _Other -> + %% dropped or {error,busy} + ?observe(_Name,{dropped,1}), + ok + end; + drop -> + ?observe(_Name,{dropped,1}) + catch + %% if the ETS table doesn't exist (maybe because of a + %% process restart), we can only drop the event + _:_ -> ?observe(_Name,{dropped,1}) + end, + ok. + +-spec info(Olp) -> map() | {error, busy} when + Olp :: atom() | pid() | olp_ref(). +info(Olp) -> + call(Olp, info). + +-spec reset(Olp) -> ok | {error, busy} when + Olp :: atom() | pid() | olp_ref(). +reset(Olp) -> + call(Olp, reset). + +-spec stop(Olp) -> ok when + Olp :: atom() | pid() | olp_ref(). +stop({_Name,Pid,_ModRef}) -> + stop(Pid); +stop(Pid) -> + _ = gen_server:call(Pid, stop), + ok. + +-spec set_opts(Olp, Opts) -> ok | {error,term()} | {error, busy} when + Olp :: atom() | pid() | olp_ref(), + Opts :: options(). +set_opts(Olp, Opts) -> + call(Olp, {set_opts,Opts}). + +-spec get_opts(Olp) -> options() | {error, busy} when + Olp :: atom() | pid() | olp_ref(). +get_opts(Olp) -> + call(Olp, get_opts). + +-spec get_default_opts() -> options(). +get_default_opts() -> + #{sync_mode_qlen => ?SYNC_MODE_QLEN, + drop_mode_qlen => ?DROP_MODE_QLEN, + flush_qlen => ?FLUSH_QLEN, + burst_limit_enable => ?BURST_LIMIT_ENABLE, + burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT, + burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME, + overload_kill_enable => ?OVERLOAD_KILL_ENABLE, + overload_kill_qlen => ?OVERLOAD_KILL_QLEN, + overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE, + overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER}. + +-spec restart(fun(() -> any())) -> ok. +restart(Fun) -> + Result = + try Fun() + catch C:R:S -> + {error,{restart_failed,Fun,C,R,S}} + end, + ?LOG_INTERNAL(debug,[{logger_olp,restart}, + {result,Result}]), + ok. + +-spec get_ref() -> olp_ref(). +get_ref() -> + get(olp_ref). + +-spec get_ref(PidOrName) -> olp_ref() | {error, busy} when + PidOrName :: pid() | atom(). +get_ref(PidOrName) -> + call(PidOrName,get_ref). + +-spec get_pid(olp_ref()) -> pid(). +get_pid({_Name,Pid,_ModeRef}) -> + Pid. + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +init([Name,Module,Args,Options]) -> + register(Name, self()), + process_flag(message_queue_data, off_heap), + + ?start_observation(Name), + + try ets:new(Name, [public]) of + ModeRef -> + OlpRef = {Name,self(),ModeRef}, + put(olp_ref,OlpRef), + try Module:init(Args) of + {ok,CBState} -> + ?set_mode(ModeRef, async), + T0 = ?timestamp(), + proc_lib:init_ack({ok,self(),OlpRef}), + %% Storing options in state to avoid copying + %% (sending) the option data with each message + State0 = ?merge_with_stats( + Options#{id => Name, + idle=> true, + module => Module, + mode_ref => ModeRef, + mode => async, + last_qlen => 0, + last_load_ts => T0, + burst_win_ts => T0, + burst_msg_count => 0, + cb_state => CBState}), + State = reset_restart_flag(State0), + gen_server:enter_loop(?MODULE, [], State); + Error -> + _ = ets:delete(ModeRef), + unregister(Name), + proc_lib:init_ack(Error) + catch + _:Error -> + _ = ets:delete(ModeRef), + unregister(Name), + proc_lib:init_ack(Error) + end + catch + _:Error -> + unregister(Name), + proc_lib:init_ack(Error) + end. + +%% This is the synchronous load event. +handle_call({'$olp_load', Msg}, _From, State) -> + {Result,State1} = do_load(Msg, call, State#{idle=>false}), + %% Result == ok | dropped + reply_return(Result,State1); + +handle_call(get_ref,_From,#{id:=Name,mode_ref:=ModeRef}=State) -> + reply_return({Name,self(),ModeRef},State); + +handle_call({set_opts,Opts0},_From,State) -> + Opts = maps:merge(maps:with(?OPT_KEYS,State),Opts0), + case check_opts(Opts) of + ok -> + reply_return(ok, maps:merge(State,Opts)); + Error -> + reply_return(Error, State) + end; + +handle_call(get_opts,_From,State) -> + reply_return(maps:with(?OPT_KEYS,State), State); + +handle_call(info, _From, State) -> + reply_return(State, State); + +handle_call(reset, _From, #{module:=Module,cb_state:=CBState}=State) -> + State1 = ?merge_with_stats(State), + CBState1 = try_callback_call(Module,reset_state,[CBState],CBState), + reply_return(ok, State1#{idle => true, + last_qlen => 0, + last_load_ts => ?timestamp(), + cb_state => CBState1}); + +handle_call(stop, _From, State) -> + {stop, {shutdown,stopped}, ok, State}; + +handle_call(Msg, From, #{module:=Module,cb_state:=CBState}=State) -> + case try_callback_call(Module,handle_call,[Msg, From, CBState]) of + {reply,Reply,CBState1} -> + reply_return(Reply,State#{cb_state=>CBState1}); + {noreply,CBState1} -> + noreply_return(State#{cb_state=>CBState1}); + {stop, Reason, Reply, CBState1} -> + {stop, Reason, Reply, State#{cb_state=>CBState1}}; + {stop, Reason, CBState1} -> + {stop, Reason, State#{cb_state=>CBState1}} + end. + +%% This is the asynchronous load event. +handle_cast({'$olp_load', Msg}, State) -> + {_Result,State1} = do_load(Msg, cast, State#{idle=>false}), + noreply_return(State1); + +handle_cast(Msg, #{module:=Module, cb_state:=CBState} = State) -> + case try_callback_call(Module,handle_cast,[Msg, CBState]) of + {noreply,CBState1} -> + noreply_return(State#{cb_state=>CBState1}); + {stop, Reason, CBState1} -> + {stop, Reason, State#{cb_state=>CBState1}} + end. + +handle_info(timeout, #{mode_ref:=_ModeRef, mode:=Mode} = State) -> + State1 = notify(idle,State), + State2 = maybe_notify_mode_change(async,State1), + {noreply, State2#{idle => true, + mode => ?change_mode(_ModeRef, Mode, async), + burst_msg_count => 0}}; +handle_info(Msg, #{module := Module, cb_state := CBState} = State) -> + case try_callback_call(Module,handle_info,[Msg, CBState]) of + {noreply,CBState1} -> + noreply_return(State#{cb_state=>CBState1}); + {stop, Reason, CBState1} -> + {stop, Reason, State#{cb_state=>CBState1}}; + {load,CBState1} -> + {_,State1} = do_load(Msg, cast, State#{idle=>false, + cb_state=>CBState1}), + noreply_return(State1) + end. + +terminate({shutdown,{overloaded,_QLen,_Mem}}, + #{id:=Name, module := Module, cb_state := CBState, + overload_kill_restart_after := RestartAfter} = State) -> + %% We're terminating because of an overload situation (see + %% kill_if_choked/3). + unregister(Name), %%!!!! to avoid error printout of callback crashed on stop + case try_callback_call(Module,terminate,[overloaded,CBState],ok) of + {ok,Fun} when is_function(Fun,0), is_integer(RestartAfter) -> + set_restart_flag(State), + _ = timer:apply_after(RestartAfter,?MODULE,restart,[Fun]), + ok; + _ -> + ok + end; +terminate(Reason, #{id:=Name, module:=Module, cb_state:=CBState}) -> + _ = try_callback_call(Module,terminate,[Reason,CBState],ok), + unregister(Name), + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +%%%----------------------------------------------------------------- +%%% Internal functions +-spec call(Olp, term()) -> term() | {error,busy} when + Olp :: atom() | pid() | olp_ref(). +call({_Name, Pid, _ModeRef},Msg) -> + call(Pid, Msg); +call(Server, Msg) -> + try + gen_server:call(Server, Msg) + catch + _:{timeout,_} -> {error,busy} + end. + +-spec cast(olp_ref(),term()) -> ok. +cast({_Name, Pid, _ModeRef},Msg) -> + gen_server:cast(Pid, Msg). + +%% check for overload between every event (and set Mode to async, +%% sync or drop accordingly), but never flush the whole mailbox +%% before LogWindowSize events have been handled +do_load(Msg, CallOrCast, State) -> + T1 = ?timestamp(), + State1 = ?update_time(T1,State), + + %% check if the process is getting overloaded, or if it's + %% recovering from overload (the check must be done for each + %% event to react quickly to large bursts of events and + %% to ensure that the handler can never end up in drop mode + %% with an empty mailbox, which would stop operation) + {Mode1,QLen,Mem,State2} = check_load(State1), + + %% kill the handler if it can't keep up with the load + kill_if_choked(QLen, Mem, State2), + + if Mode1 == flush -> + flush(T1, State2); + true -> + handle_load(Mode1, T1, Msg, CallOrCast, State2) + end. + +%% this function is called by do_load/3 after an overload check +%% has been performed, where QLen > FlushQLen +flush(T1, State=#{id := _Name, mode := Mode, last_load_ts := _T0, mode_ref := ModeRef}) -> + %% flush load messages in the mailbox (a limited number in order + %% to not cause long delays) + NewFlushed = flush_load(?FLUSH_MAX_N), + + %% write info in log about flushed messages + State1=notify({flushed,NewFlushed},State), + + %% because of the receive loop when flushing messages, the + %% handler will be scheduled out often and the mailbox could + %% grow very large, so we'd better check the queue again here + {_,QLen1} = process_info(self(), message_queue_len), + ?observe(_Name,{max_qlen,QLen1}), + + %% Add 1 for the current log event + ?observe(_Name,{flushed,NewFlushed+1}), + + State2 = ?update_max_time(?diff_time(T1,_T0),State1), + State3 = ?update_max_qlen(QLen1,State2), + State4 = maybe_notify_mode_change(async,State3), + {dropped,?update_other(flushed,FLUSHED,NewFlushed, + State4#{mode => ?change_mode(ModeRef,Mode,async), + last_qlen => QLen1, + last_load_ts => T1})}. + +%% this function is called to actually handle the message +handle_load(Mode, T1, Msg, _CallOrCast, + State = #{id := _Name, + module := Module, + cb_state := CBState, + last_qlen := LastQLen, + last_load_ts := _T0}) -> + %% check if we need to limit the number of writes + %% during a burst of log events + {DoWrite,State1} = limit_burst(State), + + {Result,LastQLen1,CBState1} = + if DoWrite -> + ?observe(_Name,{_CallOrCast,1}), + CBS = try_callback_call(Module,handle_load,[Msg,CBState]), + {ok,element(2, process_info(self(), message_queue_len)),CBS}; + true -> + ?observe(_Name,{flushed,1}), + {dropped,LastQLen,CBState} + end, + State2 = State1#{cb_state=>CBState1}, + + State3 = State2#{mode => Mode}, + State4 = ?update_calls_or_casts(_CallOrCast,1,State3), + State5 = ?update_max_qlen(LastQLen1,State4), + State6 = + ?update_max_time(?diff_time(T1,_T0), + State5#{last_qlen := LastQLen1, + last_load_ts => T1}), + State7 = case Result of + ok -> + S = ?update_freq(T1,State6), + ?update_other(writes,WRITES,1,S); + _ -> + State6 + end, + {Result,State7}. + + +%%%----------------------------------------------------------------- +%%% Check that the options are valid +check_opts(Options) when is_map(Options) -> + case do_check_opts(maps:to_list(Options)) of + ok -> + case overload_levels_ok(Options) of + true -> + ok; + false -> + Faulty = maps:with([sync_mode_qlen, + drop_mode_qlen, + flush_qlen],Options), + {error,{invalid_olp_levels,Faulty}} + end; + {error,Key,Value} -> + {error,{invalid_olp_config,#{Key=>Value}}} + end. + +do_check_opts([{sync_mode_qlen,N}|Options]) when is_integer(N) -> + do_check_opts(Options); +do_check_opts([{drop_mode_qlen,N}|Options]) when is_integer(N) -> + do_check_opts(Options); +do_check_opts([{flush_qlen,N}|Options]) when is_integer(N) -> + do_check_opts(Options); +do_check_opts([{burst_limit_enable,Bool}|Options]) when is_boolean(Bool) -> + do_check_opts(Options); +do_check_opts([{burst_limit_max_count,N}|Options]) when is_integer(N) -> + do_check_opts(Options); +do_check_opts([{burst_limit_window_time,N}|Options]) when is_integer(N) -> + do_check_opts(Options); +do_check_opts([{overload_kill_enable,Bool}|Options]) when is_boolean(Bool) -> + do_check_opts(Options); +do_check_opts([{overload_kill_qlen,N}|Options]) when is_integer(N) -> + do_check_opts(Options); +do_check_opts([{overload_kill_mem_size,N}|Options]) when is_integer(N) -> + do_check_opts(Options); +do_check_opts([{overload_kill_restart_after,NorA}|Options]) + when is_integer(NorA); NorA == infinity -> + do_check_opts(Options); +do_check_opts([{Key,Value}|_]) -> + {error,Key,Value}; +do_check_opts([]) -> + ok. + +set_restart_flag(#{id := Name, module := Module}) -> + Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])), + spawn(fun() -> + register(Flag, self()), + timer:sleep(infinity) + end), + ok. + +reset_restart_flag(#{id := Name, module := Module} = State) -> + Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])), + case whereis(Flag) of + undefined -> + State; + Pid -> + exit(Pid, kill), + notify(restart,State) + end. + +check_load(State = #{id:=_Name, mode_ref := ModeRef, mode := Mode, + sync_mode_qlen := SyncModeQLen, + drop_mode_qlen := DropModeQLen, + flush_qlen := FlushQLen}) -> + {_,Mem} = process_info(self(), memory), + ?observe(_Name,{max_mem,Mem}), + {_,QLen} = process_info(self(), message_queue_len), + ?observe(_Name,{max_qlen,QLen}), + %% When the handler process gets scheduled in, it's impossible + %% to predict the QLen. We could jump "up" arbitrarily from say + %% async to sync, async to drop, sync to flush, etc. However, when + %% the handler process manages the log events (without flushing), + %% one after the other, we will move "down" from drop to sync and + %% from sync to async. This way we don't risk getting stuck in + %% drop or sync mode with an empty mailbox. + {Mode1,_NewDrops,_NewFlushes} = + if + QLen >= FlushQLen -> + {flush, 0,1}; + QLen >= DropModeQLen -> + %% Note that drop mode will force load messages to + %% be dropped on the client side (never sent to + %% the olp process). + IncDrops = if Mode == drop -> 0; true -> 1 end, + {?change_mode(ModeRef, Mode, drop), IncDrops,0}; + QLen >= SyncModeQLen -> + {?change_mode(ModeRef, Mode, sync), 0,0}; + true -> + {?change_mode(ModeRef, Mode, async), 0,0} + end, + State1 = ?update_other(drops,DROPS,_NewDrops,State), + State2 = ?update_max_qlen(QLen,State1), + State3 = maybe_notify_mode_change(Mode1,State2), + {Mode1, QLen, Mem, + ?update_other(flushes,FLUSHES,_NewFlushes, + State3#{last_qlen => QLen})}. + +limit_burst(#{burst_limit_enable := false}=State) -> + {true,State}; +limit_burst(#{burst_win_ts := BurstWinT0, + burst_msg_count := BurstMsgCount, + burst_limit_window_time := BurstLimitWinTime, + burst_limit_max_count := BurstLimitMaxCnt} = State) -> + if (BurstMsgCount >= BurstLimitMaxCnt) -> + %% the limit for allowed messages has been reached + BurstWinT1 = ?timestamp(), + case ?diff_time(BurstWinT1,BurstWinT0) of + BurstCheckTime when BurstCheckTime < (BurstLimitWinTime*1000) -> + %% we're still within the burst time frame + {false,?update_other(burst_drops,BURSTS,1,State)}; + _BurstCheckTime -> + %% burst time frame passed, reset counters + {true,State#{burst_win_ts => BurstWinT1, + burst_msg_count => 0}} + end; + true -> + %% the limit for allowed messages not yet reached + {true,State#{burst_win_ts => BurstWinT0, + burst_msg_count => BurstMsgCount+1}} + end. + +kill_if_choked(QLen, Mem, #{overload_kill_enable := KillIfOL, + overload_kill_qlen := OLKillQLen, + overload_kill_mem_size := OLKillMem}) -> + if KillIfOL andalso + ((QLen > OLKillQLen) orelse (Mem > OLKillMem)) -> + exit({shutdown,{overloaded,QLen,Mem}}); + true -> + ok + end. + +flush_load(Limit) -> + process_flag(priority, high), + Flushed = flush_load(0, Limit), + process_flag(priority, normal), + Flushed. + +flush_load(Limit, Limit) -> + Limit; +flush_load(N, Limit) -> + %% flush log events but leave other events, such as info, reset + %% and stop, so that these have a chance to be processed even + %% under heavy load + receive + {'$gen_cast',{'$olp_load',_}} -> + flush_load(N+1, Limit); + {'$gen_call',{Pid,MRef},{'$olp_load',_}} -> + Pid ! {MRef, dropped}, + flush_load(N+1, Limit); + {log,_,_,_,_} -> + flush_load(N+1, Limit); + {log,_,_,_} -> + flush_load(N+1, Limit) + after + 0 -> N + end. + +overload_levels_ok(Options) -> + SMQL = maps:get(sync_mode_qlen, Options, ?SYNC_MODE_QLEN), + DMQL = maps:get(drop_mode_qlen, Options, ?DROP_MODE_QLEN), + FQL = maps:get(flush_qlen, Options, ?FLUSH_QLEN), + (DMQL > 1) andalso (SMQL =< DMQL) andalso (DMQL =< FQL). + +maybe_notify_mode_change(drop,#{mode:=Mode0}=State) + when Mode0=/=drop -> + notify({mode_change,Mode0,drop},State); +maybe_notify_mode_change(Mode1,#{mode:=drop}=State) + when Mode1==async; Mode1==sync -> + notify({mode_change,drop,Mode1},State); +maybe_notify_mode_change(_,State) -> + State. + +notify(Note,#{module:=Module,cb_state:=CBState}=State) -> + CBState1 = try_callback_call(Module,notify,[Note,CBState],CBState), + State#{cb_state=>CBState1}. + +try_callback_call(Module, Function, Args) -> + try_callback_call(Module, Function, Args, '$no_default_return'). + +try_callback_call(Module, Function, Args, DefRet) -> + try apply(Module, Function, Args) + catch + throw:R -> R; + error:undef:S when DefRet=/='$no_default_return' -> + case S of + [{Module,Function,Args,_}|_] -> + DefRet; + _ -> + erlang:raise(error,undef,S) + end + end. + +noreply_return(#{idle:=true}=State) -> + {noreply,State}; +noreply_return(#{idle:=false}=State) -> + {noreply,State,?IDLE_DETECT_TIME}. + +reply_return(Reply,#{idle:=true}=State) -> + {reply,Reply,State}; +reply_return(Reply,#{idle:=false}=State) -> + {reply,Reply,State,?IDLE_DETECT_TIME}. diff --git a/lib/kernel/src/logger_olp.hrl b/lib/kernel/src/logger_olp.hrl new file mode 100644 index 0000000000..9b4f5ebf27 --- /dev/null +++ b/lib/kernel/src/logger_olp.hrl @@ -0,0 +1,180 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2015. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%%%----------------------------------------------------------------- +%%% Overload protection configuration + +%%! *** NOTE *** +%%! It's important that: +%%! SYNC_MODE_QLEN =< DROP_MODE_QLEN =< FLUSH_QLEN +%%! and that DROP_MODE_QLEN >= 2. +%%! Otherwise the process could end up in drop mode with no new +%%! log requests to process. This would cause all future requests +%%! to be dropped (no switch to async mode would ever take place). + +%% This specifies the message_queue_len value where the log +%% requests switch from asynchronous casts to synchronous calls. +-define(SYNC_MODE_QLEN, 10). +%% Above this message_queue_len, log requests will be dropped, +%% i.e. no log requests get sent to the process. +-define(DROP_MODE_QLEN, 200). +%% Above this message_queue_len, the process will flush its mailbox +%% and only leave this number of messages in it. +-define(FLUSH_QLEN, 1000). + +%% Never flush more than this number of messages in one go, or the +%% process will be unresponsive for seconds (keep this number as large +%% as possible or the mailbox could grow large). +-define(FLUSH_MAX_N, 5000). + +%% BURST_LIMIT_MAX_COUNT is the max number of log requests allowed +%% to be written within a BURST_LIMIT_WINDOW_TIME time frame. +-define(BURST_LIMIT_ENABLE, true). +-define(BURST_LIMIT_MAX_COUNT, 500). +-define(BURST_LIMIT_WINDOW_TIME, 1000). + +%% This enables/disables the feature to automatically terminate the +%% process if it gets too loaded (and can't keep up). +-define(OVERLOAD_KILL_ENABLE, false). +%% If the message_queue_len goes above this size even after +%% flushing has been performed, the process is terminated. +-define(OVERLOAD_KILL_QLEN, 20000). +%% If the memory usage exceeds this level, the process is terminated. +-define(OVERLOAD_KILL_MEM_SIZE, 3000000). + +%% This is the default time to wait before restarting and accepting +%% new requests. The value 'infinity' disables restarts. +-define(OVERLOAD_KILL_RESTART_AFTER, 5000). + +%% This is the time in milliseconds after last load message received +%% that we notify the callback about being idle. +-define(IDLE_DETECT_TIME, 100). + +%%%----------------------------------------------------------------- +%%% Overload protection macros + +-define(timestamp(), erlang:monotonic_time(microsecond)). + +-define(get_mode(Tid), + case ets:lookup(Tid, mode) of + [{mode,M}] -> M; + _ -> async + end). + +-define(set_mode(Tid, M), + begin ets:insert(Tid, {mode,M}), M end). + +-define(change_mode(Tid, M0, M1), + if M0 == M1 -> + M0; + true -> + ets:insert(Tid, {mode,M1}), + M1 + end). + +-define(max(X1, X2), + if + X2 == undefined -> X1; + X2 > X1 -> X2; + true -> X1 + end). + +-define(diff_time(OS_T1, OS_T0), OS_T1-OS_T0). + +%%%----------------------------------------------------------------- +%%% These macros enable statistics counters in the state of the +%%% process, which is useful for analysing the overload protection +%%% behaviour. These counters should not be included in code to be +%%% officially released (as some counters will grow very large over +%%% time). + +%% -define(SAVE_STATS, true). +-ifdef(SAVE_STATS). + -define(merge_with_stats(STATE), + begin + TIME = ?timestamp(), + STATE#{start => TIME, time => {TIME,0}, + flushes => 0, flushed => 0, drops => 0, + burst_drops => 0, casts => 0, calls => 0, + writes => 0, max_qlen => 0, max_time => 0, + freq => {TIME,0,0}} end). + + -define(update_max_qlen(QLEN, STATE), + begin #{max_qlen := QLEN0} = STATE, + STATE#{max_qlen => ?max(QLEN0,QLEN)} end). + + -define(update_calls_or_casts(CALL_OR_CAST, INC, STATE), + case CALL_OR_CAST of + cast -> + #{casts := CASTS0} = STATE, + STATE#{casts => CASTS0+INC}; + call -> + #{calls := CALLS0} = STATE, + STATE#{calls => CALLS0+INC} + end). + + -define(update_max_time(TIME, STATE), + begin #{max_time := TIME0} = STATE, + STATE#{max_time => ?max(TIME0,TIME)} end). + + -define(update_other(OTHER, VAR, INCVAL, STATE), + begin #{OTHER := VAR} = STATE, + STATE#{OTHER => VAR+INCVAL} end). + + -define(update_freq(TIME,STATE), + begin + case STATE of + #{freq := {START, 49, _}} -> + STATE#{freq => {TIME, 0, trunc(1000000*50/(?diff_time(TIME,START)))}}; + #{freq := {START, N, FREQ}} -> + STATE#{freq => {START, N+1, FREQ}} + end end). + + -define(update_time(TIME,STATE), + begin #{start := START} = STATE, + STATE#{time => {TIME,trunc((?diff_time(TIME,START))/1000000)}} end). + +-else. % DEFAULT! + -define(merge_with_stats(STATE), STATE). + -define(update_max_qlen(_QLEN, STATE), STATE). + -define(update_calls_or_casts(_CALL_OR_CAST, _INC, STATE), STATE). + -define(update_max_time(_TIME, STATE), STATE). + -define(update_other(_OTHER, _VAR, _INCVAL, STATE), STATE). + -define(update_freq(_TIME, STATE), STATE). + -define(update_time(_TIME, STATE), STATE). +-endif. + +%%%----------------------------------------------------------------- +%%% These macros enable callbacks that make it possible to analyse the +%%% overload protection behaviour from outside the process (including +%%% dropped requests on the client side). An external callback module +%%% (?OBSERVER_MOD) is required which is not part of the kernel +%%% application. For this reason, these callbacks should not be +%%% included in code to be officially released. + +%%-define(OBSERVER_MOD, logger_test). +-ifdef(OBSERVER_MOD). + -define(start_observation(NAME), ?OBSERVER:start_observation(NAME)). + -define(observe(NAME,EVENT), ?OBSERVER:observe(NAME,EVENT)). + +-else. % DEFAULT! + -define(start_observation(_NAME), ok). + -define(observe(_NAME,_EVENT), ok). +-endif. diff --git a/lib/kernel/src/logger_proxy.erl b/lib/kernel/src/logger_proxy.erl new file mode 100644 index 0000000000..24b293805c --- /dev/null +++ b/lib/kernel/src/logger_proxy.erl @@ -0,0 +1,165 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2017-2018. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(logger_proxy). + +%% API +-export([start_link/0, restart/0, log/1, child_spec/0, get_default_config/0]). + +%% logger_olp callbacks +-export([init/1, handle_load/2, handle_info/2, terminate/2, + notify/2]). + +-include("logger_internal.hrl"). + +-define(SERVER,?MODULE). + +%%%----------------------------------------------------------------- +%%% API +-spec log(RemoteLog) -> ok when + RemoteLog :: {remote,node(),LogEvent}, + LogEvent :: {log,Level,Format,Args,Meta} | + {log,Level,StringOrReport,Meta}, + Level :: logger:level(), + Format :: io:format(), + Args :: list(term()), + StringOrReport :: unicode:chardata() | logger:report(), + Meta :: logger:metadata(). +log(RemoteLog) -> + Olp = persistent_term:get(?MODULE), + case logger_olp:get_pid(Olp) =:= self() of + true -> + %% This happens when the log event comes from the + %% emulator, and the group leader is on a remote node. + _ = handle_load(RemoteLog, no_state), + ok; + false -> + logger_olp:load(Olp, RemoteLog) + end. + +%% Called by supervisor +-spec start_link() -> {ok,pid(),logger_olp:olp_ref()} | {error,term()}. +start_link() -> + %% Notice that sync_mode is only used when logging to remote node, + %% i.e. when the log/2 API function is called. + %% + %% When receiving log events from the emulator or from a remote + %% node, the log event is sent as a message to this process, and + %% thus received directly in handle_info/2. This means that the + %% mode (async/sync/drop) is not read before the message is + %% sent. Thus sync mode is never entered, and drop mode is + %% implemented by setting the system_logger flag to undefined (see + %% notify/2) + %% + %% Burst limit is disabled, since this is only a proxy and we + %% don't want to limit bursts twice (here and in the handler). + logger_olp:start_link(?SERVER,?MODULE,[],logger:get_proxy_config()). + +%% Fun used for restarting this process after it has been killed due +%% to overload (must set overload_kill_enable=>true in opts) +restart() -> + case supervisor:start_child(logger_sup, child_spec()) of + {ok,_Pid,Olp} -> + {ok,Olp}; + {error,{Reason,Ch}} when is_tuple(Ch), element(1,Ch)==child -> + {error,Reason}; + Error -> + Error + end. + +%% Called internally and by logger_sup +child_spec() -> + Name = ?SERVER, + #{id => Name, + start => {?MODULE, start_link, []}, + restart => temporary, + shutdown => 2000, + type => worker, + modules => [?MODULE]}. + +get_default_config() -> + OlpDefault = logger_olp:get_default_opts(), + OlpDefault#{sync_mode_qlen=>500, + drop_mode_qlen=>1000, + flush_qlen=>5000, + burst_limit_enable=>false}. + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +init([]) -> + process_flag(trap_exit, true), + _ = erlang:system_flag(system_logger,self()), + persistent_term:put(?MODULE,logger_olp:get_ref()), + {ok,no_state}. + +%% Log event to send to the node where the group leader of it's client resides +handle_load({remote,Node,Log},State) -> + %% If the connection is overloaded (send_nosuspend returns false), + %% we drop the message. + _ = erlang:send_nosuspend({?SERVER,Node},Log), + State; +%% Log event to log on this node +handle_load({log,Level,Format,Args,Meta},State) -> + try_log([Level,Format,Args,Meta]), + State; +handle_load({log,Level,Report,Meta},State) -> + try_log([Level,Report,Meta]), + State. + +%% Log event sent to this process e.g. from the emulator - it is really load +handle_info(Log,State) when is_tuple(Log), element(1,Log)==log -> + {load,State}. + +terminate(overloaded, _State) -> + _ = erlang:system_flag(system_logger,undefined), + {ok,fun ?MODULE:restart/0}; +terminate(_Reason, _State) -> + _ = erlang:system_flag(system_logger,whereis(logger)), + ok. + +notify({mode_change,Mode0,Mode1},State) -> + _ = if Mode1=:=drop -> % entering drop mode + erlang:system_flag(system_logger,undefined); + Mode0=:=drop -> % leaving drop mode + erlang:system_flag(system_logger,self()); + true -> + ok + end, + ?LOG_INTERNAL(notice,"~w switched from ~w to ~w mode",[?MODULE,Mode0,Mode1]), + State; +notify({flushed,Flushed},State) -> + ?LOG_INTERNAL(notice, "~w flushed ~w log events",[?MODULE,Flushed]), + State; +notify(restart,State) -> + ?LOG_INTERNAL(notice, "~w restarted", [?MODULE]), + State; +notify(_Note,State) -> + State. + +%%%----------------------------------------------------------------- +%%% Internal functions +try_log(Args) -> + try apply(logger,log,Args) + catch C:R:S -> + ?LOG_INTERNAL(debug,[{?MODULE,log_failed}, + {log,Args}, + {reason,{C,R,S}}]) + end. diff --git a/lib/kernel/src/logger_server.erl b/lib/kernel/src/logger_server.erl index b7735dbcf7..722246e82c 100644 --- a/lib/kernel/src/logger_server.erl +++ b/lib/kernel/src/logger_server.erl @@ -22,8 +22,7 @@ -behaviour(gen_server). %% API --export([start_link/0, - add_handler/3, remove_handler/1, +-export([start_link/0, add_handler/3, remove_handler/1, add_filter/2, remove_filter/2, set_module_level/2, unset_module_level/0, unset_module_level/1, cache_module_level/1, @@ -43,7 +42,7 @@ -define(SERVER, logger). -define(LOGGER_SERVER_TAG, '$logger_cb_process'). --record(state, {tid, async_req, async_req_queue}). +-record(state, {tid, async_req, async_req_queue, remote_logger}). %%%=================================================================== %%% API @@ -155,6 +154,8 @@ init([]) -> process_flag(trap_exit, true), put(?LOGGER_SERVER_TAG,true), Tid = logger_config:new(?LOGGER_TABLE), + %% Store initial proxy config. logger_proxy reads config from here at startup. + logger_config:create(Tid,proxy,logger_proxy:get_default_config()), PrimaryConfig = maps:merge(default_config(primary), #{handlers=>[simple]}), logger_config:create(Tid,primary,PrimaryConfig), @@ -221,6 +222,24 @@ handle_call({add_filter,Id,Filter}, _From,#state{tid=Tid}=State) -> handle_call({remove_filter,Id,FilterId}, _From, #state{tid=Tid}=State) -> Reply = do_remove_filter(Tid,Id,FilterId), {reply,Reply,State}; +handle_call({change_config,SetOrUpd,proxy,Config0},_From,#state{tid=Tid}=State) -> + Default = + case SetOrUpd of + set -> + logger_proxy:get_default_config(); + update -> + {ok,OldConfig} = logger_config:get(Tid,proxy), + OldConfig + end, + Config = maps:merge(Default,Config0), + Reply = + case logger_olp:set_opts(logger_proxy,Config) of + ok -> + logger_config:set(Tid,proxy,Config); + Error -> + Error + end, + {reply,Reply,State}; handle_call({change_config,SetOrUpd,primary,Config0}, _From, #state{tid=Tid}=State) -> {ok,#{handlers:=Handlers}=OldConfig} = logger_config:get(Tid,primary), @@ -357,7 +376,7 @@ terminate(_Reason, _State) -> %%%=================================================================== %%% Internal functions %%%=================================================================== -call(Request) -> +call(Request) when is_tuple(Request) -> Action = element(1,Request), case get(?LOGGER_SERVER_TAG) of true when @@ -369,6 +388,7 @@ call(Request) -> gen_server:call(?SERVER,Request,?DEFAULT_LOGGER_CALL_TIMEOUT) end. + do_add_filter(Tid,Id,{FId,_} = Filter) -> case logger_config:get(Tid,Id) of {ok,Config} -> @@ -413,11 +433,13 @@ default_config(Id,Module) -> sanity_check(Owner,Key,Value) -> sanity_check_1(Owner,[{Key,Value}]). -sanity_check(HandlerId,Config) when is_map(Config) -> - sanity_check_1(HandlerId,maps:to_list(Config)); +sanity_check(Owner,Config) when is_map(Config) -> + sanity_check_1(Owner,maps:to_list(Config)); sanity_check(_,Config) -> {error,{invalid_config,Config}}. +sanity_check_1(proxy,_Config) -> + ok; % Details are checked by logger_olp:set_opts/2 sanity_check_1(Owner,Config) when is_list(Config) -> try Type = get_type(Owner), diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl index 63d1dbaba2..0669164bb6 100644 --- a/lib/kernel/src/logger_std_h.erl +++ b/lib/kernel/src/logger_std_h.erl @@ -26,7 +26,7 @@ -include_lib("kernel/include/file.hrl"). %% API --export([info/1, filesync/1, reset/1]). +-export([filesync/1]). %% logger_h_common callbacks -export([init/2, check_config/4, reset_state/2, @@ -36,6 +36,8 @@ -export([log/2, adding_handler/1, removing_handler/1, changing_config/3, filter_config/1]). +-define(DEFAULT_CALL_TIMEOUT, 5000). + %%%=================================================================== %%% API %%%=================================================================== @@ -49,25 +51,6 @@ filesync(Name) -> logger_h_common:filesync(?MODULE,Name). -%%%----------------------------------------------------------------- -%%% --spec info(Name) -> Info | {error,Reason} when - Name :: atom(), - Info :: term(), - Reason :: handler_busy | {badarg,term()}. - -info(Name) -> - logger_h_common:info(?MODULE,Name). - -%%%----------------------------------------------------------------- -%%% --spec reset(Name) -> ok | {error,Reason} when - Name :: atom(), - Reason :: handler_busy | {badarg,term()}. - -reset(Name) -> - logger_h_common:reset(?MODULE,Name). - %%%=================================================================== %%% logger callbacks - just forward to logger_h_common %%%=================================================================== diff --git a/lib/kernel/src/logger_sup.erl b/lib/kernel/src/logger_sup.erl index 3d6f482e20..9ea8558a16 100644 --- a/lib/kernel/src/logger_sup.erl +++ b/lib/kernel/src/logger_sup.erl @@ -50,7 +50,9 @@ init([]) -> start => {logger_handler_watcher, start_link, []}, shutdown => brutal_kill}, - {ok, {SupFlags, [Watcher]}}. + Proxy = logger_proxy:child_spec(), + + {ok, {SupFlags, [Watcher,Proxy]}}. %%%=================================================================== %%% Internal functions diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl index 14fe21e9de..4f9d7b3e5c 100644 --- a/lib/kernel/src/seq_trace.erl +++ b/lib/kernel/src/seq_trace.erl @@ -98,7 +98,7 @@ print(Label, Term) -> -spec reset_trace() -> 'true'. reset_trace() -> - erlang:system_flag(1, 0). + erlang:system_flag(reset_seq_trace, true). %% reset_trace(Pid) -> % this might be a useful function too diff --git a/lib/kernel/src/standard_error.erl b/lib/kernel/src/standard_error.erl index 5d649e5f94..ef5b532960 100644 --- a/lib/kernel/src/standard_error.erl +++ b/lib/kernel/src/standard_error.erl @@ -27,7 +27,8 @@ -define(PROCNAME_SUP, standard_error_sup). %% Defines for control ops --define(CTRL_OP_GET_WINSIZE,100). +-define(ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER, 16#018b0900). +-define(CTRL_OP_GET_WINSIZE, (100 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)). %% %% The basic server and start-up. diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl index 872e63ab53..0c9e1ea303 100644 --- a/lib/kernel/src/user.erl +++ b/lib/kernel/src/user.erl @@ -28,7 +28,8 @@ -define(NAME, user). %% Defines for control ops --define(CTRL_OP_GET_WINSIZE,100). +-define(ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER, 16#018b0900). +-define(CTRL_OP_GET_WINSIZE, (100 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)). %% %% The basic server and start-up. diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl index 9f914aa222..08286dd476 100644 --- a/lib/kernel/src/user_drv.erl +++ b/lib/kernel/src/user_drv.erl @@ -32,9 +32,10 @@ -define(OP_BEEP,4). -define(OP_PUTC_SYNC,5). % Control op --define(CTRL_OP_GET_WINSIZE,100). --define(CTRL_OP_GET_UNICODE_STATE,101). --define(CTRL_OP_SET_UNICODE_STATE,102). +-define(ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER, 16#018b0900). +-define(CTRL_OP_GET_WINSIZE, (100 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)). +-define(CTRL_OP_GET_UNICODE_STATE, (101 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)). +-define(CTRL_OP_SET_UNICODE_STATE, (102 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)). %% start() %% start(ArgumentList) diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 4a86265a4a..8a6ffe7e72 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -76,8 +76,11 @@ MODULES= \ logger_filters_SUITE \ logger_formatter_SUITE \ logger_legacy_SUITE \ + logger_olp_SUITE \ + logger_proxy_SUITE \ logger_simple_h_SUITE \ logger_std_h_SUITE \ + logger_stress_SUITE \ logger_test_lib \ os_SUITE \ pg2_SUITE \ diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 244bd7e2a0..52edfaee29 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -53,7 +53,7 @@ active_once_closed/1, send_timeout/1, send_timeout_active/1, otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1, wrapping_oct/0, wrapping_oct/1, otp_9389/1, otp_13939/1, - otp_12242/1]). + otp_12242/1, delay_send_error/1]). %% Internal exports. -export([sender/3, not_owner/1, passive_sockets_server/2, priority_server/1, @@ -97,7 +97,7 @@ all() -> active_once_closed, send_timeout, send_timeout_active, otp_7731, wrapping_oct, zombie_sockets, otp_7816, otp_8102, otp_9389, - otp_12242]. + otp_12242, delay_send_error]. groups() -> []. @@ -3427,3 +3427,32 @@ otp_12242(Addr) when tuple_size(Addr) =:= 4 -> wait(Mref) -> receive {'DOWN',Mref,_,_,Reason} -> Reason end. + +%% OTP-15536 +%% Test that send error works correctly for delay_send +delay_send_error(Config) -> + {ok, LS} = gen_tcp:listen(0, [{reuseaddr, true}, {packet, 1}, {active, false}]), + {ok,{{0,0,0,0},PortNum}}=inet:sockname(LS), + P = spawn_link( + fun() -> + {ok, S} = gen_tcp:accept(LS), + receive die -> gen_tcp:close(S) end + end), + erlang:monitor(process, P), + {ok, S} = gen_tcp:connect("localhost", PortNum, + [{packet, 1}, {active, false}, {delay_send, true}]), + + %% Do a couple of sends first to see that it works + ok = gen_tcp:send(S, "hello"), + ok = gen_tcp:send(S, "hello"), + ok = gen_tcp:send(S, "hello"), + + %% Make the receiver close + P ! die, + receive _Down -> ok end, + + ok = gen_tcp:send(S, "hello"), + timer:sleep(500), %% Sleep in order for delay_send to have time to trigger + + %% This used to result in a double free + {error, closed} = gen_tcp:send(S, "hello"). diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl index 6a006cdc01..4f90260f98 100644 --- a/lib/kernel/test/init_SUITE.erl +++ b/lib/kernel/test/init_SUITE.erl @@ -295,7 +295,7 @@ is_real_system(KernelVsn, StdlibVsn) -> %% before restart. %% ------------------------------------------------ many_restarts() -> - [{timetrap,{minutes,8}}]. + [{timetrap,{minutes,16}}]. many_restarts(Config) when is_list(Config) -> {ok, Node} = loose_node:start(init_test, "", ?DEFAULT_TIMEOUT_SEC), @@ -315,7 +315,7 @@ loop_restart(N,Node,EHPid) -> loose_node:stop(Node), ct:fail(not_stopping) end, - ok = wait_for(30, Node, EHPid), + ok = wait_for(60, Node, EHPid), loop_restart(N-1,Node,rpc:call(Node,erlang,whereis,[logger])). wait_for(0,Node,_) -> @@ -367,7 +367,8 @@ restart(Config) when is_list(Config) -> SysProcs0 = rpc:call(Node, ?MODULE, find_system_processes, []), io:format("SysProcs0=~p~n", [SysProcs0]), [InitPid, PurgerPid, LitCollectorPid, - DirtySigNPid, DirtySigHPid, DirtySigMPid] = SysProcs0, + DirtySigNPid, DirtySigHPid, DirtySigMPid, + PrimFilePid] = SysProcs0, InitPid = rpc:call(Node, erlang, whereis, [init]), PurgerPid = rpc:call(Node, erlang, whereis, [erts_code_purger]), Procs = rpc:call(Node, erlang, processes, []), @@ -385,7 +386,8 @@ restart(Config) when is_list(Config) -> SysProcs1 = rpc:call(Node, ?MODULE, find_system_processes, []), io:format("SysProcs1=~p~n", [SysProcs1]), [InitPid1, PurgerPid1, LitCollectorPid1, - DirtySigNPid1, DirtySigHPid1, DirtySigMPid1] = SysProcs1, + DirtySigNPid1, DirtySigHPid1, DirtySigMPid1, + PrimFilePid1] = SysProcs1, %% Still the same init process! InitPid1 = rpc:call(Node, erlang, whereis, [init]), @@ -411,6 +413,10 @@ restart(Config) when is_list(Config) -> DirtySigMP = pid_to_list(DirtySigMPid), DirtySigMP = pid_to_list(DirtySigMPid1), + %% and same prim_file helper process! + PrimFileP = pid_to_list(PrimFilePid), + PrimFileP = pid_to_list(PrimFilePid1), + NewProcs0 = rpc:call(Node, erlang, processes, []), NewProcs = NewProcs0 -- SysProcs1, case check_processes(NewProcs, MaxPid) of @@ -437,7 +443,8 @@ restart(Config) when is_list(Config) -> literal_collector, dirty_sig_handler_normal, dirty_sig_handler_high, - dirty_sig_handler_max}). + dirty_sig_handler_max, + prim_file}). find_system_processes() -> find_system_procs(processes(), #sys_procs{}). @@ -448,7 +455,8 @@ find_system_procs([], SysProcs) -> SysProcs#sys_procs.literal_collector, SysProcs#sys_procs.dirty_sig_handler_normal, SysProcs#sys_procs.dirty_sig_handler_high, - SysProcs#sys_procs.dirty_sig_handler_max]; + SysProcs#sys_procs.dirty_sig_handler_max, + SysProcs#sys_procs.prim_file]; find_system_procs([P|Ps], SysProcs) -> case process_info(P, [initial_call, priority]) of [{initial_call,{otp_ring0,start,2}},_] -> @@ -472,6 +480,9 @@ find_system_procs([P|Ps], SysProcs) -> {priority,max}] -> undefined = SysProcs#sys_procs.dirty_sig_handler_max, find_system_procs(Ps, SysProcs#sys_procs{dirty_sig_handler_max = P}); + [{initial_call,{prim_file,start,0}},_] -> + undefined = SysProcs#sys_procs.prim_file, + find_system_procs(Ps, SysProcs#sys_procs{prim_file = P}); _ -> find_system_procs(Ps, SysProcs) end. diff --git a/lib/kernel/test/kernel_bench.spec b/lib/kernel/test/kernel_bench.spec index 4de133f21b..898ceb59e0 100644 --- a/lib/kernel/test/kernel_bench.spec +++ b/lib/kernel/test/kernel_bench.spec @@ -1,2 +1,3 @@ {groups,"../kernel_test",zlib_SUITE,[bench]}. {groups,"../kernel_test",file_SUITE,[bench]}. +{suites,"../kernel_test",[logger_stress_SUITE]}. diff --git a/lib/kernel/test/logger.cover b/lib/kernel/test/logger.cover index 960bc0abff..9691aa295e 100644 --- a/lib/kernel/test/logger.cover +++ b/lib/kernel/test/logger.cover @@ -4,9 +4,12 @@ logger_backend, logger_config, logger_disk_log_h, - logger_h_common, logger_filters, logger_formatter, + logger_handler_watcher, + logger_h_common, + logger_olp, + logger_proxy, logger_server, logger_simple_h, logger_std_h, diff --git a/lib/kernel/test/logger.spec b/lib/kernel/test/logger.spec index 1ab90b3e93..3aec37951d 100644 --- a/lib/kernel/test/logger.spec +++ b/lib/kernel/test/logger.spec @@ -7,5 +7,7 @@ logger_filters_SUITE, logger_formatter_SUITE, logger_legacy_SUITE, + logger_olp_SUITE, + logger_proxy_SUITE, logger_simple_h_SUITE, logger_std_h_SUITE]}. diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl index 87b8250781..9bbec42de8 100644 --- a/lib/kernel/test/logger_disk_log_h_SUITE.erl +++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl @@ -24,6 +24,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/logger.hrl"). -include_lib("kernel/src/logger_internal.hrl"). +-include_lib("kernel/src/logger_olp.hrl"). -include_lib("kernel/src/logger_h_common.hrl"). -include_lib("stdlib/include/ms_transform.hrl"). -include_lib("kernel/include/file.hrl"). @@ -97,7 +98,6 @@ all() -> formatter_fail, config_fail, bad_input, - info_and_reset, reconfig, sync, disk_log_full, @@ -306,9 +306,9 @@ logging(cleanup, _Config) -> filter_config(_Config) -> ok = logger:add_handler(?MODULE,logger_disk_log_h,#{}), {ok,#{config:=HConfig}=Config} = logger:get_handler_config(?MODULE), - HConfig = maps:without([handler_pid,mode_tab],HConfig), + HConfig = maps:without([olp],HConfig), - FakeFullHConfig = HConfig#{handler_pid=>self(),mode_tab=>erlang:make_ref()}, + FakeFullHConfig = HConfig#{olp=>{regname,self(),erlang:make_ref()}}, #{config:=HConfig} = logger_disk_log_h:filter_config(Config#{config=>FakeFullHConfig}), ok. @@ -351,9 +351,7 @@ errors(Config) -> %% Read-only fields may (accidentially) be included in the change, %% but it won't take effect {ok,C} = logger:get_handler_config(Name1), - ok = logger:set_handler_config(Name1,config, - #{handler_pid=>self(), - mode_tab=>erlang:make_ref()}), + ok = logger:set_handler_config(Name1,config,#{olp=>dummyvalue}), {ok,C} = logger:get_handler_config(Name1), @@ -419,19 +417,16 @@ config_fail(_Config) -> filter_default=>log, formatter=>{?MODULE,self()}}), - {error,{handler_not_added,{invalid_config,logger_disk_log_h, - {invalid_levels,#{drop_mode_qlen:=1}}}}} = + {error,{handler_not_added,{invalid_olp_levels,#{drop_mode_qlen:=1}}}} = logger:add_handler(?MODULE,logger_disk_log_h, #{config => #{drop_mode_qlen=>1}}), - {error,{handler_not_added,{invalid_config,logger_disk_log_h, - {invalid_levels,#{sync_mode_qlen:=43, - drop_mode_qlen:=42}}}}} = + {error,{handler_not_added,{invalid_olp_levels,#{sync_mode_qlen:=43, + drop_mode_qlen:=42}}}} = logger:add_handler(?MODULE,logger_disk_log_h, #{config => #{sync_mode_qlen=>43, drop_mode_qlen=>42}}), - {error,{handler_not_added,{invalid_config,logger_disk_log_h, - {invalid_levels,#{drop_mode_qlen:=43, - flush_qlen:=42}}}}} = + {error,{handler_not_added,{invalid_olp_levels,#{drop_mode_qlen:=43, + flush_qlen:=42}}}} = logger:add_handler(?MODULE,logger_disk_log_h, #{config => #{drop_mode_qlen=>43, flush_qlen=>42}}), @@ -445,7 +440,7 @@ config_fail(_Config) -> #{max_no_files=>2}), %% incorrect values of OP params {ok,#{config := HConfig}} = logger:get_handler_config(?MODULE), - {error,{invalid_config,logger_disk_log_h,{invalid_levels,_}}} = + {error,{invalid_olp_levels,_}} = logger:update_handler_config(?MODULE,config, HConfig#{sync_mode_qlen=>100, flush_qlen=>99}), @@ -459,18 +454,7 @@ config_fail(cleanup,_Config) -> bad_input(_Config) -> {error,{badarg,{filesync,["BadType"]}}} = - logger_disk_log_h:filesync("BadType"), - {error,{badarg,{info,["BadType"]}}} = logger_disk_log_h:info("BadType"), - {error,{badarg,{reset,["BadType"]}}} = logger_disk_log_h:reset("BadType"). - -info_and_reset(_Config) -> - ok = logger:add_handler(?MODULE,logger_disk_log_h, - #{filter_default=>log, - formatter=>{?MODULE,self()}}), - #{id := ?MODULE} = logger_disk_log_h:info(?MODULE), - ok = logger_disk_log_h:reset(?MODULE). -info_and_reset(cleanup,_Config) -> - logger:remove_handler(?MODULE). + logger_disk_log_h:filesync("BadType"). reconfig(Config) -> Dir = ?config(priv_dir,Config), @@ -479,7 +463,7 @@ reconfig(Config) -> #{filter_default=>log, filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), formatter=>{?MODULE,self()}}), - #{id := ?MODULE, + #{%id := ?MODULE, sync_mode_qlen := ?SYNC_MODE_QLEN, drop_mode_qlen := ?DROP_MODE_QLEN, flush_qlen := ?FLUSH_QLEN, @@ -490,13 +474,14 @@ reconfig(Config) -> overload_kill_qlen := ?OVERLOAD_KILL_QLEN, overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE, overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER, - filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL, - handler_state := - #{log_opts := #{type := ?DISK_LOG_TYPE, - max_no_files := ?DISK_LOG_MAX_NO_FILES, - max_no_bytes := ?DISK_LOG_MAX_NO_BYTES, - file := DiskLogFile}}} = - logger_disk_log_h:info(?MODULE), + cb_state := + #{handler_state := + #{log_opts := #{type := ?DISK_LOG_TYPE, + max_no_files := ?DISK_LOG_MAX_NO_FILES, + max_no_bytes := ?DISK_LOG_MAX_NO_BYTES, + file := DiskLogFile}}, + filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL}} = + logger_olp:info(h_proc_name()), {ok,#{config := #{sync_mode_qlen := ?SYNC_MODE_QLEN, drop_mode_qlen := ?DROP_MODE_QLEN, @@ -527,7 +512,7 @@ reconfig(Config) -> overload_kill_restart_after => infinity, filesync_repeat_interval => no_repeat}, ok = logger:set_handler_config(?MODULE, config, HConfig1), - #{id := ?MODULE, + #{%id := ?MODULE, sync_mode_qlen := 1, drop_mode_qlen := 2, flush_qlen := 3, @@ -538,8 +523,8 @@ reconfig(Config) -> overload_kill_qlen := 100000, overload_kill_mem_size := 10000000, overload_kill_restart_after := infinity, - filesync_repeat_interval := no_repeat} = - logger_disk_log_h:info(?MODULE), + cb_state := #{filesync_repeat_interval := no_repeat}} = + logger_olp:info(h_proc_name()), {ok,#{config:=HConfig1}} = logger:get_handler_config(?MODULE), ok = logger:update_handler_config(?MODULE, config, @@ -577,12 +562,13 @@ reconfig(Config) -> max_no_files => 1, max_no_bytes => 1024, file => File}}), - #{handler_state := - #{log_opts := #{type := halt, - max_no_files := 1, - max_no_bytes := 1024, - file := File}}} = - logger_disk_log_h:info(?MODULE), + #{cb_state := + #{handler_state := + #{log_opts := #{type := halt, + max_no_files := 1, + max_no_bytes := 1024, + file := File}}}} = + logger_olp:info(h_proc_name()), {ok,#{config := #{type := halt, max_no_files := 1, @@ -650,13 +636,8 @@ sync(Config) -> {ok,#{config := HConfig}} = logger:get_handler_config(?MODULE), HConfig1 = HConfig#{filesync_repeat_interval => no_repeat}, ok = logger:update_handler_config(?MODULE, config, HConfig1), - no_repeat = maps:get(filesync_repeat_interval, - logger_disk_log_h:info(?MODULE)), - %% The following timer is to make sure the time from last log - %% ("first") to next ("second") is long enough, so the a flush is - %% triggered by the idle timeout between "fourth" and "fifth". - timer:sleep(?IDLE_DETECT_TIME_MSEC*2), + maps:get(cb_state,logger_olp:info(h_proc_name()))), start_tracer([{logger_disk_log_h,disk_log_write,3}, {disk_log,sync,1}], @@ -666,10 +647,10 @@ sync(Config) -> {disk_log,sync}]), logger:notice("second", ?domain), - timer:sleep(?IDLE_DETECT_TIME_MSEC*2), + timer:sleep(?IDLE_DETECT_TIME*2), logger:notice("third", ?domain), %% wait for automatic disk_log_sync - check_tracer(?IDLE_DETECT_TIME_MSEC*2), + check_tracer(?IDLE_DETECT_TIME*2), try_read_file(Log, {ok,<<"first\nsecond\nthird\n">>}, 1000), @@ -678,14 +659,15 @@ sync(Config) -> WaitT = 4500, OneSync = {logger_h_common,handle_cast,repeated_filesync}, %% receive 1 repeated_filesync per sec - start_tracer([{logger_h_common,handle_cast,2}], + start_tracer([{{logger_h_common,handle_cast,2}, + [{[repeated_filesync,'_'],[],[{message,{caller}}]}]}], [OneSync || _ <- lists:seq(1, trunc(WaitT/SyncInt))]), HConfig2 = HConfig#{filesync_repeat_interval => SyncInt}, ok = logger:update_handler_config(?MODULE, config, HConfig2), SyncInt = maps:get(filesync_repeat_interval, - logger_disk_log_h:info(?MODULE)), + maps:get(cb_state,logger_olp:info(h_proc_name()))), timer:sleep(WaitT), HConfig3 = HConfig#{filesync_repeat_interval => no_repeat}, ok = logger:update_handler_config(?MODULE, config, HConfig3), @@ -803,7 +785,7 @@ disk_log_full(cleanup, _Config) -> dbg:stop_clear(), logger:remove_handler(?MODULE). -disk_log_events(Config) -> +disk_log_events(_Config) -> Node = node(), Log = ?MODULE, ok = logger:add_handler(?MODULE, @@ -860,10 +842,12 @@ write_failure(Config) -> rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]), rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]), rpc:call(Node, ?MODULE, set_result, [disk_log_write,ok]), - HState = rpc:call(Node, logger_disk_log_h, info, [?STANDARD_HANDLER]), - ct:pal("LogOpts = ~p", [LogOpts = maps:get(log_opts, - maps:get(handler_state,HState))]), - + HState = rpc:call(Node, logger_olp, info, [h_proc_name(?STANDARD_HANDLER)]), + LogOpts = maps:get(log_opts, + maps:get(handler_state, + maps:get(cb_state,HState))), + ct:pal("LogOpts = ~p", [LogOpts]), + %% ?check and ?check_no_log in this test only check for internal log events ok = log_on_remote_node(Node, "Logged1"), rpc:call(Node, logger_disk_log_h, filesync, [?STANDARD_HANDLER]), @@ -914,15 +898,16 @@ sync_failure(Config) -> rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]), rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]), rpc:call(Node, ?MODULE, set_result, [disk_log_sync,ok]), - HState = rpc:call(Node, logger_disk_log_h, info, [?STANDARD_HANDLER]), - LogOpts = maps:get(log_opts, maps:get(handler_state,HState)), + HState = rpc:call(Node, logger_olp, info, [h_proc_name(?STANDARD_HANDLER)]), + LogOpts = maps:get(log_opts, maps:get(handler_state, + maps:get(cb_state,HState))), SyncInt = 500, ok = rpc:call(Node, logger, update_handler_config, [?STANDARD_HANDLER, config, #{filesync_repeat_interval => SyncInt}]), - Info = rpc:call(Node, logger_disk_log_h, info, [?STANDARD_HANDLER]), - SyncInt = maps:get(filesync_repeat_interval, Info), + Info = rpc:call(Node, logger_olp, info, [h_proc_name(?STANDARD_HANDLER)]), + SyncInt = maps:get(filesync_repeat_interval, maps:get(cb_state, Info)), ok = log_on_remote_node(Node, "Logged1"), ?check_no_log, @@ -1198,7 +1183,7 @@ qlen_kill_new(Config) -> receive {'DOWN', MRef, _, _, Info} -> case Info of - {shutdown,{overloaded,?MODULE,QLen,Mem}} -> + {shutdown,{overloaded,QLen,Mem}} -> ct:pal("Terminated with qlen = ~w, mem = ~w", [QLen,Mem]); killed -> ct:pal("Slow shutdown, handler process was killed!", []) @@ -1208,7 +1193,7 @@ qlen_kill_new(Config) -> ok after 5000 -> - Info = logger_disk_log_h:info(?MODULE), + Info = logger_olp:info(h_proc_name()), ct:pal("Handler state = ~p", [Info]), ct:fail("Handler not dead! It should not have survived this!") end. @@ -1235,7 +1220,7 @@ mem_kill_new(Config) -> receive {'DOWN', MRef, _, _, Info} -> case Info of - {shutdown,{overloaded,?MODULE,QLen,Mem}} -> + {shutdown,{overloaded,QLen,Mem}} -> ct:pal("Terminated with qlen = ~w, mem = ~w", [QLen,Mem]); killed -> ct:pal("Slow shutdown, handler process was killed!", []) @@ -1245,7 +1230,7 @@ mem_kill_new(Config) -> ok after 5000 -> - Info = logger_disk_log_h:info(?MODULE), + Info = logger_olp:info(h_proc_name()), ct:pal("Handler state = ~p", [Info]), ct:fail("Handler not dead! It should not have survived this!") end. @@ -1271,7 +1256,7 @@ restart_after(Config) -> ok after 5000 -> - Info1 = logger_std_h:info(?MODULE), + Info1 = logger_olp:info(h_proc_name()), ct:pal("Handler state = ~p", [Info1]), ct:fail("Handler not dead! It should not have survived this!") end, @@ -1295,7 +1280,7 @@ restart_after(Config) -> ok after 5000 -> - Info2 = logger_std_h:info(?MODULE), + Info2 = logger_olp:info(h_proc_name()), ct:pal("Handler state = ~p", [Info2]), ct:fail("Handler not dead! It should not have survived this!") end, @@ -1316,11 +1301,15 @@ handler_requests_under_load(Config) -> flush_qlen => 2000, burst_limit_enable => false}}, ok = logger:update_handler_config(?MODULE, NewHConfig), - Pid = spawn_link(fun() -> send_requests(?MODULE, 1, [{filesync,[]}, - {info,[]}, - {reset,[]}, - {change_config,[]}]) - end), + Pid = spawn_link( + fun() -> send_requests(1,[{logger_disk_log_h,filesync,[?MODULE],[]}, + {logger_olp,info,[h_proc_name()],[]}, + {logger_olp,reset,[h_proc_name()],[]}, + {logger,update_handler_config, + [?MODULE, config, + #{overload_kill_enable => false}], + []}]) + end), Procs = 100, Sent = Procs * send_burst({n,5000}, {spawn,Procs,10}, {chars,79}, notice), Pid ! {self(),finish}, @@ -1332,29 +1321,22 @@ handler_requests_under_load(Config) -> [E || E <- Res, is_tuple(E) andalso (element(1,E) == error)] end, - Errors = [{Req,FindError(Res)} || {Req,Res} <- ReqResult], - NoOfReqs = lists:foldl(fun({_,Res}, N) -> N + length(Res) end, 0, ReqResult), + Errors = [{Func,FindError(Res)} || {_,Func,_,Res} <- ReqResult], + NoOfReqs = lists:foldl(fun({_,_,_,Res}, N) -> N + length(Res) end, + 0, ReqResult), ct:pal("~w requests made. Errors: ~n~p", [NoOfReqs,Errors]), ok = file_delete(Log). handler_requests_under_load(cleanup, _Config) -> ok = stop_handler(?MODULE). -send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) -> +send_requests(TO, Reqs = [{Mod,Func,Args,Res}|Rs]) -> receive {From,finish} -> From ! {self(),Reqs} after TO -> - Result = - case Req of - change_config -> - logger:update_handler_config(HName, logger_disk_log_h, - #{overload_kill_enable => - false}); - Func -> - logger_disk_log_h:Func(HName) - end, - send_requests(HName, TO, Rs ++ [{Req,[Result|Res]}]) + Result = apply(Mod,Func,Args), + send_requests(TO, Rs ++ [{Mod,Func,Args,[Result|Res]}]) end. %%%----------------------------------------------------------------- @@ -1472,15 +1454,6 @@ format(Msg,Tag) -> erlang:display(Error), exit(Error). -remove(Handler, LogName) -> - logger_disk_log_h:remove(Handler, LogName), - HState = #{log_names := Logs} = logger_disk_log_h:info(), - false = maps:is_key(LogName, HState), - false = lists:member(LogName, Logs), - false = logger_config:exist(?LOGGER_TABLE, LogName), - {error,no_such_log} = disk_log:info(LogName), - ok. - start_and_add(Name, Config, LogOpts) -> HConfig = maps:get(config, Config, #{}), HConfig1 = maps:merge(HConfig, LogOpts), @@ -1607,7 +1580,9 @@ start_tracer(Trace,Expected) -> ok. tpl([{M,F,A}|Trace]) -> - {ok,Match} = dbg:tpl(M,F,A,c), + tpl([{{M,F,A},c}|Trace]); +tpl([{{M,F,A},MS}|Trace]) -> + {ok,Match} = dbg:tpl(M,F,A,MS), case lists:keyfind(matched,1,Match) of {_,_,1} -> ok; diff --git a/lib/kernel/test/logger_env_var_SUITE.erl b/lib/kernel/test/logger_env_var_SUITE.erl index e8d1a313dc..9d2ad11be8 100644 --- a/lib/kernel/test/logger_env_var_SUITE.erl +++ b/lib/kernel/test/logger_env_var_SUITE.erl @@ -59,7 +59,8 @@ groups() -> logger_undefined, logger_many_handlers_default_first, logger_many_handlers_default_last, - logger_many_handlers_default_last_broken_filter + logger_many_handlers_default_last_broken_filter, + logger_proxy ]}, {bad,[],[bad_error_logger, bad_level, @@ -541,6 +542,19 @@ logger_many_handlers(Config, Env, LogErr, LogInfo, NumProgress) -> ok. +logger_proxy(Config) -> + %% assume current node runs with default settings + DefOpts = logger_olp:get_opts(logger_proxy), + {ok,_,Node} = setup(Config, + [{logger,[{proxy,#{sync_mode_qlen=>0, + drop_mode_qlen=>2}}]}]), + Expected = DefOpts#{sync_mode_qlen:=0, + drop_mode_qlen:=2}, + Expected = rpc:call(Node,logger_olp,get_opts,[logger_proxy]), + Expected = rpc:call(Node,logger,get_proxy_config,[]), + + ok. + sasl_compatible_false(Config) -> Log = file(Config,?FUNCTION_NAME), {ok,_,Node} = setup(Config, diff --git a/lib/kernel/test/logger_olp_SUITE.erl b/lib/kernel/test/logger_olp_SUITE.erl new file mode 100644 index 0000000000..ea3eec89f5 --- /dev/null +++ b/lib/kernel/test/logger_olp_SUITE.erl @@ -0,0 +1,90 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(logger_olp_SUITE). + +-compile(export_all). + +-include_lib("kernel/src/logger_olp.hrl"). + +suite() -> + [{timetrap,{seconds,30}}]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_Group, Config) -> + Config. + +end_per_group(_Group, _Config) -> + ok. + +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(Case, Config) -> + try apply(?MODULE,Case,[cleanup,Config]) + catch error:undef -> ok + end, + ok. + +groups() -> + []. + +all() -> + [idle_timer]. + +%%%----------------------------------------------------------------- +%%% Test cases +idle_timer(_Config) -> + {ok,_Pid,Olp} = logger_olp:start_link(?MODULE,?MODULE,self(),#{}), + [logger_olp:load(Olp,{msg,N}) || N<-lists:seq(1,3)], + timer:sleep(?IDLE_DETECT_TIME*2), + [{load,{msg,1}}, + {load,{msg,2}}, + {load,{msg,3}}, + {notify,idle}] = test_server:messages_get(), + logger_olp:cast(Olp,hello), + timer:sleep(?IDLE_DETECT_TIME*2), + [{cast,hello}] = test_server:messages_get(), + ok. +idle_timer(cleanup,_Config) -> + unlink(whereis(?MODULE)), + logger_olp:stop(?MODULE), + ok. + +%%%----------------------------------------------------------------- +%%% Olp callbacks +init(P) -> + {ok,P}. + +handle_load(M,P) -> + P ! {load,M}, + P. + +handle_cast(M,P) -> + P ! {cast,M}, + {noreply,P}. + +notify(N,P) -> + P ! {notify,N}, + P. diff --git a/lib/kernel/test/logger_proxy_SUITE.erl b/lib/kernel/test/logger_proxy_SUITE.erl new file mode 100644 index 0000000000..777531e4ed --- /dev/null +++ b/lib/kernel/test/logger_proxy_SUITE.erl @@ -0,0 +1,274 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(logger_proxy_SUITE). + +-compile(export_all). + +%% -include_lib("common_test/include/ct.hrl"). +%% -include_lib("kernel/include/logger.hrl"). +%% -include_lib("kernel/src/logger_internal.hrl"). + +%% -define(str,"Log from "++atom_to_list(?FUNCTION_NAME)++ +%% ":"++integer_to_list(?LINE)). +%% -define(map_rep,#{function=>?FUNCTION_NAME, line=>?LINE}). +%% -define(keyval_rep,[{function,?FUNCTION_NAME}, {line,?LINE}]). + +%% -define(MY_LOC(N),#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY}, +%% file=>?FILE, line=>?LINE-N}). + +%% -define(TRY(X), my_try(fun() -> X end)). + + +-define(HNAME,list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME]))). +-define(LOC,#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY},line=>?LINE}). +-define(ENSURE_TIME,5000). + +suite() -> + [{timetrap,{seconds,30}}, + {ct_hooks,[logger_test_lib]}]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_Group, Config) -> + Config. + +end_per_group(_Group, _Config) -> + ok. + +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(Case, Config) -> + try apply(?MODULE,Case,[cleanup,Config]) + catch error:undef -> ok + end, + ok. + +groups() -> + []. + +all() -> + [basic, + emulator, + remote, + remote_emulator, + config, + restart_after, + terminate]. + +%%%----------------------------------------------------------------- +%%% Test cases +basic(_Config) -> + ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}), + logger_proxy ! {log,notice,"Log from: ~p; ~p",[?FUNCTION_NAME,?LINE],L1=?LOC}, + ok = ensure(L1), + logger_proxy ! {log,notice,[{test_case,?FUNCTION_NAME},{line,?LINE}],L2=?LOC}, + ok = ensure(L2), + logger_proxy:log({remote,node(),{log,notice, + "Log from: ~p; ~p", + [?FUNCTION_NAME,?LINE], + L3=?LOC}}), + ok = ensure(L3), + logger_proxy:log({remote,node(),{log,notice, + [{test_case,?FUNCTION_NAME}, + {line,?LINE}], + L4=?LOC}}), + ok = ensure(L4), + ok. +basic(cleanup,_Config) -> + ok = logger:remove_handler(?HNAME). + +emulator(_Config) -> + ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}), + Pid = spawn(fun() -> erlang:error(some_reason) end), + ok = ensure(#{pid=>Pid}), + ok. +emulator(cleanup,_Config) -> + ok = logger:remove_handler(?HNAME). + +remote(Config) -> + {ok,_,Node} = logger_test_lib:setup(Config,[{logger,[{proxy,#{}}]}]), + ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}), + L1 = ?LOC, spawn(Node,fun() -> logger:notice("Log from ~p; ~p",[?FUNCTION_NAME,?LINE],L1) end), + ok = ensure(L1), + L2 = ?LOC, spawn(Node,fun() -> logger:notice([{test_case,?FUNCTION_NAME},{line,?LINE}],L2) end), + ok = ensure(L2), + ok. +remote(cleanup,_Config) -> + ok = logger:remove_handler(?HNAME). + +remote_emulator(Config) -> + {ok,_,Node} = logger_test_lib:setup(Config,[{logger,[{proxy,#{}}]}]), + ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}), + Pid = spawn(Node,fun() -> erlang:error(some_reason) end), + ok = ensure(#{pid=>Pid}), + ok. +remote_emulator(cleanup,_Config) -> + ok = logger:remove_handler(?HNAME). + +config(_Config) -> + C1 = #{sync_mode_qlen:=SQ, + drop_mode_qlen:=DQ} = logger:get_proxy_config(), + C1 = logger_olp:get_opts(logger_proxy), + + %% Update the existing config with these two values + SQ1 = SQ+1, + DQ1 = DQ+1, + ok = logger:update_proxy_config(#{sync_mode_qlen=>SQ1, + drop_mode_qlen=>DQ1}), + C2 = logger:get_proxy_config(), % reads from ets table + C2 = logger_olp:get_opts(logger_proxy), % ensure consistency with process opts + C2 = C1#{sync_mode_qlen:=SQ1, + drop_mode_qlen:=DQ1}, + + %% Update the existing again with only one value + SQ2 = SQ+2, + ok = logger:update_proxy_config(#{sync_mode_qlen=>SQ2}), + C3 = logger:get_proxy_config(), + C3 = logger_olp:get_opts(logger_proxy), + C3 = C2#{sync_mode_qlen:=SQ2}, + + %% Set the config, i.e. merge with defaults + ok = logger:set_proxy_config(#{sync_mode_qlen=>SQ1}), + C4 = logger:get_proxy_config(), + C4 = logger_olp:get_opts(logger_proxy), + C4 = C1#{sync_mode_qlen:=SQ1}, + + %% Reset to default + ok = logger:set_proxy_config(#{}), + C5 = logger:get_proxy_config(), + C5 = logger_olp:get_opts(logger_proxy), + C5 = logger_proxy:get_default_config(), + + %% Errors + {error,{invalid_olp_config,_}} = + logger:set_proxy_config(#{faulty_key=>1}), + {error,{invalid_olp_config,_}} = + logger:set_proxy_config(#{sync_mode_qlen=>infinity}), + {error,{invalid_config,[]}} = logger:set_proxy_config([]), + + {error,{invalid_olp_config,_}} = + logger:update_proxy_config(#{faulty_key=>1}), + {error,{invalid_olp_config,_}} = + logger:update_proxy_config(#{sync_mode_qlen=>infinity}), + {error,{invalid_config,[]}} = logger:update_proxy_config([]), + + C5 = logger:get_proxy_config(), + C5 = logger_olp:get_opts(logger_proxy), + + ok. +config(cleanup,_Config) -> + _ = logger:set_logger_proxy(logger_proxy:get_default_config()), + ok. + +restart_after(_Config) -> + Restart = 3000, + ok = logger:update_proxy_config(#{overload_kill_enable => true, + overload_kill_qlen => 10, + overload_kill_restart_after => Restart}), + Proxy = whereis(logger_proxy), + Proxy = erlang:system_info(system_logger), + ProxyConfig = logger:get_proxy_config(), + ProxyConfig = logger_olp:get_opts(logger_proxy), + + Ref = erlang:monitor(process,Proxy), + spawn(fun() -> + [logger_proxy ! {log,debug, + [{test_case,?FUNCTION_NAME}, + {line,?LINE}], + ?LOC} || _ <- lists:seq(1,100)] + end), + receive + {'DOWN',Ref,_,_,_Reason} -> + undefined = erlang:system_info(system_logger), + timer:sleep(Restart), + poll_restarted(10) + after 5000 -> + ct:fail(proxy_not_terminated) + end, + + Proxy1 = whereis(logger_proxy), + Proxy1 = erlang:system_info(system_logger), + ProxyConfig = logger:get_proxy_config(), + ProxyConfig = logger_olp:get_opts(logger_proxy), + + ok. +restart_after(cleanup,_Config) -> + _ = logger:set_logger_proxy(logger_proxy:get_default_config()), + ok. + +%% Test that system_logger flag is set to logger process if +%% logger_proxy terminates for other reason than overloaded. +terminate(_Config) -> + Logger = whereis(logger), + Proxy = whereis(logger_proxy), + Proxy = erlang:system_info(system_logger), + ProxyConfig = logger:get_proxy_config(), + ProxyConfig = logger_olp:get_opts(logger_proxy), + + Ref = erlang:monitor(process,Proxy), + ok = logger_olp:stop(Proxy), + receive + {'DOWN',Ref,_,_,_Reason} -> + Logger = erlang:system_info(system_logger), + logger_proxy:restart(), + poll_restarted(10) + after 5000 -> + ct:fail(proxy_not_terminated) + end, + + Proxy1 = whereis(logger_proxy), + Proxy1 = erlang:system_info(system_logger), + ProxyConfig = logger:get_proxy_config(), + ProxyConfig = logger_olp:get_opts(logger_proxy), + + ok. + +%%%----------------------------------------------------------------- +%%% Internal functions + +poll_restarted(0) -> + ct:fail(proxy_not_restarted); +poll_restarted(N) -> + timer:sleep(1000), + case whereis(logger_proxy) of + undefined -> + poll_restarted(N-1); + _Pid -> + ok + end. + +%% Logger handler callback +log(#{meta:=Meta},#{config:=Pid}) -> + Pid ! {logged,Meta}. + +%% Check that the log from the logger callback function log/2 is received +ensure(Match) -> + receive {logged,Meta} -> + case maps:with(maps:keys(Match),Meta) of + Match -> ok; + _NoMatch -> {error,Match,Meta,test_server:messages_get()} + end + after ?ENSURE_TIME -> {error,Match,test_server:messages_get()} + end. diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl index eb17a6d857..484d914ec3 100644 --- a/lib/kernel/test/logger_std_h_SUITE.erl +++ b/lib/kernel/test/logger_std_h_SUITE.erl @@ -25,10 +25,15 @@ -include_lib("kernel/include/logger.hrl"). -include_lib("kernel/src/logger_internal.hrl"). -include_lib("kernel/src/logger_h_common.hrl"). +-include_lib("kernel/src/logger_olp.hrl"). -include_lib("stdlib/include/ms_transform.hrl"). -include_lib("kernel/include/file.hrl"). --define(check_no_log, [] = test_server:messages_get()). +-define(check_no_log, + begin + timer:sleep(?IDLE_DETECT_TIME*2), + [] = test_server:messages_get() + end). -define(check(Expected), receive {log,Expected} -> @@ -115,7 +120,6 @@ all() -> crash_std_h_to_file, crash_std_h_to_disk_log, bad_input, - info_and_reset, reconfig, file_opts, sync, @@ -209,9 +213,9 @@ default_formatter(_Config) -> filter_config(_Config) -> ok = logger:add_handler(?MODULE,logger_std_h,#{}), {ok,#{config:=HConfig}=Config} = logger:get_handler_config(?MODULE), - HConfig = maps:without([handler_pid,mode_tab],HConfig), + HConfig = maps:without([olp],HConfig), - FakeFullHConfig = HConfig#{handler_pid=>self(),mode_tab=>erlang:make_ref()}, + FakeFullHConfig = HConfig#{olp=>{regname,self(),erlang:make_ref()}}, #{config:=HConfig} = logger_std_h:filter_config(Config#{config=>FakeFullHConfig}), ok. @@ -246,13 +250,13 @@ errors(Config) -> _ -> NoDir = lists:concat(["/",?MODULE,"_dir"]), {error, - {handler_not_added,{{open_failed,NoDir,eacces},_}}} = + {handler_not_added,{open_failed,NoDir,eacces}}} = logger:add_handler(myh2,logger_std_h, #{config=>#{type=>{file,NoDir}}}) end, {error, - {handler_not_added,{{open_failed,Log,_},_}}} = + {handler_not_added,{open_failed,Log,_}}} = logger:add_handler(myh3,logger_std_h, #{config=>#{type=>{file,Log,[bad_file_opt]}}}), @@ -320,19 +324,16 @@ config_fail(_Config) -> #{config => #{restart_type => bad}, filter_default=>log, formatter=>{?MODULE,self()}}), - {error,{handler_not_added,{invalid_config,logger_std_h, - {invalid_levels,#{drop_mode_qlen:=1}}}}} = + {error,{handler_not_added,{invalid_olp_levels,#{drop_mode_qlen:=1}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{drop_mode_qlen=>1}}), - {error,{handler_not_added,{invalid_config,logger_std_h, - {invalid_levels,#{sync_mode_qlen:=43, - drop_mode_qlen:=42}}}}} = + {error,{handler_not_added,{invalid_olp_levels,#{sync_mode_qlen:=43, + drop_mode_qlen:=42}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{sync_mode_qlen=>43, drop_mode_qlen=>42}}), - {error,{handler_not_added,{invalid_config,logger_std_h, - {invalid_levels,#{drop_mode_qlen:=43, - flush_qlen:=42}}}}} = + {error,{handler_not_added,{invalid_olp_levels,#{drop_mode_qlen:=43, + flush_qlen:=42}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{drop_mode_qlen=>43, flush_qlen=>42}}), @@ -344,7 +345,7 @@ config_fail(_Config) -> logger:set_handler_config(?MODULE,config, #{type=>{file,"file"}}), - {error,{invalid_config,logger_std_h,{invalid_levels,_}}} = + {error,{invalid_olp_levels,_}} = logger:set_handler_config(?MODULE,config, #{sync_mode_qlen=>100, flush_qlen=>99}), @@ -355,9 +356,7 @@ config_fail(_Config) -> %% Read-only fields may (accidentially) be included in the change, %% but it won't take effect {ok,C} = logger:get_handler_config(?MODULE), - ok = logger:set_handler_config(?MODULE,config, - #{handler_pid=>self(), - mode_tab=>erlang:make_ref()}), + ok = logger:set_handler_config(?MODULE,config,#{olp=>dummyvalue}), {ok,C} = logger:get_handler_config(?MODULE), ok. @@ -425,10 +424,13 @@ crash_std_h(Config,Func,Var,Type,Log) -> %% logger would send the log event to the logger process here instead %% of logging it itself. log_on_remote_node(Node,Msg) -> + Pid = self(), _ = spawn_link(Node, fun() -> erlang:group_leader(whereis(user),self()), - logger:notice(Msg) + logger:notice(Msg), + Pid ! done end), + receive done -> ok end, ok. @@ -456,14 +458,7 @@ sync_and_read(Node,file,Log) -> end. bad_input(_Config) -> - {error,{badarg,{filesync,["BadType"]}}} = logger_std_h:filesync("BadType"), - {error,{badarg,{info,["BadType"]}}} = logger_std_h:info("BadType"), - {error,{badarg,{reset,["BadType"]}}} = logger_std_h:reset("BadType"). - - -info_and_reset(_Config) -> - #{id := ?STANDARD_HANDLER} = logger_std_h:info(?STANDARD_HANDLER), - ok = logger_std_h:reset(?STANDARD_HANDLER). + {error,{badarg,{filesync,["BadType"]}}} = logger_std_h:filesync("BadType"). reconfig(Config) -> Dir = ?config(priv_dir,Config), @@ -473,9 +468,10 @@ reconfig(Config) -> filter_default=>log, filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), formatter=>{?MODULE,self()}}), - #{id := ?MODULE, - handler_state := #{type := standard_io, - file_ctrl_pid := FileCtrlPid}, + #{%id := ?MODULE, + cb_state:=#{handler_state := #{type := standard_io, + file_ctrl_pid := FileCtrlPid}, + filesync_repeat_interval := no_repeat}, sync_mode_qlen := ?SYNC_MODE_QLEN, drop_mode_qlen := ?DROP_MODE_QLEN, flush_qlen := ?FLUSH_QLEN, @@ -485,9 +481,8 @@ reconfig(Config) -> overload_kill_enable := ?OVERLOAD_KILL_ENABLE, overload_kill_qlen := ?OVERLOAD_KILL_QLEN, overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE, - overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER, - filesync_repeat_interval := no_repeat} = DefaultInfo = - logger_std_h:info(?MODULE), + overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER} = + logger_olp:info(h_proc_name()), {ok, #{config:= @@ -518,9 +513,10 @@ reconfig(Config) -> overload_kill_mem_size => 10000000, overload_kill_restart_after => infinity, filesync_repeat_interval => 5000}), - #{id := ?MODULE, - handler_state := #{type := standard_io, - file_ctrl_pid := FileCtrlPid}, + #{%id := ?MODULE, + cb_state := #{handler_state := #{type := standard_io, + file_ctrl_pid := FileCtrlPid}, + filesync_repeat_interval := no_repeat}, sync_mode_qlen := 1, drop_mode_qlen := 2, flush_qlen := 3, @@ -530,8 +526,7 @@ reconfig(Config) -> overload_kill_enable := true, overload_kill_qlen := 100000, overload_kill_mem_size := 10000000, - overload_kill_restart_after := infinity, - filesync_repeat_interval := no_repeat} = Info = logger_std_h:info(?MODULE), + overload_kill_restart_after := infinity} = logger_olp:info(h_proc_name()), {ok,#{config := #{type := standard_io, @@ -613,7 +608,7 @@ file_opts(Config) -> Log = filename:join(Dir, lists:concat([?FUNCTION_NAME,".log"])), BadFileOpts = [raw], BadType = {file,Log,BadFileOpts}, - {error,{handler_not_added,{{open_failed,Log,enoent},_}}} = + {error,{handler_not_added,{open_failed,Log,enoent}}} = logger:add_handler(?MODULE, logger_std_h, #{config => #{type => BadType}}), @@ -626,7 +621,9 @@ file_opts(Config) -> filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), formatter=>{?MODULE,self()}}), - #{handler_state := #{type := OkType}} = logger_std_h:info(?MODULE), + #{cb_state := #{handler_state := #{type := OkType}}} = + logger_olp:info(h_proc_name()), + {ok,#{config := #{type := OkType}}} = logger:get_handler_config(?MODULE), logger:notice(M1=?msg,?domain), ?check(M1), B1 = ?bin(M1), @@ -675,11 +672,8 @@ sync(Config) -> %% a filesync is still performed when handler goes idle ok = logger:update_handler_config(?MODULE, config, #{filesync_repeat_interval => no_repeat}), - no_repeat = maps:get(filesync_repeat_interval, logger_std_h:info(?MODULE)), - %% The following timer is to make sure the time from last log - %% ("second") to next ("third") is long enough, so the a flush is - %% triggered by the idle timeout between "thrid" and "fourth". - timer:sleep(?IDLE_DETECT_TIME_MSEC*2), + no_repeat = maps:get(filesync_repeat_interval, + maps:get(cb_state, logger_olp:info(h_proc_name()))), start_tracer([{logger_std_h, write_to_dev, 5}, {file, datasync, 1}], [{logger_std_h, write_to_dev, <<"third\n">>}, @@ -688,22 +682,24 @@ sync(Config) -> {file,datasync}]), logger:notice("third", ?domain), %% wait for automatic filesync - timer:sleep(?IDLE_DETECT_TIME_MSEC*2), + timer:sleep(?IDLE_DETECT_TIME*2), logger:notice("fourth", ?domain), %% wait for automatic filesync - check_tracer(?IDLE_DETECT_TIME_MSEC*2), + check_tracer(?IDLE_DETECT_TIME*2), %% switch repeated filesync on and verify that the looping works SyncInt = 1000, WaitT = 4500, OneSync = {logger_h_common,handle_cast,repeated_filesync}, %% receive 1 repeated_filesync per sec - start_tracer([{logger_h_common,handle_cast,2}], + start_tracer([{{logger_h_common,handle_cast,2}, + [{[repeated_filesync,'_'],[],[]}]}], [OneSync || _ <- lists:seq(1, trunc(WaitT/SyncInt))]), ok = logger:update_handler_config(?MODULE, config, #{filesync_repeat_interval => SyncInt}), - SyncInt = maps:get(filesync_repeat_interval, logger_std_h:info(?MODULE)), + SyncInt = maps:get(filesync_repeat_interval, + maps:get(cb_state,logger_olp:info(h_proc_name()))), timer:sleep(WaitT), ok = logger:update_handler_config(?MODULE, config, #{filesync_repeat_interval => no_repeat}), @@ -764,8 +760,6 @@ sync_failure(Config) -> ok = rpc:call(Node, logger, update_handler_config, [?STANDARD_HANDLER, config, #{filesync_repeat_interval => SyncInt}]), - Info = rpc:call(Node, logger_std_h, info, [?STANDARD_HANDLER]), - SyncInt = maps:get(filesync_repeat_interval, Info), ok = log_on_remote_node(Node, "Logged1"), ?check_no_log, @@ -1095,7 +1089,7 @@ qlen_kill_new(Config) -> receive {'DOWN', MRef, _, _, Info} -> case Info of - {shutdown,{overloaded,?MODULE,QLen,Mem}} -> + {shutdown,{overloaded,QLen,Mem}} -> ct:pal("Terminated with qlen = ~w, mem = ~w", [QLen,Mem]); killed -> ct:pal("Slow shutdown, handler process was killed!", []) @@ -1105,7 +1099,7 @@ qlen_kill_new(Config) -> ok after 5000 -> - Info = logger_std_h:info(?MODULE), + Info = logger_olp:info(h_proc_name()), ct:pal("Handler state = ~p", [Info]), ct:fail("Handler not dead! It should not have survived this!") end. @@ -1146,7 +1140,7 @@ mem_kill_new(Config) -> receive {'DOWN', MRef, _, _, Info} -> case Info of - {shutdown,{overloaded,?MODULE,QLen,Mem}} -> + {shutdown,{overloaded,QLen,Mem}} -> ct:pal("Terminated with qlen = ~w, mem = ~w", [QLen,Mem]); killed -> ct:pal("Slow shutdown, handler process was killed!", []) @@ -1156,7 +1150,7 @@ mem_kill_new(Config) -> ok after 5000 -> - Info = logger_std_h:info(?MODULE), + Info = logger_olp:info(h_proc_name()), ct:pal("Handler state = ~p", [Info]), ct:fail("Handler not dead! It should not have survived this!") end. @@ -1187,7 +1181,7 @@ restart_after(Config) -> ok after 5000 -> - Info1 = logger_std_h:info(?MODULE), + Info1 = logger_olp:info(h_proc_name()), ct:pal("Handler state = ~p", [Info1]), ct:fail("Handler not dead! It should not have survived this!") end, @@ -1212,7 +1206,7 @@ restart_after(Config) -> ok after 5000 -> - Info2 = logger_std_h:info(?MODULE), + Info2 = logger_olp:info(h_proc_name()), ct:pal("Handler state = ~p", [Info2]), ct:fail("Handler not dead! It should not have survived this!") end, @@ -1234,11 +1228,15 @@ handler_requests_under_load(Config) -> flush_qlen => 2000, burst_limit_enable => false}}, ok = logger:update_handler_config(?MODULE, NewHConfig), - Pid = spawn_link(fun() -> send_requests(?MODULE, 1, [{filesync,[]}, - {info,[]}, - {reset,[]}, - {change_config,[]}]) - end), + Pid = spawn_link( + fun() -> send_requests(1,[{logger_std_h,filesync,[?MODULE],[]}, + {logger_olp,info,[h_proc_name()],[]}, + {logger_olp,reset,[h_proc_name()],[]}, + {logger,update_handler_config, + [?MODULE, config, + #{overload_kill_enable => false}], + []}]) + end), Sent = send_burst({t,10000}, seq, {chars,79}, notice), Pid ! {self(),finish}, ReqResult = receive {Pid,Result} -> Result end, @@ -1249,8 +1247,9 @@ handler_requests_under_load(Config) -> [E || E <- Res, is_tuple(E) andalso (element(1,E) == error)] end, - Errors = [{Req,FindError(Res)} || {Req,Res} <- ReqResult], - NoOfReqs = lists:foldl(fun({_,Res}, N) -> N + length(Res) end, 0, ReqResult), + Errors = [{Func,FindError(Res)} || {_,Func,_,Res} <- ReqResult], + NoOfReqs = lists:foldl(fun({_,_,_,Res}, N) -> N + length(Res) end, + 0, ReqResult), ct:pal("~w requests made. Errors: ~n~p", [NoOfReqs,Errors]), ok = file_delete(Log). handler_requests_under_load(cleanup, _Config) -> @@ -1272,22 +1271,14 @@ recreate_deleted_log(cleanup, _Config) -> %%%----------------------------------------------------------------- %%% -send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) -> +send_requests(TO, Reqs = [{Mod,Func,Args,Res}|Rs]) -> receive {From,finish} -> From ! {self(),Reqs} after TO -> - Result = - case Req of - change_config -> - logger:update_handler_config(HName, config, - #{overload_kill_enable => - false}); - Func -> - logger_std_h:Func(HName) - end, - send_requests(HName, TO, Rs ++ [{Req,[Result|Res]}]) + Result = apply(Mod,Func,Args), + send_requests(TO, Rs ++ [{Mod,Func,Args,[Result|Res]}]) end. @@ -1624,7 +1615,8 @@ start_tracer(Trace,Expected) -> Pid = self(), FileCtrlPid = maps:get(file_ctrl_pid, maps:get(handler_state, - logger_std_h:info(?MODULE))), + maps:get(cb_state, + logger_olp:info(h_proc_name())))), dbg:tracer(process,{fun tracer/2,{Pid,Expected}}), dbg:p(whereis(h_proc_name()),[c]), dbg:p(FileCtrlPid,[c]), @@ -1632,7 +1624,9 @@ start_tracer(Trace,Expected) -> ok. tpl([{M,F,A}|Trace]) -> - {ok,Match} = dbg:tpl(M,F,A,[]), + tpl([{{M,F,A},[]}|Trace]); +tpl([{{M,F,A},MS}|Trace]) -> + {ok,Match} = dbg:tpl(M,F,A,MS), case lists:keyfind(matched,1,Match) of {_,_,1} -> ok; diff --git a/lib/kernel/test/logger_stress_SUITE.erl b/lib/kernel/test/logger_stress_SUITE.erl new file mode 100644 index 0000000000..4072e8c86a --- /dev/null +++ b/lib/kernel/test/logger_stress_SUITE.erl @@ -0,0 +1,456 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(logger_stress_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct_event.hrl"). +-include_lib("kernel/include/logger.hrl"). +-include_lib("kernel/src/logger_h_common.hrl"). + +-ifdef(SAVE_STATS). + -define(COLLECT_STATS(_All_,_Procs_), + ct:pal("~p",[stats(_All_,_Procs_)])). +-else. + -define(COLLECT_STATS(_All_,_Procs__), ok). +-endif. + +-define(TEST_DURATION,120). % seconds + +suite() -> + [{timetrap,{minutes,3}}, + {ct_hooks,[logger_test_lib]}]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_Group, Config) -> + Config. + +end_per_group(_Group, _Config) -> + ok. + +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(Case, Config) -> + try apply(?MODULE,Case,[cleanup,Config]) + catch error:undef -> ok + end, + ok. + +groups() -> + []. + +all() -> + [allow_events, + reject_events, + std_handler, + disk_log_handler, + emulator_events, + remote_events, + remote_to_disk_log, + remote_emulator_events, + remote_emulator_to_disk_log]. + +%%%----------------------------------------------------------------- +%%% Test cases +%%%----------------------------------------------------------------- +%% Time from log macro call to handler callback +allow_events(Config) -> + {ok,_,Node} = + logger_test_lib:setup(Config, + [{logger, + [{handler,default,?MODULE,#{}}]}, + {logger_level,notice}]), + N = 100000, + {T,_} = timer:tc(fun() -> rpc:call(Node,?MODULE,nlogs,[N]) end), + IOPS = N * 1000/T, % log events allowed per millisecond + ct_event:notify(#event{name = benchmark_data, + data = [{value,IOPS}]}), + {comment,io_lib:format("~.2f accepted events pr millisecond", + [IOPS])}. + +%% Time from log macro call to reject (log level) +reject_events(Config) -> + {ok,_,Node} = + logger_test_lib:setup(Config, + [{logger, + [{handler,default,?MODULE,#{}}]}, + {logger_level,error}]), + N = 1000000, + {T,_} = timer:tc(fun() -> rpc:call(Node,?MODULE,nlogs,[N]) end), + IOPS = N * 1000/T, % log events rejected per millisecond + ct_event:notify(#event{name = benchmark_data, + data = [{value,IOPS}]}), + {comment,io_lib:format("~.2f rejected events pr millisecond", + [IOPS])}. + +%% Cascading failure that produce gen_server and proc_lib reports - +%% how many of the produced log events are actually written to a log +%% with logger_std_h file handler. +std_handler(Config) -> + {ok,_,Node} = + logger_test_lib:setup(Config, + [{logger, + [{handler,default,logger_std_h, + #{config=>#{type=>{file,"default.log"}}}}]}]), + + cascade({Node,{logger_backend,log_allowed,2},[]}, + {Node,{logger_std_h,write,4},[{default,logger_std_h_default}]}, + fun otp_cascading/0). +std_handler(cleanup,_Config) -> + _ = file:delete("default.log"), + ok. + +%% Cascading failure that produce gen_server and proc_lib reports - +%% how many of the produced log events are actually written to a log +%% with logger_disk_log_h wrap file handler. +disk_log_handler(Config) -> + {ok,_,Node} = + logger_test_lib:setup(Config, + [{logger, + [{handler,default,logger_disk_log_h,#{}}]}]), + cascade({Node,{logger_backend,log_allowed,2},[]}, + {Node,{logger_disk_log_h,write,4}, + [{default,logger_disk_log_h_default}]}, + fun otp_cascading/0). +disk_log_handler(cleanup,_Config) -> + Files = filelib:wildcard("default.log.*"), + [_ = file:delete(F) || F <- Files], + ok. + +%% Cascading failure that produce log events from the emulator - how +%% many of the produced log events pass through the proxy. +emulator_events(Config) -> + {ok,_,Node} = + logger_test_lib:setup(Config, + [{logger, + [{handler,default,?MODULE,#{}}]}]), + cascade({Node,{?MODULE,producer,0},[]}, + {Node,{?MODULE,log,2},[{proxy,logger_proxy}]}, + fun em_cascading/0). + +%% Cascading failure that produce gen_server and proc_lib reports on +%% remote node - how many of the produced log events pass through the +%% proxy. +remote_events(Config) -> + {ok,_,Node1} = + logger_test_lib:setup([{postfix,1}|Config], + [{logger, + [{handler,default,?MODULE,#{}}]}]), + {ok,_,Node2} = + logger_test_lib:setup([{postfix,2}|Config],[]), + cascade({Node2,{logger_backend,log_allowed,2},[{remote_proxy,logger_proxy}]}, + {Node1,{?MODULE,log,2},[{local_proxy,logger_proxy}]}, + fun otp_cascading/0). + +%% Cascading failure that produce gen_server and proc_lib reports on +%% remote node - how many of the produced log events are actually +%% written to a log with logger_disk_log_h wrap file handler. +remote_to_disk_log(Config) -> + {ok,_,Node1} = + logger_test_lib:setup([{postfix,1}|Config], + [{logger, + [{handler,default,logger_disk_log_h,#{}}]}]), + {ok,_,Node2} = + logger_test_lib:setup([{postfix,2}|Config],[]), + cascade({Node2,{logger_backend,log_allowed,2},[{remote_proxy,logger_proxy}]}, + {Node1,{logger_disk_log_h,write,4}, + [{local_proxy,logger_proxy}, + {local_default,logger_disk_log_h_default}]}, + fun otp_cascading/0). +remote_to_disk_log(cleanup,_Config) -> + Files = filelib:wildcard("default.log.*"), + [_ = file:delete(F) || F <- Files], + ok. + +%% Cascading failure that produce log events from the emulator on +%% remote node - how many of the produced log events pass through the +%% proxy. +remote_emulator_events(Config) -> + {ok,_,Node1} = + logger_test_lib:setup([{postfix,1}|Config], + [{logger, + [{handler,default,?MODULE,#{}}]}]), + {ok,_,Node2} = + logger_test_lib:setup([{postfix,2}|Config],[]), + cascade({Node2,{?MODULE,producer,0},[{remote_proxy,logger_proxy}]}, + {Node1,{?MODULE,log,2},[{local_proxy,logger_proxy}]}, + fun em_cascading/0). + +%% Cascading failure that produce log events from the emulator on +%% remote node - how many of the produced log events are actually +%% written to a log with logger_disk_log_h wrap file handler. +remote_emulator_to_disk_log(Config) -> + {ok,_,Node1} = + logger_test_lib:setup([{postfix,1}|Config], + [{logger, + [{handler,default,logger_disk_log_h,#{}}]}]), + {ok,_,Node2} = + logger_test_lib:setup([{postfix,2}|Config],[]), + cascade({Node2,{?MODULE,producer,0},[{remote_proxy,logger_proxy}]}, + {Node1,{logger_disk_log_h,write,4}, + [{local_proxy,logger_proxy}, + {local_default,logger_disk_log_h_default}]}, + fun em_cascading/0). +remote_emulator_to_disk_log(cleanup,_Config) -> + Files = filelib:wildcard("default.log.*"), + [_ = file:delete(F) || F <- Files], + ok. + +%%%----------------------------------------------------------------- +%%% Internal functions +nlogs(N) -> + group_leader(whereis(user),self()), + Str = "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "[\\]^_`abcdefghijklmnopqr", + [?LOG_NOTICE(Str) || _ <- lists:seq(1,N)], + ok. + +%% cascade(ProducerInfo,ConsumerInfo,TestFun) +cascade({PNode,PMFA,_PStatProcs},{CNode,CMFA,_CStatProcs},TestFun) -> + Tab = ets:new(counter,[set,public]), + ets:insert(Tab,{producer,0}), + ets:insert(Tab,{consumer,0}), + dbg:tracer(process,{fun tracer/2,{Tab,PNode,CNode}}), + dbg:n(PNode), + dbg:n(CNode), + dbg:cn(node()), + dbg:p(all,[call,arity]), + dbg:tpl(PMFA,[]), + dbg:tpl(CMFA,[]), + + Pid = rpc:call(CNode,?MODULE,wrap_test,[PNode,TestFun]), + MRef = erlang:monitor(process,Pid), + TO = ?TEST_DURATION*1000, + receive {'DOWN',MRef,_,_,Reason} -> + ct:fail({remote_pid_down,Reason}) + after TO -> + All = ets:lookup_element(Tab,producer,2), + Written = ets:lookup_element(Tab,consumer,2), + dbg:stop_clear(), + ?COLLECT_STATS(All, + [{PNode,P,Id} || {Id,P} <- _PStatProcs] ++ + [{CNode,P,Id} || {Id,P} <- _CStatProcs]), + Ratio = Written/All * 100, + ct_event:notify(#event{name = benchmark_data, + data = [{value,Ratio}]}), + {comment,io_lib:format("~p % (~p written, ~p produced)", + [round(Ratio),Written,All])} + end. + +wrap_test(Fun) -> + wrap_test(node(),Fun). +wrap_test(Node,Fun) -> + reset(), + group_leader(whereis(user),self()), + rpc:call(Node,?MODULE,do_fun,[Fun]). + +do_fun(Fun) -> + reset(), + Fun(). + +reset() -> + reset([logger_std_h_default, logger_disk_log_h_default, logger_proxy]). +reset([P|Ps]) -> + is_pid(whereis(P)) andalso logger_olp:reset(P), + reset(Ps); +reset([]) -> + ok. + + +tracer({trace,_,call,{?MODULE,producer,_}},{Tab,_PNode,_CNode}=S) -> + ets:update_counter(Tab,producer,1), + S; +tracer({trace,Pid,call,{logger_backend,log_allowed,_}},{Tab,PNode,_CNode}=S) when node(Pid)=:=PNode -> + ets:update_counter(Tab,producer,1), + S; +tracer({trace,_,call,{?MODULE,log,_}},{Tab,_PNode,_CNode}=S) -> + ets:update_counter(Tab,consumer,1), + S; +tracer({trace,_,call,{_,write,_}},{Tab,_PNode,_CNode}=S) -> + ets:update_counter(Tab,consumer,1), + S; +tracer(_,S) -> + S. + + +%%%----------------------------------------------------------------- +%%% Collect statistics +-define(STAT_KEYS, + [burst_drops, + calls, + casts, + drops, + flushed, + flushes, + freq, + last_qlen, + max_qlen, + time, + writes]). +-define(EVENT_KEYS, + [calls,casts,flushed]). + +stats(All,Procs) -> + NI = [{Id,rpc:call(N,logger_olp,info,[P])} || {N,P,Id}<-Procs], + [{all,All}|[stats(Id,I,All) || {Id,I} <- NI]]. + +stats(Id,Info,All) -> + S = maps:with(?STAT_KEYS,Info), + AllOnProc = lists:sum(maps:values(maps:with(?EVENT_KEYS,S))), + if All>0 -> + Writes = maps:get(writes,S), + {_,ActiveTime} = maps:get(time,S), + Rate = round(100*Writes/All), + RateOnProc = + if AllOnProc>0 -> + round(100*Writes/AllOnProc); + true -> + 0 + end, + AvFreq = + if ActiveTime>0 -> + round(Writes/ActiveTime); + true -> + 0 + end, + {Id, + {stats,S}, + {rate,Rate}, + {rate_on_proc,RateOnProc}, + {av_freq,AvFreq}}; + true -> + {Id,none} + end. + +%%%----------------------------------------------------------------- +%%% Spawn a lot of processes that crash repeatedly, causing a lot of +%%% error reports from the emulator. +em_cascading() -> + spawn(fun() -> super() end). + +super() -> + process_flag(trap_exit,true), + spawn_link(fun server/0), + [spawn_link(fun client/0) || _<-lists:seq(1,10000)], + super_loop(). + +super_loop() -> + receive + {'EXIT',_,server} -> + spawn_link(fun server/0), + super_loop(); + {'EXIT',_,_} -> + _L = lists:sum(lists:seq(1,10000)), + spawn_link(fun client/0), + super_loop() + end. + +client() -> + receive + after 1 -> + case whereis(server) of + Pid when is_pid(Pid) -> + ok; + undefined -> + producer(), + erlang:error(some_exception) + end + end, + client(). + +server() -> + register(server,self()), + receive + after 3000 -> + exit(server) + end. + + +%%%----------------------------------------------------------------- +%%% Create a supervisor tree with processes that crash repeatedly, +%%% causing a lot of supervisor reports and crashreports +otp_cascading() -> + {ok,Pid} = supervisor:start_link({local,otp_super}, ?MODULE, [otp_super]), + unlink(Pid), + Pid. + +otp_server_sup() -> + supervisor:start_link({local,otp_server_sup},?MODULE,[otp_server_sup]). + +otp_client_sup(N) -> + supervisor:start_link({local,otp_client_sup},?MODULE,[otp_client_sup,N]). + +otp_server() -> + gen_server:start_link({local,otp_server},?MODULE,[otp_server],[]). + +otp_client() -> + gen_server:start_link(?MODULE,[otp_client],[]). + +init([otp_super]) -> + {ok, {{one_for_one, 200, 10}, + [{client_sup, + {?MODULE, otp_client_sup, [10000]}, + permanent, 1000, supervisor, [?MODULE]}, + {server_sup, + {?MODULE, otp_server_sup, []}, + permanent, 1000, supervisor, [?MODULE]} + ]}}; +init([otp_server_sup]) -> + {ok, {{one_for_one, 2, 10}, + [{server, + {?MODULE, otp_server, []}, + permanent, 1000, worker, [?MODULE]} + ]}}; +init([otp_client_sup,N]) -> + spawn(fun() -> + [supervisor:start_child(otp_client_sup,[]) + || _ <- lists:seq(1,N)] + end), + {ok, {{simple_one_for_one, N*10, 1}, + [{client, + {?MODULE, otp_client, []}, + permanent, 1000, worker, [?MODULE]} + ]}}; +init([otp_server]) -> + {ok, server, 10000}; +init([otp_client]) -> + {ok, client,1}. + +handle_info(timeout, client) -> + true = is_pid(whereis(otp_server)), + {noreply,client,1}; +handle_info(timeout, server) -> + exit(self(), some_error). + +%%%----------------------------------------------------------------- +%%% Logger callbacks +log(_LogEvent,_Config) -> + ok. + +%%%----------------------------------------------------------------- +%%% Function to trace on for counting produced emulator messages +producer() -> + ok. diff --git a/lib/kernel/test/logger_test_lib.erl b/lib/kernel/test/logger_test_lib.erl index 81eb9ce5eb..be4bc427fb 100644 --- a/lib/kernel/test/logger_test_lib.erl +++ b/lib/kernel/test/logger_test_lib.erl @@ -28,11 +28,17 @@ post_end_per_testcase/5, post_end_per_suite/3]). setup(Config,Vars) -> + Postfix = case proplists:get_value(postfix, Config) of + undefined -> ""; + P -> ["_",P] + end, FuncStr = lists:concat([proplists:get_value(suite, Config), "_", - proplists:get_value(tc, Config)]), + proplists:get_value(tc, Config)| + Postfix]), ConfigFileName = filename:join(proplists:get_value(priv_dir, Config), FuncStr), file:write_file(ConfigFileName ++ ".config", io_lib:format("[{kernel, ~p}].",[Vars])), - case test_server:start_node(proplists:get_value(tc, Config), slave, + Sname = lists:concat([proplists:get_value(tc,Config)|Postfix]), + case test_server:start_node(Sname, slave, [{args, ["-pa ",filename:dirname(code:which(?MODULE)), " -boot start_sasl -kernel start_timer true " "-config ",ConfigFileName]}]) of diff --git a/lib/megaco/doc/src/megaco.xml b/lib/megaco/doc/src/megaco.xml index d4a7451bfc..c7bcdfcd6f 100644 --- a/lib/megaco/doc/src/megaco.xml +++ b/lib/megaco/doc/src/megaco.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco.xml</file> </header> - <module>megaco</module> + <module since="">megaco</module> <modulesummary>Main API of the Megaco application</modulesummary> <description> <p>Interface module for the Megaco application</p> @@ -135,7 +135,7 @@ megaco_incr_timer() = #megaco_incr_timer{} <funcs> <func> - <name>start() -> ok | {error, Reason}</name> + <name since="">start() -> ok | {error, Reason}</name> <fsummary>Starts the Megaco application</fsummary> <type> <v>Reason = term()</v> @@ -153,7 +153,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>stop() -> ok | {error, Reason}</name> + <name since="">stop() -> ok | {error, Reason}</name> <fsummary>Stops the Megaco application</fsummary> <type> <v>Reason = term()</v> @@ -166,7 +166,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>start_user(UserMid, Config) -> ok | {error, Reason}</name> + <name since="">start_user(UserMid, Config) -> ok | {error, Reason}</name> <fsummary>Initial configuration of a user</fsummary> <type> <v>UserMid = megaco_mid()</v> @@ -188,7 +188,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>stop_user(UserMid) -> ok | {error, Reason}</name> + <name since="">stop_user(UserMid) -> ok | {error, Reason}</name> <fsummary>Delete the configuration of a user</fsummary> <type> <v>UserMid = megaco_mid()</v> @@ -203,8 +203,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>user_info(UserMid) -> [{Item, Value}]</name> - <name>user_info(UserMid, Item) -> Value | exit(Reason)</name> + <name since="">user_info(UserMid) -> [{Item, Value}]</name> + <name since="">user_info(UserMid, Item) -> Value | exit(Reason)</name> <fsummary>Lookup user information</fsummary> <type> <v>Handle = user_info_handle()</v> @@ -703,7 +703,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>update_user_info(UserMid, Item, Value) -> ok | {error, Reason}</name> + <name since="">update_user_info(UserMid, Item, Value) -> ok | {error, Reason}</name> <fsummary>Update information about a user</fsummary> <type> <v>UserMid = megaco_mid() </v> @@ -721,8 +721,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>conn_info(ConnHandle) -> [{Item, Value}]</name> - <name>conn_info(ConnHandle, Item) -> Value | exit(Reason)</name> + <name since="">conn_info(ConnHandle) -> [{Item, Value}]</name> + <name since="">conn_info(ConnHandle, Item) -> Value | exit(Reason)</name> <fsummary>Lookup information about an active connection</fsummary> <type> <v>ConnHandle = #megaco_conn_handle{}</v> @@ -1222,7 +1222,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>update_conn_info(ConnHandle, Item, Value) -> ok | {error, Reason}</name> + <name since="">update_conn_info(ConnHandle, Item, Value) -> ok | {error, Reason}</name> <fsummary>Update information about an active connection</fsummary> <type> <v>ConnHandle = #megaco_conn_handle{}</v> @@ -1241,8 +1241,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>system_info() -> [{Item, Value}] | exit(Reason)</name> - <name>system_info(Item) -> Value | exit(Reason)</name> + <name since="">system_info() -> [{Item, Value}] | exit(Reason)</name> + <name since="">system_info(Item) -> Value | exit(Reason)</name> <fsummary>Lookup system information</fsummary> <type> <v>Item = system_info_item()</v> @@ -1289,7 +1289,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>info() -> Info</name> + <name since="">info() -> Info</name> <fsummary>All the information of the application</fsummary> <type> <v>Info = [{Key, Value}]</v> @@ -1311,8 +1311,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid) -> {ok, ConnHandle} | {error, Reason}</name> - <name>connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid, Extra) -> {ok, ConnHandle} | {error, Reason}</name> + <name since="">connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid) -> {ok, ConnHandle} | {error, Reason}</name> + <name since="">connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid, Extra) -> {ok, ConnHandle} | {error, Reason}</name> <fsummary>Establish a "virtual" connection</fsummary> <type> <v>ReceiveHandle = #megaco_receive_handle{}</v> @@ -1436,7 +1436,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>disconnect(ConnHandle, DiscoReason) -> ok | {error, ErrReason}</name> + <name since="">disconnect(ConnHandle, DiscoReason) -> ok | {error, ErrReason}</name> <fsummary>Tear down a "virtual" connection</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -1454,7 +1454,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>call(ConnHandle, Actions, Options) -> {ProtocolVersion, UserReply}</name> + <name since="">call(ConnHandle, Actions, Options) -> {ProtocolVersion, UserReply}</name> <fsummary>Sends one or more transaction request(s) and waits for the reply</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -1545,7 +1545,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>cast(ConnHandle, Actions, Options) -> ok | {error, Reason}</name> + <name since="">cast(ConnHandle, Actions, Options) -> ok | {error, Reason}</name> <fsummary>Sends one or more transaction request(s) but does NOT wait for a reply</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -1582,7 +1582,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>encode_actions(ConnHandle, Actions, Options) -> {ok, BinOrBins} | {error, Reason}</name> + <name since="">encode_actions(ConnHandle, Actions, Options) -> {ok, BinOrBins} | {error, Reason}</name> <fsummary>Encode action requests for one or more transaction request(s)</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -1607,9 +1607,9 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>token_tag2string(Tag) -> Result</name> - <name>token_tag2string(Tag, EncoderMod) -> Result</name> - <name>token_tag2string(Tag, EncoderMod, Version) -> Result</name> + <name since="">token_tag2string(Tag) -> Result</name> + <name since="">token_tag2string(Tag, EncoderMod) -> Result</name> + <name since="">token_tag2string(Tag, EncoderMod, Version) -> Result</name> <fsummary>Convert a token tag to a string</fsummary> <type> <v>Tag = atom()</v> @@ -1635,7 +1635,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>cancel(ConnHandle, CancelReason) -> ok | {error, ErrReason}</name> + <name since="">cancel(ConnHandle, CancelReason) -> ok | {error, ErrReason}</name> <fsummary>Cancel all outstanding messages for this connection</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -1655,8 +1655,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name> - <name>process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name> + <name since="">process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name> + <name since="">process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name> <fsummary>Process a received message</fsummary> <type> <v>ReceiveHandle = #megaco_receive_handle{}</v> @@ -1755,8 +1755,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name> - <name>receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name> + <name since="">receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name> + <name since="">receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name> <fsummary>Process a received message</fsummary> <type> <v>ReceiveHandle = #megaco_receive_handle{}</v> @@ -1783,7 +1783,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>parse_digit_map(DigitMapBody) -> {ok, ParsedDigitMap} | {error, Reason}</name> + <name since="">parse_digit_map(DigitMapBody) -> {ok, ParsedDigitMap} | {error, Reason}</name> <fsummary>Parses a digit map body</fsummary> <type> <v>DigitMapBody = string()</v> @@ -1802,8 +1802,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>eval_digit_map(DigitMap) -> {ok, MatchResult} | {error, Reason}</name> - <name>eval_digit_map(DigitMap, Timers) -> {ok, MatchResult} | {error, Reason}</name> + <name since="">eval_digit_map(DigitMap) -> {ok, MatchResult} | {error, Reason}</name> + <name since="">eval_digit_map(DigitMap, Timers) -> {ok, MatchResult} | {error, Reason}</name> <fsummary>Collect digit map letters according to the digit map</fsummary> <type> <v>DigitMap = #'DigitMapValue'{} | parsed_digit_map()</v> @@ -1839,7 +1839,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>report_digit_event(DigitMapEvalPid, Events) -> ok | {error, Reason}</name> + <name since="">report_digit_event(DigitMapEvalPid, Events) -> ok | {error, Reason}</name> <fsummary>Send one or more events to the event collector process</fsummary> <type> <v>DigitMapEvalPid = pid()</v> @@ -1866,7 +1866,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>test_digit_event(DigitMap, Events) -> {ok, Kind, Letters} | {error, Reason}</name> + <name since="">test_digit_event(DigitMap, Events) -> {ok, Kind, Letters} | {error, Reason}</name> <fsummary>Feed digit map collector with events and return the result</fsummary> <type> <v>DigitMap = #'DigitMapValue'{} | parsed_digit_map()</v> @@ -1900,7 +1900,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>encode_sdp(SDP) -> {ok, PP} | {error, Reason}</name> + <name since="">encode_sdp(SDP) -> {ok, PP} | {error, Reason}</name> <fsummary>Encode an SDP construct</fsummary> <type> <v>SDP = sdp_property_parm() | sdp_property_group() | sdp_property_groups() | asn1_NOVALUE</v> @@ -1929,7 +1929,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>decode_sdp(PP) -> {ok, SDP} | {error, Reason}</name> + <name since="">decode_sdp(PP) -> {ok, SDP} | {error, Reason}</name> <fsummary>Decode an property parameter construct</fsummary> <type> <v>PP = property_parm() | property_group() | property_groups() | asn1_NOVALUE</v> @@ -1969,7 +1969,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>get_sdp_record_from_PropertGroup(Type, PG) -> [sdp()]</name> + <name since="">get_sdp_record_from_PropertGroup(Type, PG) -> [sdp()]</name> <fsummary>Get all sdp records of a certain type from a property group</fsummary> <type> <v>Type = v | c | m | o | a | b | t | r | z | k | s | i | u | e | p</v> @@ -1986,8 +1986,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>versions1() -> {ok, VersionInfo} | {error, Reason}</name> - <name>versions2() -> {ok, Info} | {error, Reason}</name> + <name since="">versions1() -> {ok, VersionInfo} | {error, Reason}</name> + <name since="">versions2() -> {ok, Info} | {error, Reason}</name> <fsummary>Retreive various system and application info</fsummary> <type> <v>VersionInfo = [version_info()]</v> @@ -2007,8 +2007,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>print_version_info() -> void()</name> - <name>print_version_info(VersionInfo) -> void()</name> + <name since="">print_version_info() -> void()</name> + <name since="">print_version_info(VersionInfo) -> void()</name> <fsummary>Formated print of result of the versions functions</fsummary> <type> <v>VersionInfo = [version_info()]</v> @@ -2029,7 +2029,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>enable_trace(Level, Destination) -> void()</name> + <name since="">enable_trace(Level, Destination) -> void()</name> <fsummary>Start megaco tracing</fsummary> <type> <v>Level = max | min | 0 <= integer() <= 100</v> @@ -2057,7 +2057,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>disable_trace() -> void()</name> + <name since="">disable_trace() -> void()</name> <fsummary>Stop megaco tracing</fsummary> <desc> <p>This function is used to stop megaco tracing.</p> @@ -2065,7 +2065,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </desc> </func> <func> - <name>set_trace(Level) -> void()</name> + <name since="">set_trace(Level) -> void()</name> <fsummary>Change megaco trace level</fsummary> <type> <v>Level = max | min | 0 <= integer() <= 100</v> @@ -2081,10 +2081,10 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>get_stats() -> {ok, TotalStats} | {error, Reason}</name> - <name>get_stats(GlobalCounter) -> {ok, CounterStats} | {error, Reason}</name> - <name>get_stats(ConnHandle) -> {ok, ConnHandleStats} | {error, Reason}</name> - <name>get_stats(ConnHandle, Counter) -> {ok, integer()} | {error, Reason}</name> + <name since="">get_stats() -> {ok, TotalStats} | {error, Reason}</name> + <name since="">get_stats(GlobalCounter) -> {ok, CounterStats} | {error, Reason}</name> + <name since="">get_stats(ConnHandle) -> {ok, ConnHandleStats} | {error, Reason}</name> + <name since="">get_stats(ConnHandle, Counter) -> {ok, integer()} | {error, Reason}</name> <fsummary></fsummary> <type> <v>TotalStats = [total_stats()]</v> @@ -2110,8 +2110,8 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>reset_stats() -> void()</name> - <name>reset_stats(ConnHandle) -> void()</name> + <name since="">reset_stats() -> void()</name> + <name since="">reset_stats(ConnHandle) -> void()</name> <fsummary></fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -2123,7 +2123,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>test_request(ConnHandle, Version, EncodingMod, EncodingConfig, Actions) -> {MegaMsg, EncodeRes}</name> + <name since="">test_request(ConnHandle, Version, EncodingMod, EncodingConfig, Actions) -> {MegaMsg, EncodeRes}</name> <fsummary>Tests if the Actions argument is correct</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -2150,7 +2150,7 @@ megaco_incr_timer() = #megaco_incr_timer{} </func> <func> - <name>test_reply(ConnHandle, Version, EncodingMod, EncodingConfig, Reply) -> {MegaMsg, EncodeRes}</name> + <name since="">test_reply(ConnHandle, Version, EncodingMod, EncodingConfig, Reply) -> {MegaMsg, EncodeRes}</name> <fsummary>Tests if the Reply argument is correct</fsummary> <type> <v>ConnHandle = conn_handle()</v> diff --git a/lib/megaco/doc/src/megaco_codec_meas.xml b/lib/megaco/doc/src/megaco_codec_meas.xml index 13cc3eb834..5184fe392e 100644 --- a/lib/megaco/doc/src/megaco_codec_meas.xml +++ b/lib/megaco/doc/src/megaco_codec_meas.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_codec_meas.xml</file> </header> - <module>megaco_codec_meas</module> + <module since="">megaco_codec_meas</module> <modulesummary>This module implements a simple megaco codec measurement tool.</modulesummary> <description> <p>This module implements a simple megaco codec measurement tool.</p> @@ -43,8 +43,8 @@ <funcs> <func> - <name>start() -> void()</name> - <name>start(MessagePackage) -> void()</name> + <name since="">start() -> void()</name> + <name since="">start(MessagePackage) -> void()</name> <fsummary></fsummary> <type> <v>MessagePackageRaw = message_package()</v> diff --git a/lib/megaco/doc/src/megaco_codec_mstone1.xml b/lib/megaco/doc/src/megaco_codec_mstone1.xml index 2ff959a648..507a790c71 100644 --- a/lib/megaco/doc/src/megaco_codec_mstone1.xml +++ b/lib/megaco/doc/src/megaco_codec_mstone1.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_codec_mstone1.xml</file> </header> - <module>megaco_codec_mstone1</module> + <module since="">megaco_codec_mstone1</module> <modulesummary>This module implements a simple megaco codec-based performance tool.</modulesummary> <description> <p>This module implements the <em>mstone1</em> tool, @@ -44,9 +44,9 @@ <funcs> <func> - <name>start() -> void()</name> - <name>start(MessagePackage) -> void()</name> - <name>start(MessagePackage, Factor) -> void()</name> + <name since="">start() -> void()</name> + <name since="">start(MessagePackage) -> void()</name> + <name since="">start(MessagePackage, Factor) -> void()</name> <fsummary></fsummary> <type> <v>MessagePackage = message_package()</v> @@ -63,9 +63,9 @@ </func> <func> - <name>start_flex() -> void()</name> - <name>start_flex(MessagePackage) -> void()</name> - <name>start_flex(MessagePackage, Factor) -> void()</name> + <name since="">start_flex() -> void()</name> + <name since="">start_flex(MessagePackage) -> void()</name> + <name since="">start_flex(MessagePackage, Factor) -> void()</name> <fsummary></fsummary> <type> <v>MessagePackage = message_package()</v> @@ -83,9 +83,9 @@ </func> <func> - <name>start_only_drv() -> void()</name> - <name>start_only_drv(MessagePackage) -> void()</name> - <name>start_only_drv(MessagePackage, Factor) -> void()</name> + <name since="">start_only_drv() -> void()</name> + <name since="">start_only_drv(MessagePackage) -> void()</name> + <name since="">start_only_drv(MessagePackage, Factor) -> void()</name> <fsummary></fsummary> <type> <v>MessagePackage = message_package()</v> @@ -105,9 +105,9 @@ </func> <func> - <name>start_no_drv() -> void()</name> - <name>start_no_drv(MessagePackage) -> void()</name> - <name>start_no_drv(MessagePackage, Factor) -> void()</name> + <name since="">start_no_drv() -> void()</name> + <name since="">start_no_drv(MessagePackage) -> void()</name> + <name since="">start_no_drv(MessagePackage, Factor) -> void()</name> <fsummary></fsummary> <type> <v>MessagePackage = message_package()</v> diff --git a/lib/megaco/doc/src/megaco_codec_mstone2.xml b/lib/megaco/doc/src/megaco_codec_mstone2.xml index 3da30d4f99..03990f5c3d 100644 --- a/lib/megaco/doc/src/megaco_codec_mstone2.xml +++ b/lib/megaco/doc/src/megaco_codec_mstone2.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_codec_mstone2.xml</file> </header> - <module>megaco_codec_mstone2</module> + <module since="">megaco_codec_mstone2</module> <modulesummary>This module implements a simple megaco codec-based performance tool.</modulesummary> <description> <p>This module implements the <em>mstone2</em> tool, @@ -44,8 +44,8 @@ <funcs> <func> - <name>start() -> void()</name> - <name>start(MessagePackage) -> void()</name> + <name since="">start() -> void()</name> + <name since="">start(MessagePackage) -> void()</name> <fsummary></fsummary> <type> <v>MessagePackage = message_package()</v> diff --git a/lib/megaco/doc/src/megaco_codec_transform.xml b/lib/megaco/doc/src/megaco_codec_transform.xml index 26b83c3799..392868fdfa 100644 --- a/lib/megaco/doc/src/megaco_codec_transform.xml +++ b/lib/megaco/doc/src/megaco_codec_transform.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_codec_transform.xml</file> </header> - <module>megaco_codec_transform</module> + <module since="">megaco_codec_transform</module> <modulesummary>Megaco message transformation utility.</modulesummary> <description> @@ -45,8 +45,8 @@ <funcs> <func> - <name>export_messages() -> void()</name> - <name>export_messages(MessagePackage) -> void()</name> + <name since="">export_messages() -> void()</name> + <name since="">export_messages(MessagePackage) -> void()</name> <fsummary></fsummary> <type> <v>MessagePackage = atom()</v> diff --git a/lib/megaco/doc/src/megaco_edist_compress.xml b/lib/megaco/doc/src/megaco_edist_compress.xml index d5c7c7224d..16443e469c 100644 --- a/lib/megaco/doc/src/megaco_edist_compress.xml +++ b/lib/megaco/doc/src/megaco_edist_compress.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_edist_compress.xml</file> </header> - <module>megaco_edist_compress</module> + <module since="">megaco_edist_compress</module> <modulesummary>Megaco erlang dist compress behaviour.</modulesummary> <description> <p>The following functions should be exported from a @@ -40,7 +40,7 @@ </description> <funcs> <func> - <name>Module:encode(R, Version) -> T</name> + <name since="">Module:encode(R, Version) -> T</name> <fsummary>Encode (compress) a megaco component.</fsummary> <type> <v>R = megaco_message() | transaction() | action_reply() | action_request() | command_request()</v> @@ -53,7 +53,7 @@ </desc> </func> <func> - <name>Module:decode(T, Version) -> R</name> + <name since="">Module:decode(T, Version) -> R</name> <fsummary>Decode (decompress) a megaco component.</fsummary> <type> <v>T = term()</v> diff --git a/lib/megaco/doc/src/megaco_encoder.xml b/lib/megaco/doc/src/megaco_encoder.xml index 13c6ed324b..cc8270440b 100644 --- a/lib/megaco/doc/src/megaco_encoder.xml +++ b/lib/megaco/doc/src/megaco_encoder.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_encoder.xml</file> </header> - <module>megaco_encoder</module> + <module since="">megaco_encoder</module> <modulesummary>Megaco encoder behaviour.</modulesummary> <description> <p>The following functions should be exported from a @@ -64,7 +64,7 @@ action_reply() = #'ActionReply'{} <funcs> <func> - <name>Module:encode_message(EncodingConfig, Version, Message) -> {ok, Bin} | Error</name> + <name since="">Module:encode_message(EncodingConfig, Version, Message) -> {ok, Bin} | Error</name> <fsummary>Encode a megaco message.</fsummary> <type> <v>EncodingConfig = list()</v> @@ -81,7 +81,7 @@ action_reply() = #'ActionReply'{} </func> <func> - <name>Module:decode_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name> + <name since="">Module:decode_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name> <fsummary>Decode a megaco message.</fsummary> <type> <v>EncodingConfig = list()</v> @@ -104,7 +104,7 @@ action_reply() = #'ActionReply'{} </func> <func> - <name>Module:decode_mini_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name> + <name since="">Module:decode_mini_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name> <fsummary>Perform a minimal decode of a megaco message.</fsummary> <type> <v>EncodingConfig = list()</v> @@ -129,7 +129,7 @@ action_reply() = #'ActionReply'{} </func> <func> - <name>Module:encode_transaction(EncodingConfig, Version, Transaction) -> OK | Error</name> + <name since="">Module:encode_transaction(EncodingConfig, Version, Transaction) -> OK | Error</name> <fsummary>Encode a megaco transaction.</fsummary> <type> <v>EncodingConfig = list()</v> @@ -155,7 +155,7 @@ action_reply() = #'ActionReply'{} </func> <func> - <name>Module:encode_action_requests(EncodingConfig, Version, ARs) -> OK | Error</name> + <name since="">Module:encode_action_requests(EncodingConfig, Version, ARs) -> OK | Error</name> <fsummary>Encode megaco action requests.</fsummary> <type> <v>EncodingConfig = list()</v> @@ -181,7 +181,7 @@ action_reply() = #'ActionReply'{} </func> <func> - <name>Module:encode_action_reply(EncodingConfig, Version, AR) -> OK | Error</name> + <name since="">Module:encode_action_reply(EncodingConfig, Version, AR) -> OK | Error</name> <fsummary>Encode a megaco action reply.</fsummary> <type> <v>EncodingConfig = list()</v> diff --git a/lib/megaco/doc/src/megaco_flex_scanner.xml b/lib/megaco/doc/src/megaco_flex_scanner.xml index 0856f3f429..121a7fbcff 100644 --- a/lib/megaco/doc/src/megaco_flex_scanner.xml +++ b/lib/megaco/doc/src/megaco_flex_scanner.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_flex_scanner.xml</file> </header> - <module>megaco_flex_scanner</module> + <module since="">megaco_flex_scanner</module> <modulesummary>Interface module to the flex scanner linked in driver.</modulesummary> <description> <p>This module contains the public interface to the flex scanner @@ -72,7 +72,7 @@ megaco_version() = integer() >= 1 <funcs> <func> - <name>start() -> {ok, PortOrPorts} | {error, Reason}</name> + <name since="">start() -> {ok, PortOrPorts} | {error, Reason}</name> <fsummary></fsummary> <type> <v>PortOrPorts = megaco_ports()</v> @@ -94,7 +94,7 @@ megaco_version() = integer() >= 1 </func> <func> - <name>stop(PortOrPorts) -> stopped</name> + <name since="">stop(PortOrPorts) -> stopped</name> <fsummary></fsummary> <type> <v>PortOrPorts = megaco_ports()</v> @@ -108,7 +108,7 @@ megaco_version() = integer() >= 1 </func> <func> - <name>is_reentrant_enabled() -> Boolean</name> + <name since="">is_reentrant_enabled() -> Boolean</name> <fsummary></fsummary> <type> <v>Boolean = boolean()</v> @@ -121,7 +121,7 @@ megaco_version() = integer() >= 1 </func> <func> - <name>is_scanner_port(Port, PortOrPorts) -> Boolean</name> + <name since="">is_scanner_port(Port, PortOrPorts) -> Boolean</name> <fsummary></fsummary> <type> <v>Port = port()</v> @@ -137,7 +137,7 @@ megaco_version() = integer() >= 1 </func> <func> - <name>scan(Binary, PortOrPorts) -> {ok, Tokens, Version, LatestLine} | {error, Reason, LatestLine} </name> + <name since="">scan(Binary, PortOrPorts) -> {ok, Tokens, Version, LatestLine} | {error, Reason, LatestLine} </name> <fsummary></fsummary> <type> <v>Binary = binary()</v> diff --git a/lib/megaco/doc/src/megaco_tcp.xml b/lib/megaco/doc/src/megaco_tcp.xml index 77aee32f6c..63713b2c56 100644 --- a/lib/megaco/doc/src/megaco_tcp.xml +++ b/lib/megaco/doc/src/megaco_tcp.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_tcp.xml</file> </header> - <module>megaco_tcp</module> + <module since="">megaco_tcp</module> <modulesummary>Interface module to TPKT transport protocol for Megaco/H.248.</modulesummary> <description> <p>This module contains the public interface to the TPKT (TCP/IP) version @@ -40,7 +40,7 @@ </description> <funcs> <func> - <name>start_transport() -> {ok, TransportRef}</name> + <name since="">start_transport() -> {ok, TransportRef}</name> <fsummary></fsummary> <type> <v>TransportRef = pid()</v> @@ -51,7 +51,7 @@ </desc> </func> <func> - <name>listen(TransportRef, ListenPortSpecList) -> ok</name> + <name since="">listen(TransportRef, ListenPortSpecList) -> ok</name> <fsummary></fsummary> <type> <v>TransportRef = pid() | regname()</v> @@ -65,7 +65,7 @@ </desc> </func> <func> - <name>connect(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name> + <name since="">connect(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name> <fsummary></fsummary> <type> <v>TransportRef = pid() | regname()</v> @@ -86,7 +86,7 @@ </desc> </func> <func> - <name>close(Handle) -> ok</name> + <name since="">close(Handle) -> ok</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -96,7 +96,7 @@ </desc> </func> <func> - <name>socket(Handle) -> Socket</name> + <name since="">socket(Handle) -> Socket</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -109,7 +109,7 @@ </desc> </func> <func> - <name>send_message(Handle, Message) -> ok</name> + <name since="">send_message(Handle, Message) -> ok</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -120,7 +120,7 @@ </desc> </func> <func> - <name>block(Handle) -> ok</name> + <name since="">block(Handle) -> ok</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -130,7 +130,7 @@ </desc> </func> <func> - <name>unblock(Handle) -> ok</name> + <name since="">unblock(Handle) -> ok</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -141,7 +141,7 @@ </desc> </func> <func> - <name>upgrade_receive_handle(ControlPid) -> ok</name> + <name since="">upgrade_receive_handle(ControlPid) -> ok</name> <fsummary></fsummary> <type> <v>ControlPid = pid()</v> @@ -153,9 +153,9 @@ </desc> </func> <func> - <name>get_stats() -> {ok, TotalStats} | {error, Reason}</name> - <name>get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name> - <name>get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name> + <name since="">get_stats() -> {ok, TotalStats} | {error, Reason}</name> + <name since="">get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name> + <name since="">get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name> <fsummary></fsummary> <type> <v>TotalStats = [send_handle_stats()]</v> @@ -173,8 +173,8 @@ </desc> </func> <func> - <name>reset_stats() -> void()</name> - <name>reset_stats(SendHandle) -> void()</name> + <name since="">reset_stats() -> void()</name> + <name since="">reset_stats(SendHandle) -> void()</name> <fsummary></fsummary> <type> <v>SendHandle = send_handle()</v> diff --git a/lib/megaco/doc/src/megaco_transport.xml b/lib/megaco/doc/src/megaco_transport.xml index 3002e9b74e..ba8c794750 100644 --- a/lib/megaco/doc/src/megaco_transport.xml +++ b/lib/megaco/doc/src/megaco_transport.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_transport.xml</file> </header> - <module>megaco_transport</module> + <module since="">megaco_transport</module> <modulesummary>Megaco transport behaviour.</modulesummary> <description> <p>The following functions should be exported from a @@ -54,8 +54,8 @@ </description> <funcs> <func> - <name>Module:send_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name> - <name>Module:send_message(Handle, Msg, Resend) -> ok | {cancel, Reason} | Error</name> + <name since="">Module:send_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name> + <name since="">Module:send_message(Handle, Msg, Resend) -> ok | {cancel, Reason} | Error</name> <fsummary>Send a megaco message.</fsummary> <type> <v>Handle = term()</v> @@ -99,7 +99,7 @@ </func> <func> - <name>Module:resend_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name> + <name since="">Module:resend_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name> <fsummary>Re-send a megaco message.</fsummary> <type> <v>Handle = term()</v> diff --git a/lib/megaco/doc/src/megaco_udp.xml b/lib/megaco/doc/src/megaco_udp.xml index b2559c77d5..3d776c19b6 100644 --- a/lib/megaco/doc/src/megaco_udp.xml +++ b/lib/megaco/doc/src/megaco_udp.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_udp.xml</file> </header> - <module>megaco_udp</module> + <module since="">megaco_udp</module> <modulesummary>Interface module to UDP transport protocol for Megaco/H.248.</modulesummary> <description> <p>This module contains the public interface to the UDP/IP version @@ -40,7 +40,7 @@ </description> <funcs> <func> - <name>start_transport() -> {ok, TransportRef}</name> + <name since="">start_transport() -> {ok, TransportRef}</name> <fsummary></fsummary> <type> <v>TransportRef = pid()</v> @@ -51,7 +51,7 @@ </desc> </func> <func> - <name>open(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name> + <name since="">open(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name> <fsummary></fsummary> <type> <v>TransportRef = pid() | regname()</v> @@ -73,7 +73,7 @@ </desc> </func> <func> - <name>close(Handle, Msg) -> ok</name> + <name since="">close(Handle, Msg) -> ok</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -84,7 +84,7 @@ </desc> </func> <func> - <name>socket(Handle) -> Socket</name> + <name since="">socket(Handle) -> Socket</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -97,7 +97,7 @@ </desc> </func> <func> - <name>create_send_handle(Handle, Host, Port) -> send_handle()</name> + <name since="">create_send_handle(Handle, Host, Port) -> send_handle()</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -110,7 +110,7 @@ </desc> </func> <func> - <name>send_message(SendHandle, Msg) -> ok</name> + <name since="">send_message(SendHandle, Msg) -> ok</name> <fsummary></fsummary> <type> <v>SendHandle = send_handle()</v> @@ -125,7 +125,7 @@ </desc> </func> <func> - <name>block(Handle) -> ok</name> + <name since="">block(Handle) -> ok</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -135,7 +135,7 @@ </desc> </func> <func> - <name>unblock(Handle) -> ok</name> + <name since="">unblock(Handle) -> ok</name> <fsummary></fsummary> <type> <v>Handle = socket_handle()</v> @@ -146,7 +146,7 @@ </desc> </func> <func> - <name>upgrade_receive_handle(ControlPid, NewHandle) -> ok</name> + <name since="">upgrade_receive_handle(ControlPid, NewHandle) -> ok</name> <fsummary></fsummary> <type> <v>ControlPid = pid()</v> @@ -160,9 +160,9 @@ </desc> </func> <func> - <name>get_stats() -> {ok, TotalStats} | {error, Reason}</name> - <name>get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name> - <name>get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name> + <name since="">get_stats() -> {ok, TotalStats} | {error, Reason}</name> + <name since="">get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name> + <name since="">get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name> <fsummary></fsummary> <type> <v>TotalStats = [total_stats()]</v> @@ -180,8 +180,8 @@ </desc> </func> <func> - <name>reset_stats() -> void()</name> - <name>reset_stats(SendHandle) -> void()</name> + <name since="">reset_stats() -> void()</name> + <name since="">reset_stats(SendHandle) -> void()</name> <fsummary></fsummary> <type> <v>SendHandle = send_handle()</v> diff --git a/lib/megaco/doc/src/megaco_user.xml b/lib/megaco/doc/src/megaco_user.xml index 067be15fe0..198f2aa24c 100644 --- a/lib/megaco/doc/src/megaco_user.xml +++ b/lib/megaco/doc/src/megaco_user.xml @@ -32,7 +32,7 @@ <rev>%VSN%</rev> <file>megaco_user.xml</file> </header> - <module>megaco_user</module> + <module since="">megaco_user</module> <modulesummary>Callback module for users of the Megaco application</modulesummary> <description> <p>This module defines the callback behaviour of Megaco users. A @@ -164,8 +164,8 @@ protocol_version() = integer() ]]></code> <funcs> <func> - <name>handle_connect(ConnHandle, ProtocolVersion) -> ok | error | {error,ErrorDescr}</name> - <name>handle_connect(ConnHandle, ProtocolVersion, Extra]) -> ok | error | {error,ErrorDescr}</name> + <name since="">handle_connect(ConnHandle, ProtocolVersion) -> ok | error | {error,ErrorDescr}</name> + <name since="">handle_connect(ConnHandle, ProtocolVersion, Extra]) -> ok | error | {error,ErrorDescr}</name> <fsummary>Invoked when a new connection is established</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -202,7 +202,7 @@ protocol_version() = integer() ]]></code> </func> <func> - <name>handle_disconnect(ConnHandle, ProtocolVersion, Reason) -> ok</name> + <name since="">handle_disconnect(ConnHandle, ProtocolVersion, Reason) -> ok</name> <fsummary>Invoked when a connection is teared down</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -220,8 +220,8 @@ protocol_version() = integer() ]]></code> </func> <func> - <name>handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name> - <name>handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED, Extra) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name> + <name since="">handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name> + <name since="">handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED, Extra) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name> <fsummary>Invoked when a received message had syntax errors</fsummary> <type> <v>ReceiveHandle = receive_handle()</v> @@ -258,8 +258,8 @@ protocol_version() = integer() ]]></code> </func> <func> - <name>handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr) -> ok</name> - <name>handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr, Extra) -> ok</name> + <name since="">handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr) -> ok</name> + <name since="">handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr, Extra) -> ok</name> <fsummary>Invoked when a received message just contains an error</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -291,8 +291,8 @@ protocol_version() = integer() ]]></code> <!-- <func> - <name>handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError) -> ok</name> - <name>handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError, Extra) -> ok</name> + <name since="">handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError) -> ok</name> + <name since="">handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError, Extra) -> ok</name> <fsummary>Invoked when a segment error has been detected</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -316,8 +316,8 @@ protocol_version() = integer() ]]></code> --> <func> - <name>handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) -> pending() | reply() | ignore_trans_request</name> - <name>handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests, Extra) -> pending() | reply() | ignore_trans_request</name> + <name since="">handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) -> pending() | reply() | ignore_trans_request</name> + <name since="">handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests, Extra) -> pending() | reply() | ignore_trans_request</name> <fsummary>Invoked for each transaction request</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -420,8 +420,8 @@ protocol_version() = integer() ]]></code> </func> <func> - <name>handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData) -> reply()</name> - <name>handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Extra) -> reply()</name> + <name since="">handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData) -> reply()</name> + <name since="">handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Extra) -> reply()</name> <fsummary>Optionally invoked for a time consuming transaction request</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -460,8 +460,8 @@ protocol_version() = integer() ]]></code> </func> <func> - <name>handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData) -> ok</name> - <name>handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData, Extra) -> ok</name> + <name since="">handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData) -> ok</name> + <name since="">handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData, Extra) -> ok</name> <fsummary>Optionally invoked for a transaction reply</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -593,8 +593,8 @@ protocol_version() = integer() ]]></code> </func> <func> - <name>handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) -> ok</name> - <name>handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Extra) -> ok</name> + <name since="">handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) -> ok</name> + <name since="">handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Extra) -> ok</name> <fsummary>Optionally invoked for a transaction acknowledgement</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -658,8 +658,8 @@ protocol_version() = integer() ]]></code> </func> <func> - <name>handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) -> ok</name> - <name>handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans, Extra) -> ok</name> + <name since="">handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) -> ok</name> + <name since="">handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans, Extra) -> ok</name> <fsummary>Invoked when an unexpected message is received</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -685,8 +685,8 @@ protocol_version() = integer() ]]></code> </func> <func> - <name>handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid) -> ok</name> - <name>handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid, Extra) -> ok</name> + <name since="">handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid) -> ok</name> + <name since="">handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid, Extra) -> ok</name> <fsummary>Invoked when an transaction request has been aborted</fsummary> <type> <v>ConnHandle = conn_handle()</v> @@ -710,8 +710,8 @@ protocol_version() = integer() ]]></code> </func> <func> - <name>handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl) -> ok</name> - <name>handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl, Extra) -> ok</name> + <name since="">handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl) -> ok</name> + <name since="">handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl, Extra) -> ok</name> <fsummary>Segment Reply Indication</fsummary> <type> <v>ConnHandle = conn_handle()</v> diff --git a/lib/mnesia/doc/src/mnesia.xml b/lib/mnesia/doc/src/mnesia.xml index 621b6047ee..11b0b8e987 100644 --- a/lib/mnesia/doc/src/mnesia.xml +++ b/lib/mnesia/doc/src/mnesia.xml @@ -32,7 +32,7 @@ <rev></rev> <file></file> </header> - <module>mnesia</module> + <module since="">mnesia</module> <modulesummary>A distributed telecommunications DBMS</modulesummary> <description> @@ -183,7 +183,7 @@ <funcs> <func> - <name>abort(Reason) -> transaction abort</name> + <name since="">abort(Reason) -> transaction abort</name> <fsummary>Terminates the current transaction.</fsummary> <desc> <p>Makes the transaction silently @@ -195,7 +195,7 @@ </desc> </func> <func> - <name>activate_checkpoint(Args) -> {ok,Name,Nodes} | {error,Reason}</name> + <name since="">activate_checkpoint(Args) -> {ok,Name,Nodes} | {error,Reason}</name> <fsummary>Activates a checkpoint.</fsummary> <desc> <marker id="activate_checkpoint"></marker> @@ -259,7 +259,7 @@ </desc> </func> <func> - <name>activity(AccessContext, Fun [, Args]) -> ResultOfFun | exit(Reason)</name> + <name since="">activity(AccessContext, Fun [, Args]) -> ResultOfFun | exit(Reason)</name> <fsummary>Executes <c>Fun</c> in <c>AccessContext</c>.</fsummary> <desc> <marker id="activity_2_3"></marker> @@ -271,7 +271,7 @@ </desc> </func> <func> - <name>activity(AccessContext, Fun, Args, AccessMod) -> ResultOfFun | exit(Reason)</name> + <name since="">activity(AccessContext, Fun, Args, AccessMod) -> ResultOfFun | exit(Reason)</name> <fsummary>Executes <c>Fun</c> in <c>AccessContext</c>.</fsummary> <desc> <marker id="activity_4"></marker> @@ -403,7 +403,7 @@ </desc> </func> <func> - <name>add_table_copy(Tab, Node, Type) -> {aborted, R} | {atomic, ok}</name> + <name since="">add_table_copy(Tab, Node, Type) -> {aborted, R} | {atomic, ok}</name> <fsummary>Copies a table to a remote node.</fsummary> <desc> <marker id="add_table_copy"></marker> @@ -420,7 +420,7 @@ mnesia:add_table_copy(person, Node, disc_copies)</code> </desc> </func> <func> - <name>add_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name> + <name since="">add_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name> <fsummary>Creates an index for a table.</fsummary> <desc> <marker id="add_table_index"></marker> @@ -441,7 +441,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>all_keys(Tab) -> KeyList | transaction abort</name> + <name since="">all_keys(Tab) -> KeyList | transaction abort</name> <fsummary>Returns all keys in a table.</fsummary> <desc> <marker id="all_keys"></marker> @@ -453,7 +453,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>async_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> + <name since="">async_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> <fsummary>Calls the <c>Fun</c> in a context that is not protected by a transaction.</fsummary> <desc> <marker id="async_dirty"></marker> @@ -493,7 +493,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>backup(Opaque [, BackupMod]) -> ok | {error,Reason}</name> + <name since="">backup(Opaque [, BackupMod]) -> ok | {error,Reason}</name> <fsummary>Backs up all tables in the database.</fsummary> <desc> <marker id="backup"></marker> @@ -505,7 +505,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>backup_checkpoint(Name, Opaque [, BackupMod]) -> ok | {error,Reason}</name> + <name since="">backup_checkpoint(Name, Opaque [, BackupMod]) -> ok | {error,Reason}</name> <fsummary>Backs up all tables in a checkpoint.</fsummary> <desc> <marker id="backup_checkpoint"></marker> @@ -520,7 +520,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>change_config(Config, Value) -> {error, Reason} | {ok, ReturnValue}</name> + <name since="">change_config(Config, Value) -> {error, Reason} | {ok, ReturnValue}</name> <fsummary>Changes a configuration parameter.</fsummary> <desc> <marker id="change_config"></marker> @@ -554,7 +554,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>change_table_access_mode(Tab, AccessMode) -> {aborted, R} | {atomic, ok}</name> + <name since="">change_table_access_mode(Tab, AccessMode) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes the access mode for the table.</fsummary> <desc> <marker id="change_table_access_mode"></marker> @@ -568,7 +568,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>change_table_copy_type(Tab, Node, To) -> {aborted, R} | {atomic, ok}</name> + <name since="">change_table_copy_type(Tab, Node, To) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes the storage type of a table.</fsummary> <desc> <marker id="change_table_copy_type"></marker> @@ -585,7 +585,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>change_table_load_order(Tab, LoadOrder) -> {aborted, R} | {atomic, ok}</name> + <name since="">change_table_load_order(Tab, LoadOrder) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes the load order priority for the table.</fsummary> <desc> <marker id="change_table_load_order"></marker> @@ -595,7 +595,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>change_table_majority(Tab, Majority) -> {aborted, R} | {atomic, ok}</name> + <name since="OTP R14B03">change_table_majority(Tab, Majority) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes the majority check setting for the table.</fsummary> <desc> <p><c>Majority</c> must be a boolean. Default is <c>false</c>. @@ -607,7 +607,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>clear_table(Tab) -> {aborted, R} | {atomic, ok}</name> + <name since="">clear_table(Tab) -> {aborted, R} | {atomic, ok}</name> <fsummary>Deletes all entries in a table.</fsummary> <desc> <marker id="clear_table"></marker> @@ -615,7 +615,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>create_schema(DiscNodes) -> ok | {error,Reason}</name> + <name since="">create_schema(DiscNodes) -> ok | {error,Reason}</name> <fsummary>Creates a new schema on the specified nodes.</fsummary> <desc> <marker id="create_schema"></marker> @@ -637,7 +637,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>create_table(Name, TabDef) -> {atomic, ok} | {aborted, Reason}</name> + <name since="">create_table(Name, TabDef) -> {atomic, ok} | {aborted, Reason}</name> <fsummary>Creates a Mnesia table called <c>Name</c>with properties as described by argument <c>TabDef</c>.</fsummary> <desc> <marker id="create_table"></marker> @@ -799,7 +799,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>deactivate_checkpoint(Name) -> ok | {error, Reason}</name> + <name since="">deactivate_checkpoint(Name) -> ok | {error, Reason}</name> <fsummary>Deactivates a checkpoint.</fsummary> <desc> <marker id="deactivate_checkpoint"></marker> @@ -811,7 +811,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>del_table_copy(Tab, Node) -> {aborted, R} | {atomic, ok}</name> + <name since="">del_table_copy(Tab, Node) -> {aborted, R} | {atomic, ok}</name> <fsummary>Deletes the replica of table <c>Tab</c> at node <c>Node</c>.</fsummary> <desc> <marker id="del_table_copy"></marker> @@ -825,7 +825,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>del_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name> + <name since="">del_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name> <fsummary>Deletes an index in a table.</fsummary> <desc> <marker id="del_table_index"></marker> @@ -834,7 +834,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete({Tab, Key}) -> transaction abort | ok</name> + <name since="">delete({Tab, Key}) -> transaction abort | ok</name> <fsummary>Deletes all records in table <c>Tab</c> with the key <c>Key</c>.</fsummary> <desc> <marker id="delete_2"></marker> @@ -842,7 +842,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete(Tab, Key, LockKind) -> transaction abort | ok</name> + <name since="">delete(Tab, Key, LockKind) -> transaction abort | ok</name> <fsummary>Deletes all records in table <c>Tab</c>with the key <c>Key</c>.</fsummary> <desc> <marker id="delete_3"></marker> @@ -857,7 +857,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete_object(Record) -> transaction abort | ok</name> + <name since="">delete_object(Record) -> transaction abort | ok</name> <fsummary>Delete a record.</fsummary> <desc> <marker id="delete_object_1"></marker> @@ -866,7 +866,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete_object(Tab, Record, LockKind) -> transaction abort | ok</name> + <name since="">delete_object(Tab, Record, LockKind) -> transaction abort | ok</name> <fsummary>Deletes a record.</fsummary> <desc> <marker id="delete_object_3"></marker> @@ -883,7 +883,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete_schema(DiscNodes) -> ok | {error,Reason}</name> + <name since="">delete_schema(DiscNodes) -> ok | {error,Reason}</name> <fsummary>Deletes the schema on the given nodes.</fsummary> <desc> <marker id="delete_schema"></marker> @@ -904,7 +904,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete_table(Tab) -> {aborted, Reason} | {atomic, ok}</name> + <name since="">delete_table(Tab) -> {aborted, Reason} | {atomic, ok}</name> <fsummary>Deletes permanently all replicas of table <c>Tab</c>.</fsummary> <desc> <marker id="delete_table"></marker> @@ -912,7 +912,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_all_keys(Tab) -> KeyList | exit({aborted, Reason})</name> + <name since="">dirty_all_keys(Tab) -> KeyList | exit({aborted, Reason})</name> <fsummary>Dirty search for all record keys in table.</fsummary> <desc> <marker id="delete_all_keys"></marker> @@ -920,7 +920,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_delete({Tab, Key}) -> ok | exit({aborted, Reason})</name> + <name since="">dirty_delete({Tab, Key}) -> ok | exit({aborted, Reason})</name> <fsummary>Dirty delete of a record.</fsummary> <desc> <marker id="dirty_delete"></marker> @@ -928,14 +928,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_delete(Tab, Key) -> ok | exit({aborted, Reason})</name> + <name since="">dirty_delete(Tab, Key) -> ok | exit({aborted, Reason})</name> <fsummary>Dirty delete of a record.</fsummary> <desc> <p>Dirty equivalent of the function <c>mnesia:delete/3</c>.</p> </desc> </func> <func> - <name>dirty_delete_object(Record)</name> + <name since="">dirty_delete_object(Record)</name> <fsummary>Dirty delete of a record.</fsummary> <desc> <marker id="dirty_delete_object_1"></marker> @@ -944,14 +944,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_delete_object(Tab, Record)</name> + <name since="">dirty_delete_object(Tab, Record)</name> <fsummary>Dirty delete of a record.</fsummary> <desc> <p>Dirty equivalent of the function <c>mnesia:delete_object/3</c>.</p> </desc> </func> <func> - <name>dirty_first(Tab) -> Key | exit({aborted, Reason})</name> + <name since="">dirty_first(Tab) -> Key | exit({aborted, Reason})</name> <fsummary>Returns the key for the first record in a table.</fsummary> <desc> <marker id="dirty_first"></marker> @@ -967,7 +967,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_index_match_object(Pattern, Pos)</name> + <name since="">dirty_index_match_object(Pattern, Pos)</name> <fsummary>Dirty pattern match using index.</fsummary> <desc> <marker id="dirty_index_match_object_2"></marker> @@ -977,7 +977,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_index_match_object(Tab, Pattern, Pos)</name> + <name since="">dirty_index_match_object(Tab, Pattern, Pos)</name> <fsummary>Dirty pattern match using index.</fsummary> <desc> <p>Dirty equivalent of the function @@ -985,7 +985,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_index_read(Tab, SecondaryKey, Pos)</name> + <name since="">dirty_index_read(Tab, SecondaryKey, Pos)</name> <fsummary>Dirty read using index.</fsummary> <desc> <marker id="dirty_index_read"></marker> @@ -994,7 +994,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_last(Tab) -> Key | exit({aborted, Reason})</name> + <name since="">dirty_last(Tab) -> Key | exit({aborted, Reason})</name> <fsummary>Returns the key for the last record in a table.</fsummary> <desc> <marker id="dirty_last"></marker> @@ -1006,7 +1006,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_match_object(Pattern) -> RecordList | exit({aborted, Reason})</name> + <name since="">dirty_match_object(Pattern) -> RecordList | exit({aborted, Reason})</name> <fsummary>Dirty pattern match pattern.</fsummary> <desc> <marker id="dirty_match_object_1"></marker> @@ -1015,7 +1015,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_match_object(Tab, Pattern) -> RecordList | exit({aborted, Reason})</name> + <name since="">dirty_match_object(Tab, Pattern) -> RecordList | exit({aborted, Reason})</name> <fsummary>Dirty pattern match pattern.</fsummary> <desc> <p>Dirty equivalent of the function @@ -1023,7 +1023,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_next(Tab, Key) -> Key | exit({aborted, Reason})</name> + <name since="">dirty_next(Tab, Key) -> Key | exit({aborted, Reason})</name> <fsummary>Return the next key in a table.</fsummary> <desc> <marker id="dirty_next"></marker> @@ -1038,7 +1038,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_prev(Tab, Key) -> Key | exit({aborted, Reason})</name> + <name since="">dirty_prev(Tab, Key) -> Key | exit({aborted, Reason})</name> <fsummary>Returns the previous key in a table.</fsummary> <desc> <marker id="dirty_prev"></marker> @@ -1050,7 +1050,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_read({Tab, Key}) -> ValueList | exit({aborted, Reason}</name> + <name since="">dirty_read({Tab, Key}) -> ValueList | exit({aborted, Reason}</name> <fsummary>Dirty read of records.</fsummary> <desc> <marker id="dirty_read"></marker> @@ -1058,14 +1058,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_read(Tab, Key) -> ValueList | exit({aborted, Reason}</name> + <name since="">dirty_read(Tab, Key) -> ValueList | exit({aborted, Reason}</name> <fsummary>Dirty read of records.</fsummary> <desc> <p>Dirty equivalent of the function <c>mnesia:read/3</c>.</p> </desc> </func> <func> - <name>dirty_select(Tab, MatchSpec) -> ValueList | exit({aborted, Reason}</name> + <name since="">dirty_select(Tab, MatchSpec) -> ValueList | exit({aborted, Reason}</name> <fsummary>Dirty matches the objects in <c>Tab</c> against <c>MatchSpec</c>.</fsummary> <desc> <marker id="dirty_select"></marker> @@ -1073,7 +1073,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_slot(Tab, Slot) -> RecordList | exit({aborted, Reason})</name> + <name since="">dirty_slot(Tab, Slot) -> RecordList | exit({aborted, Reason})</name> <fsummary>Returns the list of records that are associated with <c>Slot</c> in a table.</fsummary> <desc> <marker id="dirty_slot"></marker> @@ -1089,7 +1089,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_update_counter({Tab, Key}, Incr) -> NewVal | exit({aborted, Reason})</name> + <name since="">dirty_update_counter({Tab, Key}, Incr) -> NewVal | exit({aborted, Reason})</name> <fsummary>Dirty update of a counter record.</fsummary> <desc> <marker id="dirty_update_counter"></marker> @@ -1097,7 +1097,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_update_counter(Tab, Key, Incr) -> NewVal | exit({aborted, Reason})</name> + <name since="">dirty_update_counter(Tab, Key, Incr) -> NewVal | exit({aborted, Reason})</name> <fsummary>Dirty update of a counter record.</fsummary> <desc> <p>Mnesia has no special counter records. However, @@ -1126,7 +1126,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_write(Record) -> ok | exit({aborted, Reason})</name> + <name since="">dirty_write(Record) -> ok | exit({aborted, Reason})</name> <fsummary>Dirty write of a record.</fsummary> <desc> <marker id="dirty_write_1"></marker> @@ -1135,14 +1135,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_write(Tab, Record) -> ok | exit({aborted, Reason})</name> + <name since="">dirty_write(Tab, Record) -> ok | exit({aborted, Reason})</name> <fsummary>Dirty write of a record.</fsummary> <desc> <p>Dirty equivalent of the function <c>mnesia:write/3</c>.</p> </desc> </func> <func> - <name>dump_log() -> dumped</name> + <name since="">dump_log() -> dumped</name> <fsummary>Performs a user-initiated dump of the local log file.</fsummary> <desc> <marker id="dump_log"></marker> @@ -1156,7 +1156,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dump_tables(TabList) -> {atomic, ok} | {aborted, Reason}</name> + <name since="">dump_tables(TabList) -> {atomic, ok} | {aborted, Reason}</name> <fsummary>Dumps all RAM tables to disc.</fsummary> <desc> <marker id="dump_tables"></marker> @@ -1168,7 +1168,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dump_to_textfile(Filename)</name> + <name since="">dump_to_textfile(Filename)</name> <fsummary>Dumps local tables into a text file.</fsummary> <desc> <marker id="dump_to_textfile"></marker> @@ -1181,7 +1181,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>error_description(Error) -> String</name> + <name since="">error_description(Error) -> String</name> <fsummary>Returns a string describing a particular Mnesia error.</fsummary> <desc> <marker id="error_description"></marker> @@ -1259,7 +1259,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>ets(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> + <name since="">ets(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> <fsummary>Calls the <c>Fun</c> in a raw context that is not protected by a transaction.</fsummary> <desc> <marker id="ets"></marker> @@ -1278,7 +1278,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>first(Tab) -> Key | transaction abort</name> + <name since="">first(Tab) -> Key | transaction abort</name> <fsummary>Returns the key for the first record in a table.</fsummary> <desc> <marker id="first"></marker> @@ -1293,7 +1293,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>foldl(Function, Acc, Table) -> NewAcc | transaction abort</name> + <name since="">foldl(Function, Acc, Table) -> NewAcc | transaction abort</name> <fsummary>Calls <c>Function</c> for each record in <c>Table</c>.</fsummary> <desc> <marker id="foldl"></marker> @@ -1306,7 +1306,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>foldr(Function, Acc, Table) -> NewAcc | transaction abort</name> + <name since="">foldr(Function, Acc, Table) -> NewAcc | transaction abort</name> <fsummary>Calls <c>Function</c> for each record in <c>Table</c>.</fsummary> <desc> <marker id="foldr"></marker> @@ -1317,7 +1317,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>force_load_table(Tab) -> yes | ErrorDescription</name> + <name since="">force_load_table(Tab) -> yes | ErrorDescription</name> <fsummary>Forces a table to be loaded into the system.</fsummary> <desc> <marker id="force_load_table"></marker> @@ -1335,7 +1335,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>index_match_object(Pattern, Pos) -> transaction abort | ObjList</name> + <name since="">index_match_object(Pattern, Pos) -> transaction abort | ObjList</name> <fsummary>Matches records and uses index information.</fsummary> <desc> <marker id="index_match_object_2"></marker> @@ -1345,7 +1345,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>index_match_object(Tab, Pattern, Pos, LockKind) -> transaction abort | ObjList</name> + <name since="">index_match_object(Tab, Pattern, Pos, LockKind) -> transaction abort | ObjList</name> <fsummary>Matches records and uses index information.</fsummary> <desc> <marker id="index_match_object_4"></marker> @@ -1377,7 +1377,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>index_read(Tab, SecondaryKey, Pos) -> transaction abort | RecordList</name> + <name since="">index_read(Tab, SecondaryKey, Pos) -> transaction abort | RecordList</name> <fsummary>Reads records through index table.</fsummary> <desc> <marker id="index_read"></marker> @@ -1397,7 +1397,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>info() -> ok</name> + <name since="">info() -> ok</name> <fsummary>Prints system information on the terminal.</fsummary> <desc> <marker id="info"></marker> @@ -1408,7 +1408,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>install_fallback(Opaque) -> ok | {error,Reason}</name> + <name since="">install_fallback(Opaque) -> ok | {error,Reason}</name> <fsummary>Installs a backup as fallback.</fsummary> <desc> <marker id="install_fallback_1"></marker> @@ -1417,7 +1417,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>install_fallback(Opaque), BackupMod) -> ok | {error,Reason}</name> + <name since="">install_fallback(Opaque), BackupMod) -> ok | {error,Reason}</name> <fsummary>Installs a backup as fallback.</fsummary> <desc> <p>Calls <c>mnesia:install_fallback(Opaque, Args)</c>, where @@ -1425,7 +1425,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>install_fallback(Opaque, Args) -> ok | {error,Reason}</name> + <name since="">install_fallback(Opaque, Args) -> ok | {error,Reason}</name> <fsummary>Installs a backup as fallback.</fsummary> <desc> <p>Installs a backup as fallback. The fallback is used to @@ -1483,7 +1483,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>is_transaction() -> boolean</name> + <name since="">is_transaction() -> boolean</name> <fsummary>Checks if code is running in a transaction.</fsummary> <desc> <marker id="is_transaction"></marker> @@ -1492,7 +1492,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>last(Tab) -> Key | transaction abort</name> + <name since="">last(Tab) -> Key | transaction abort</name> <fsummary>Returns the key for the last record in a table.</fsummary> <desc> <p>Works exactly like @@ -1503,7 +1503,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>load_textfile(Filename)</name> + <name since="">load_textfile(Filename)</name> <fsummary>Loads tables from a text file.</fsummary> <desc> <marker id="load_textfile"></marker> @@ -1516,7 +1516,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>lock(LockItem, LockKind) -> Nodes | ok | transaction abort</name> + <name since="">lock(LockItem, LockKind) -> Nodes | ok | transaction abort</name> <fsummary>Explicit grab lock.</fsummary> <desc> <marker id="lock"></marker> @@ -1605,7 +1605,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>match_object(Pattern) -> transaction abort | RecList</name> + <name since="">match_object(Pattern) -> transaction abort | RecList</name> <fsummary>Matches <c>Pattern</c> for records.</fsummary> <desc> <marker id="match_object_1"></marker> @@ -1614,7 +1614,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>match_object(Tab, Pattern, LockKind) -> transaction abort | RecList</name> + <name since="">match_object(Tab, Pattern, LockKind) -> transaction abort | RecList</name> <fsummary>Matches <c>Pattern</c> for records.</fsummary> <desc> <marker id="match_object_3"></marker> @@ -1639,7 +1639,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>move_table_copy(Tab, From, To) -> {aborted, Reason} | {atomic, ok}</name> + <name since="">move_table_copy(Tab, From, To) -> {aborted, Reason} | {atomic, ok}</name> <fsummary>Moves the copy of table <c>Tab</c> from node <c>From</c> to node <c>To</c>.</fsummary> <desc> <marker id="move_table_copy"></marker> @@ -1653,7 +1653,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>next(Tab, Key) -> Key | transaction abort</name> + <name since="">next(Tab, Key) -> Key | transaction abort</name> <fsummary>Returns the next key in a table.</fsummary> <desc> <marker id="next"></marker> @@ -1665,7 +1665,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>prev(Tab, Key) -> Key | transaction abort</name> + <name since="">prev(Tab, Key) -> Key | transaction abort</name> <fsummary>Returns the previous key in a table.</fsummary> <desc> <p>Works exactly like @@ -1676,7 +1676,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>read({Tab, Key}) -> transaction abort | RecordList</name> + <name since="">read({Tab, Key}) -> transaction abort | RecordList</name> <fsummary>Reads records(s) with a given key.</fsummary> <desc> <marker id="read_2"></marker> @@ -1684,14 +1684,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>read(Tab, Key) -> transaction abort | RecordList</name> + <name since="">read(Tab, Key) -> transaction abort | RecordList</name> <fsummary>Reads records(s) with a given key.</fsummary> <desc> <p>Calls function <c>mnesia:read(Tab, Key, read)</c>.</p> </desc> </func> <func> - <name>read(Tab, Key, LockKind) -> transaction abort | RecordList</name> + <name since="">read(Tab, Key, LockKind) -> transaction abort | RecordList</name> <fsummary>Reads records(s) with a given key.</fsummary> <desc> <marker id="read_3"></marker> @@ -1716,7 +1716,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>read_lock_table(Tab) -> ok | transaction abort</name> + <name since="">read_lock_table(Tab) -> ok | transaction abort</name> <fsummary>Sets a read lock on an entire table.</fsummary> <desc> <marker id="read_lock_table"></marker> @@ -1725,7 +1725,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>report_event(Event) -> ok</name> + <name since="">report_event(Event) -> ok</name> <fsummary>Reports a user event to the Mnesia event handler.</fsummary> <desc> <marker id="report_event"></marker> @@ -1743,7 +1743,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>restore(Opaque, Args) -> {atomic, RestoredTabs} |{aborted, Reason}</name> + <name since="">restore(Opaque, Args) -> {atomic, RestoredTabs} |{aborted, Reason}</name> <fsummary>Online restore of backup.</fsummary> <desc> <marker id="restore"></marker> @@ -1803,7 +1803,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>s_delete({Tab, Key}) -> ok | transaction abort</name> + <name since="">s_delete({Tab, Key}) -> ok | transaction abort</name> <fsummary>Sets sticky lock and delete records.</fsummary> <desc> <marker id="s_delete"></marker> @@ -1812,7 +1812,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>s_delete_object(Record) -> ok | transaction abort</name> + <name since="">s_delete_object(Record) -> ok | transaction abort</name> <fsummary>Sets sticky lock and delete record.</fsummary> <desc> <marker id="s_delete_object"></marker> @@ -1822,7 +1822,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>s_write(Record) -> ok | transaction abort</name> + <name since="">s_write(Record) -> ok | transaction abort</name> <fsummary>Writes <c>Record</c> and sets sticky lock.</fsummary> <desc> <marker id="s_write"></marker> @@ -1832,21 +1832,21 @@ mnesia:create_table(person, </desc> </func> <func> - <name>schema() -> ok</name> + <name since="">schema() -> ok</name> <fsummary>Prints information about all table definitions on the terminal.</fsummary> <desc> <p>Prints information about all table definitions on the terminal.</p> </desc> </func> <func> - <name>schema(Tab) -> ok</name> + <name since="">schema(Tab) -> ok</name> <fsummary>Prints information about one table definition on the terminal.</fsummary> <desc> <p>Prints information about one table definition on the terminal.</p> </desc> </func> <func> - <name>select(Tab, MatchSpec [, Lock]) -> transaction abort | [Object]</name> + <name since="">select(Tab, MatchSpec [, Lock]) -> transaction abort | [Object]</name> <fsummary>Matches the objects in <c>Tab</c> against <c>MatchSpec</c>.</fsummary> <desc> <marker id="select_2_3"></marker> @@ -1884,7 +1884,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>select(Tab, MatchSpec, NObjects, Lock) -> transaction abort | {[Object],Cont} | '$end_of_table'</name> + <name since="">select(Tab, MatchSpec, NObjects, Lock) -> transaction abort | {[Object],Cont} | '$end_of_table'</name> <fsummary>Matches the objects in <c>Tab</c> against <c>MatchSpec</c>.</fsummary> <desc> <marker id="select_4"></marker> @@ -1907,7 +1907,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>select(Cont) -> transaction abort | {[Object],Cont} | '$end_of_table'</name> + <name since="">select(Cont) -> transaction abort | {[Object],Cont} | '$end_of_table'</name> <fsummary>Continues selecting objects.</fsummary> <desc> <p>Selects more objects with the match specification initiated @@ -1919,7 +1919,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>set_debug_level(Level) -> OldLevel</name> + <name since="">set_debug_level(Level) -> OldLevel</name> <fsummary>Changes the internal debug level of Mnesia.</fsummary> <desc> <marker id="set_debug_level"></marker> @@ -1930,7 +1930,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>set_master_nodes(MasterNodes) -> ok | {error, Reason}</name> + <name since="">set_master_nodes(MasterNodes) -> ok | {error, Reason}</name> <fsummary>Sets the master nodes for all tables.</fsummary> <desc> <marker id="set_master_nodes_1"></marker> @@ -1943,7 +1943,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>set_master_nodes(Tab, MasterNodes) -> ok | {error, Reason}</name> + <name since="">set_master_nodes(Tab, MasterNodes) -> ok | {error, Reason}</name> <fsummary>Sets the master nodes for a table.</fsummary> <desc> <marker id="set_master_nodes_2"></marker> @@ -1968,14 +1968,14 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>snmp_close_table(Tab) -> {aborted, R} | {atomic, ok}</name> + <name since="">snmp_close_table(Tab) -> {aborted, R} | {atomic, ok}</name> <fsummary>Removes the possibility for SNMP to manipulate the table.</fsummary> <desc> <p>Removes the possibility for SNMP to manipulate the table.</p> </desc> </func> <func> - <name>snmp_get_mnesia_key(Tab, RowIndex) -> {ok, Key} | undefined</name> + <name since="">snmp_get_mnesia_key(Tab, RowIndex) -> {ok, Key} | undefined</name> <fsummary>Gets the corresponding Mnesia key from an SNMP index.</fsummary> <type> <v>Tab ::= atom()</v> @@ -1990,7 +1990,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>snmp_get_next_index(Tab, RowIndex) -> {ok, NextIndex} | endOfTable</name> + <name since="">snmp_get_next_index(Tab, RowIndex) -> {ok, NextIndex} | endOfTable</name> <fsummary>Gets the index of the next lexicographical row.</fsummary> <type> <v>Tab ::= atom()</v> @@ -2006,7 +2006,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>snmp_get_row(Tab, RowIndex) -> {ok, Row} | undefined</name> + <name since="">snmp_get_row(Tab, RowIndex) -> {ok, Row} | undefined</name> <fsummary>Retrieves a row indexed by an SNMP index.</fsummary> <type> <v>Tab ::= atom()</v> @@ -2019,7 +2019,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>snmp_open_table(Tab, SnmpStruct) -> {aborted, R} | {atomic, ok}</name> + <name since="">snmp_open_table(Tab, SnmpStruct) -> {aborted, R} | {atomic, ok}</name> <fsummary>Organizes a Mnesia table as an SNMP table.</fsummary> <type> <v>Tab ::= atom()</v> @@ -2073,10 +2073,17 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>start() -> ok | {error, Reason}</name> + <name since="">start() -> ok | {error, Reason}</name> <fsummary>Starts a local Mnesia system.</fsummary> <desc> <marker id="start"></marker> + <p>Mnesia startup is asynchronous. The function call + <c>mnesia:start()</c> returns the atom <c>ok</c> and then + starts to initialize the different tables. Depending on the + size of the database, this can take some time, and the + application programmer must wait for the tables that the + application needs before they can be used. This is achieved + by using the function <c>mnesia:wait_for_tables/2</c>.</p> <p>The startup procedure for a set of Mnesia nodes is a fairly complicated operation. A Mnesia system consists of a set of nodes, with Mnesia started locally on all @@ -2108,7 +2115,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>stop() -> stopped</name> + <name since="">stop() -> stopped</name> <fsummary>Stops Mnesia locally.</fsummary> <desc> <marker id="stop"></marker> @@ -2117,7 +2124,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>subscribe(EventCategory) -> {ok, Node} | {error, Reason}</name> + <name since="">subscribe(EventCategory) -> {ok, Node} | {error, Reason}</name> <fsummary>Subscribes to events of type <c>EventCategory</c>.</fsummary> <desc> <marker id="subscribe"></marker> @@ -2127,7 +2134,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>sync_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> + <name since="">sync_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> <fsummary>Calls the <c>Fun</c> in a context that is not protected by a transaction.</fsummary> <desc> <marker id="sync_dirty"></marker> @@ -2143,7 +2150,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>sync_log() -> ok | {error, Reason}</name> + <name since="OTP 17.0">sync_log() -> ok | {error, Reason}</name> <fsummary>Performs a file sync of the local log file.</fsummary> <desc> <p>Ensures that the local transaction log file is synced to disk. @@ -2153,7 +2160,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>sync_transaction(Fun, [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name> + <name since="">sync_transaction(Fun, [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name> <fsummary>Synchronously executes a transaction.</fsummary> <desc> <marker id="sync_transaction"></marker> @@ -2166,7 +2173,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>system_info(InfoKey) -> Info | exit({aborted, Reason})</name> + <name since="">system_info(InfoKey) -> Info | exit({aborted, Reason})</name> <fsummary>Returns information about the Mnesia system.</fsummary> <desc> <marker id="system_info"></marker> @@ -2353,7 +2360,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>table(Tab [,[Option]]) -> QueryHandle</name> + <name since="">table(Tab [,[Option]]) -> QueryHandle</name> <fsummary>Return a QLC query handle.</fsummary> <desc> <marker id="table"></marker> @@ -2408,7 +2415,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>table_info(Tab, InfoKey) -> Info | exit({aborted, Reason})</name> + <name since="">table_info(Tab, InfoKey) -> Info | exit({aborted, Reason})</name> <fsummary>Returns local information about table.</fsummary> <desc> <marker id="table_info"></marker> @@ -2560,7 +2567,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>transaction(Fun [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name> + <name since="">transaction(Fun [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name> <fsummary>Executes a transaction.</fsummary> <desc> <marker id="transaction"></marker> @@ -2628,7 +2635,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>transform_table(Tab, Fun, NewAttributeList, NewRecordName) -> {aborted, R} | {atomic, ok}</name> + <name since="">transform_table(Tab, Fun, NewAttributeList, NewRecordName) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes format on all records in table <c>Tab</c>.</fsummary> <desc> <marker id="transform_table_4"></marker> @@ -2649,7 +2656,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>transform_table(Tab, Fun, NewAttributeList) -> {aborted, R} | {atomic, ok}</name> + <name since="">transform_table(Tab, Fun, NewAttributeList) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes format on all records in table <c>Tab</c>.</fsummary> <desc> <p>Calls <c>mnesia:transform_table(Tab, Fun, @@ -2658,7 +2665,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>traverse_backup(Source, [SourceMod,] Target, [TargetMod,] Fun, Acc) -> {ok, LastAcc} | {error, Reason}</name> + <name since="">traverse_backup(Source, [SourceMod,] Target, [TargetMod,] Fun, Acc) -> {ok, LastAcc} | {error, Reason}</name> <fsummary>Traversal of a backup.</fsummary> <desc> <marker id="traverse_backup"></marker> @@ -2689,7 +2696,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>uninstall_fallback() -> ok | {error,Reason}</name> + <name since="">uninstall_fallback() -> ok | {error,Reason}</name> <fsummary>Uninstalls a fallback.</fsummary> <desc> <marker id="uninstall_fallback_0"></marker> @@ -2698,7 +2705,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>uninstall_fallback(Args) -> ok | {error,Reason}</name> + <name since="">uninstall_fallback(Args) -> ok | {error,Reason}</name> <fsummary>Uninstalls a fallback.</fsummary> <desc> <p>Deinstalls a fallback before it @@ -2725,7 +2732,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>unsubscribe(EventCategory) -> {ok, Node} | {error, Reason}</name> + <name since="">unsubscribe(EventCategory) -> {ok, Node} | {error, Reason}</name> <fsummary>Subscribes to events of type <c>EventCategory</c>.</fsummary> <desc> <marker id="unsubscribe"></marker> @@ -2735,7 +2742,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>wait_for_tables(TabList, Timeout) -> ok | {timeout, BadTabList} | {error, Reason}</name> + <name since="">wait_for_tables(TabList, Timeout) -> ok | {timeout, BadTabList} | {error, Reason}</name> <fsummary>Waits for tables to be accessible.</fsummary> <desc> <marker id="wait_for_tables"></marker> @@ -2746,7 +2753,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>wread({Tab, Key}) -> transaction abort | RecordList</name> + <name since="">wread({Tab, Key}) -> transaction abort | RecordList</name> <fsummary>Reads records with given key.</fsummary> <desc> <marker id="wread"></marker> @@ -2754,7 +2761,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>write(Record) -> transaction abort | ok</name> + <name since="">write(Record) -> transaction abort | ok</name> <fsummary>Writes a record into the database.</fsummary> <desc> <marker id="write_1"></marker> @@ -2763,7 +2770,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>write(Tab, Record, LockKind) -> transaction abort | ok</name> + <name since="">write(Tab, Record, LockKind) -> transaction abort | ok</name> <fsummary>Writes a record into the database.</fsummary> <desc> <marker id="write_3"></marker> @@ -2779,7 +2786,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>write_lock_table(Tab) -> ok | transaction abort</name> + <name since="">write_lock_table(Tab) -> ok | transaction abort</name> <fsummary>Sets write lock on an entire table.</fsummary> <desc> <marker id="write_lock_table"></marker> diff --git a/lib/mnesia/doc/src/mnesia_frag_hash.xml b/lib/mnesia/doc/src/mnesia_frag_hash.xml index c233acdb05..ccaba412d0 100644 --- a/lib/mnesia/doc/src/mnesia_frag_hash.xml +++ b/lib/mnesia/doc/src/mnesia_frag_hash.xml @@ -34,7 +34,7 @@ <rev>A</rev> <file>mnesia_frag_hash.sgml</file> </header> - <module>mnesia_frag_hash</module> + <module since="">mnesia_frag_hash</module> <modulesummary>Defines mnesia_frag_hash callback behavior</modulesummary> <description> <p>This module defines a callback behavior for user-defined hash @@ -50,7 +50,7 @@ <funcs> <func> - <name>init_state(Tab, State) -> NewState | abort(Reason)</name> + <name since="">init_state(Tab, State) -> NewState | abort(Reason)</name> <fsummary>Initiates the hash state for a new table.</fsummary> <type> <v>Tab = atom()</v> @@ -72,7 +72,7 @@ </desc> </func> <func> - <name>add_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name> + <name since="">add_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name> <fsummary>Starts when a new fragment is added to a fragmented table.</fsummary> <type> <v>State = term()</v> @@ -100,7 +100,7 @@ </desc> </func> <func> - <name>del_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name> + <name since="">del_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name> <fsummary>Starts when a fragment is deleted from a fragmented table.</fsummary> <type> <v>State = term()</v> @@ -127,7 +127,7 @@ </desc> </func> <func> - <name>key_to_frag_number(State, Key) -> FragNum | abort(Reason)</name> + <name since="">key_to_frag_number(State, Key) -> FragNum | abort(Reason)</name> <fsummary>Resolves the key of a record into a fragment number.</fsummary> <type> <v>FragNum = integer()</v> @@ -140,7 +140,7 @@ </desc> </func> <func> - <name>match_spec_to_frag_numbers(State, MatchSpec) -> FragNums | abort(Reason)</name> + <name since="">match_spec_to_frag_numbers(State, MatchSpec) -> FragNums | abort(Reason)</name> <fsummary>Resolves a <c>MatchSpec</c> into a list of fragment numbers.</fsummary> <type> <v>MatcSpec = ets_select_match_spec()</v> diff --git a/lib/mnesia/doc/src/mnesia_registry.xml b/lib/mnesia/doc/src/mnesia_registry.xml index a76f716981..18ddc4ab9e 100644 --- a/lib/mnesia/doc/src/mnesia_registry.xml +++ b/lib/mnesia/doc/src/mnesia_registry.xml @@ -34,7 +34,7 @@ <rev>A</rev> <file>mnesia_registry.sgml</file> </header> - <module>mnesia_registry</module> + <module since="">mnesia_registry</module> <modulesummary>Dump support for registries in erl_interface.</modulesummary> <description> <p>This module is usually part of the <c>erl_interface</c> @@ -57,7 +57,7 @@ <funcs> <func> - <name>create_table(Tab) -> ok | exit(Reason)</name> + <name since="">create_table(Tab) -> ok | exit(Reason)</name> <fsummary>Creates a registry table in Mnesia.</fsummary> <desc> <p>A wrapper function for <c>mnesia:create_table/2</c>, @@ -73,7 +73,7 @@ </desc> </func> <func> - <name>create_table(Tab, TabDef) -> ok | exit(Reason)</name> + <name since="">create_table(Tab, TabDef) -> ok | exit(Reason)</name> <fsummary>Creates a customized registry table in Mnesia.</fsummary> <desc> <p>A wrapper function for <c>mnesia:create_table/2</c>, diff --git a/lib/observer/doc/src/crashdump.xml b/lib/observer/doc/src/crashdump.xml index 48f944cbce..62c6ff1f25 100644 --- a/lib/observer/doc/src/crashdump.xml +++ b/lib/observer/doc/src/crashdump.xml @@ -34,7 +34,7 @@ <rev>PA1</rev> <file>crashdump.xml</file> </header> - <module>crashdump_viewer</module> + <module since="">crashdump_viewer</module> <modulesummary>A WxWidgets based tool for browsing Erlang crashdumps.</modulesummary> <description> @@ -46,8 +46,8 @@ </description> <funcs> <func> - <name>start() -> ok</name> - <name>start(File) -> ok</name> + <name since="">start() -> ok</name> + <name since="OTP 17.0">start(File) -> ok</name> <fsummary>Start the Crashdump Viewer.</fsummary> <type> <v>File = string()</v> @@ -62,7 +62,7 @@ </desc> </func> <func> - <name>stop() -> ok</name> + <name since="">stop() -> ok</name> <fsummary>Terminate the Crashdump Viewer.</fsummary> <desc> <p>Terminates the Crashdump Viewer and closes diff --git a/lib/observer/doc/src/etop.xml b/lib/observer/doc/src/etop.xml index e7a83d0514..f0acc7b5d8 100644 --- a/lib/observer/doc/src/etop.xml +++ b/lib/observer/doc/src/etop.xml @@ -34,7 +34,7 @@ <rev></rev> <file></file> </header> - <module>etop</module> + <module since="">etop</module> <modulesummary>Erlang Top is a tool for presenting information about Erlang processes similar to the information presented by "top" in UNIX.</modulesummary> <description> @@ -98,7 +98,7 @@ </description> <funcs> <func> - <name>start() -> ok</name> + <name since="OTP R15B01">start() -> ok</name> <fsummary>Start etop.</fsummary> <desc> <p>Starts <c>etop</c>. @@ -106,7 +106,7 @@ </desc> </func> <func> - <name>start(Options) -> ok</name> + <name since="OTP R15B01">start(Options) -> ok</name> <fsummary>Start etop.</fsummary> <type> <v>Options = [Option]</v> @@ -120,7 +120,7 @@ </desc> </func> <func> - <name>help() -> ok</name> + <name since="OTP R15B01">help() -> ok</name> <fsummary>Display the etop help.</fsummary> <desc> <p>Displays the help of <c>etop</c> and @@ -128,7 +128,7 @@ </desc> </func> <func> - <name>config(Key,Value) -> Result</name> + <name since="">config(Key,Value) -> Result</name> <fsummary>Change the configuration of the tool.</fsummary> <type> <v>Result = ok | {error,Reason}</v> @@ -142,7 +142,7 @@ </desc> </func> <func> - <name>dump(File) -> Result</name> + <name since="">dump(File) -> Result</name> <fsummary>Dump the current display to a file.</fsummary> <type> <v>Result = ok | {error,Reason}</v> @@ -153,7 +153,7 @@ </desc> </func> <func> - <name>stop() -> stop</name> + <name since="">stop() -> stop</name> <fsummary>Terminate etop.</fsummary> <desc> <p>Terminates <c>etop</c>.</p> diff --git a/lib/observer/doc/src/observer.xml b/lib/observer/doc/src/observer.xml index 843be26ee1..7fb1dd044e 100644 --- a/lib/observer/doc/src/observer.xml +++ b/lib/observer/doc/src/observer.xml @@ -33,7 +33,7 @@ <rev>PA1</rev> <file>observer.xml</file> </header> - <module>observer</module> + <module since="OTP R15B">observer</module> <modulesummary>A GUI tool for observing an Erlang system.</modulesummary> <description> <p>Observer is a graphical tool for observing the characteristics of @@ -48,7 +48,7 @@ </description> <funcs> <func> - <name>start() -> ok</name> + <name since="OTP R15B">start() -> ok</name> <fsummary>Start the Observer GUI.</fsummary> <desc> <p>Starts the Observer GUI. diff --git a/lib/observer/doc/src/ttb.xml b/lib/observer/doc/src/ttb.xml index 7cd15e15d3..fee95e0b21 100644 --- a/lib/observer/doc/src/ttb.xml +++ b/lib/observer/doc/src/ttb.xml @@ -33,7 +33,7 @@ <rev>PA1</rev> <file>ttb.xml</file> </header> - <module>ttb</module> + <module since="">ttb</module> <modulesummary>A base for building trace tools for distributed systems.</modulesummary> <description> <p>The Trace Tool Builder, <c>ttb</c>, is a base for building trace @@ -44,7 +44,7 @@ </description> <funcs> <func> - <name>start_trace(Nodes, Patterns, FlagSpec, Opts) -> Result</name> + <name since="OTP R15B">start_trace(Nodes, Patterns, FlagSpec, Opts) -> Result</name> <fsummary>Start a trace port on each specified node.</fsummary> <type> <v>Result = see p/2</v> @@ -76,7 +76,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>tracer() -> Result</name> + <name since="">tracer() -> Result</name> <fsummary>Equivalent to tracer(node()).</fsummary> <desc> <p>Equivalent to <c>tracer(node())</c>.</p> @@ -84,7 +84,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>tracer(Shortcut) -> Result</name> + <name since="">tracer(Shortcut) -> Result</name> <fsummary>Handy shortcuts for common tracing settings.</fsummary> <type> <v>Shortcut = shell | dbg</v> @@ -97,7 +97,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>tracer(Nodes) -> Result</name> + <name since="">tracer(Nodes) -> Result</name> <fsummary>Equivalent to tracer(Nodes,[]).</fsummary> <desc> <p>Equivalent to <c>tracer(Nodes,[])</c>.</p> @@ -105,7 +105,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>tracer(Nodes,Opts) -> Result</name> + <name since="">tracer(Nodes,Opts) -> Result</name> <fsummary>Start a trace port on each specified node.</fsummary> <type> <v>Result = {ok, ActivatedNodes} | {error,Reason}</v> @@ -243,7 +243,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>p(Item,Flags) -> Return</name> + <name since="">p(Item,Flags) -> Return</name> <fsummary>Set the specified trace flags on the specified processes or ports.</fsummary> <type> <v>Return = {ok,[{Item,MatchDesc}]}</v> @@ -277,7 +277,8 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>tp, tpl, tpe, ctp, ctpl, ctpg, ctpe</name> + <name since="">tp, tpl, ctp, ctpl, ctpg</name> + <name since="OTP 19.0">tpe, ctpe</name> <fsummary>Set and clear trace patterns.</fsummary> <desc> <p>These functions are to be used with trace @@ -338,7 +339,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>list_history() -> History</name> + <name since="">list_history() -> History</name> <fsummary>Return all calls stored in history.</fsummary> <type> <v>History = [{N,Func,Args}]</v> @@ -352,7 +353,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>run_history(N) -> ok | {error, Reason}</name> + <name since="">run_history(N) -> ok | {error, Reason}</name> <fsummary>Execute one entry of the history.</fsummary> <type> <v>N = integer() | [integer()]</v> @@ -364,7 +365,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>write_config(ConfigFile,Config)</name> + <name since="">write_config(ConfigFile,Config)</name> <fsummary>Equivalent to write_config(ConfigFile,Config,[]).</fsummary> <desc> <p>Equivalent to <c>write_config(ConfigFile,Config,[])</c>.</p> @@ -372,7 +373,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>write_config(ConfigFile,Config,Opts) -> ok | {error,Reason}</name> + <name since="">write_config(ConfigFile,Config,Opts) -> ok | {error,Reason}</name> <fsummary>Create a configuration file.</fsummary> <type> <v>ConfigFile = string()</v> @@ -405,7 +406,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>run_config(ConfigFile) -> ok | {error,Reason}</name> + <name since="">run_config(ConfigFile) -> ok | {error,Reason}</name> <fsummary>Execute all entries in a configuration file.</fsummary> <type> <v>ConfigFile = string()</v> @@ -418,7 +419,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>run_config(ConfigFile,NumList) -> ok | {error,Reason}</name> + <name since="">run_config(ConfigFile,NumList) -> ok | {error,Reason}</name> <fsummary>Execute selected entries from a configuration file.</fsummary> <type> <v>ConfigFile = string()</v> @@ -437,7 +438,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>list_config(ConfigFile) -> Config | {error,Reason}</name> + <name since="">list_config(ConfigFile) -> Config | {error,Reason}</name> <fsummary>List all entries in a configuration file.</fsummary> <type> <v>ConfigFile = string()</v> @@ -449,7 +450,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>write_trace_info(Key,Info) -> ok</name> + <name since="">write_trace_info(Key,Info) -> ok</name> <fsummary>Write any information to file <c>.ti</c>.</fsummary> <type> <v>Key = term()</v> @@ -465,7 +466,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>seq_trigger_ms() -> MatchSpec</name> + <name since="">seq_trigger_ms() -> MatchSpec</name> <fsummary>Equivalent to seq_trigger_ms(all).</fsummary> <desc> <p>Equivalent to <c>seq_trigger_ms(all)</c>.</p> @@ -473,7 +474,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>seq_trigger_ms(Flags) -> MatchSpec</name> + <name since="">seq_trigger_ms(Flags) -> MatchSpec</name> <fsummary>Return a match_spec() which starts sequential tracing.</fsummary> <type> <v>MatchSpec = match_spec()</v> @@ -521,7 +522,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>stop()</name> + <name since="">stop()</name> <fsummary>Equivalent to stop([]).</fsummary> <desc> <p>Equivalent to <c>stop([])</c>.</p> @@ -529,7 +530,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>stop(Opts) -> stopped | {stopped, Dir}</name> + <name since="">stop(Opts) -> stopped | {stopped, Dir}</name> <fsummary>Stop tracing and fetch/format logs from all nodes.</fsummary> <type> <v>Opts = Opt | [Opt]</v> @@ -573,7 +574,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>get_et_handler()</name> + <name since="OTP R15B">get_et_handler()</name> <fsummary>Return the <c>et</c> handler.</fsummary> <desc> <p>Returns the <c>et</c> handler, which can be used with <c>format/2</c> @@ -583,7 +584,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>format(File)</name> + <name since="">format(File)</name> <fsummary>Equivalent to <c>format(File,[])</c>.</fsummary> <desc> <p>Equivalent to <c>format(File,[])</c>.</p> @@ -591,7 +592,7 @@ ttb:p(all, call).</input></pre> </func> <func> - <name>format(File,Options) -> ok | {error, Reason}</name> + <name since="">format(File,Options) -> ok | {error, Reason}</name> <fsummary>Format a binary trace log.</fsummary> <type> <v>File = string() | [string()]</v> diff --git a/lib/observer/src/cdv_detail_wx.erl b/lib/observer/src/cdv_detail_wx.erl index 4b1984c394..5e1137511a 100644 --- a/lib/observer/src/cdv_detail_wx.erl +++ b/lib/observer/src/cdv_detail_wx.erl @@ -84,8 +84,9 @@ destroy_progress(_) -> ok. init(Id,ParentFrame,Callback,App,Parent,{Title,Info,TW}) -> + Scale = observer_wx:get_scale(), Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [Title], - [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {850,600}}]), + [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {Scale*850,Scale*600}}]), MenuBar = wxMenuBar:new(), create_menus(MenuBar), wxFrame:setMenuBar(Frame, MenuBar), diff --git a/lib/observer/src/cdv_html_wx.erl b/lib/observer/src/cdv_html_wx.erl index ffef83227c..8956173c93 100644 --- a/lib/observer/src/cdv_html_wx.erl +++ b/lib/observer/src/cdv_html_wx.erl @@ -79,14 +79,14 @@ handle_info(active, #state{panel=HtmlWin,delayed_fetch=Callback}=State) observer_lib:sync_destroy_progress_dialog(), wx_misc:beginBusyCursor(), wxHtmlWindow:setPage(HtmlWin,HtmlText), - cdv_wx:set_status(TW), + cdv_wx_set_status(State, TW), wx_misc:endBusyCursor(), {noreply, State#state{expand_table=Tab, delayed_fetch=undefined, trunc_warn=TW}}; handle_info(active, State) -> - cdv_wx:set_status(State#state.trunc_warn), + cdv_wx_set_status(State, State#state.trunc_warn), {noreply, State}; handle_info(Info, State) -> @@ -164,3 +164,10 @@ expand(Id,Callback,#state{expand_wins=Opened0, app=App}=State) -> Opened0 end, State#state{expand_wins=Opened}. + +cdv_wx_set_status(#state{app = cdv}, Status) -> + %% this module is used by the observer when cdw_wx isn't started + %% only try to set status when used by cdv + cdv_wx:set_status(Status); +cdv_wx_set_status(_, _) -> + ok. diff --git a/lib/observer/src/cdv_table_wx.erl b/lib/observer/src/cdv_table_wx.erl index 0f28a51017..0cad272262 100644 --- a/lib/observer/src/cdv_table_wx.erl +++ b/lib/observer/src/cdv_table_wx.erl @@ -50,11 +50,12 @@ init([ParentWin, {ColumnSpec,Info,TW}]) -> end, Grid = wxListCtrl:new(ParentWin, [{style, Style}]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), AddListEntry = fun({Name, Align, DefSize}, Col) -> wxListItem:setText(Li, Name), wxListItem:setAlign(Li, Align), wxListCtrl:insertColumn(Grid, Col, Li), - wxListCtrl:setColumnWidth(Grid, Col, DefSize), + wxListCtrl:setColumnWidth(Grid, Col, DefSize*Scale), Col + 1 end, lists:foldl(AddListEntry, 0, ColumnSpec), diff --git a/lib/observer/src/cdv_virtual_list_wx.erl b/lib/observer/src/cdv_virtual_list_wx.erl index 2702301021..14877b7eab 100644 --- a/lib/observer/src/cdv_virtual_list_wx.erl +++ b/lib/observer/src/cdv_virtual_list_wx.erl @@ -132,11 +132,12 @@ create_list_box(Panel, Holder, Callback, Owner) -> end} ]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), AddListEntry = fun({Name, Align, DefSize}, Col) -> wxListItem:setText(Li, Name), wxListItem:setAlign(Li, Align), wxListCtrl:insertColumn(ListCtrl, Col, Li), - wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize), + wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize*Scale), Col + 1 end, ListItems = Callback:col_spec(), diff --git a/lib/observer/src/cdv_wx.erl b/lib/observer/src/cdv_wx.erl index 1e9cef8952..811c767e66 100644 --- a/lib/observer/src/cdv_wx.erl +++ b/lib/observer/src/cdv_wx.erl @@ -101,8 +101,9 @@ init(File0) -> {ok,CdvServer} = crashdump_viewer:start_link(), catch wxSystemOptions:setOption("mac.listctrl.always_use_generic", 1), + Scale = observer_wx:get_scale(), Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Crashdump Viewer", - [{size, {850, 600}}, {style, ?wxDEFAULT_FRAME_STYLE}]), + [{size, {Scale*850, Scale*600}}, {style, ?wxDEFAULT_FRAME_STYLE}]), IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"), Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), wxFrame:setIcon(Frame, Icon), diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl index 54e246f247..da47a30fb1 100644 --- a/lib/observer/src/observer_alloc_wx.erl +++ b/lib/observer/src/observer_alloc_wx.erl @@ -282,11 +282,12 @@ create_mem_info(Parent) -> Grid = wxListCtrl:new(Parent, [{style, Style}]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), AddListEntry = fun({Name, Align, DefSize}, Col) -> wxListItem:setText(Li, Name), wxListItem:setAlign(Li, Align), wxListCtrl:insertColumn(Grid, Col, Li), - wxListCtrl:setColumnWidth(Grid, Col, DefSize), + wxListCtrl:setColumnWidth(Grid, Col, DefSize*Scale), Col + 1 end, ListItems = [{"Allocator Type", ?wxLIST_FORMAT_LEFT, 200}, diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl index 2a481966da..8c3eef5411 100644 --- a/lib/observer/src/observer_app_wx.erl +++ b/lib/observer/src/observer_app_wx.erl @@ -117,16 +117,19 @@ init([Notebook, Parent, _Config]) -> UseGC = haveGC(), Version28 = ?wxMAJOR_VERSION =:= 2 andalso ?wxMINOR_VERSION =:= 8, + Scale = observer_wx:get_scale(), Font = case os:type() of {unix,_} when UseGC, Version28 -> - wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL); + wxFont:new(Scale * 12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL); _ -> - wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT) + Font0 = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), + wxFont:setPointSize(Font0, Scale * wxFont:getPointSize(Font0)), + Font0 end, SelCol = wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT), GreyBrush = wxBrush:new({230,230,240}), SelBrush = wxBrush:new(SelCol), - LinkPen = wxPen:new(SelCol, [{width, 2}]), + LinkPen = wxPen:new(SelCol, [{width, Scale * 2}]), process_flag(trap_exit, true), {Panel, #state{parent=Parent, panel =Panel, @@ -134,7 +137,7 @@ init([Notebook, Parent, _Config]) -> app_w =DrawingArea, usegc = UseGC, paint=#paint{font = Font, - pen = wxPen:new({80,80,80}, [{width, 2}]), + pen = wxPen:new({80,80,80}, [{width, Scale * 2}]), brush= GreyBrush, sel = SelBrush, links= LinkPen diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl index 21c6d26f49..79271addf2 100644 --- a/lib/observer/src/observer_perf_wx.erl +++ b/lib/observer/src/observer_perf_wx.erl @@ -110,25 +110,26 @@ setup_graph_drawing(Panels) -> _ = [Do(Panel) || Panel <- Panels], UseGC = haveGC(), Version28 = ?wxMAJOR_VERSION =:= 2 andalso ?wxMINOR_VERSION =:= 8, + Scale = observer_wx:get_scale(), {Font, SmallFont} = if UseGC, Version28 -> %% Def font is really small when using Graphics contexts in 2.8 %% Hardcode it - F = wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD), - SF = wxFont:new(10, ?wxFONTFAMILY_DECORATIVE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), + F = wxFont:new(Scale * 12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD), + SF = wxFont:new(Scale * 10, ?wxFONTFAMILY_DECORATIVE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), {F, SF}; true -> DefFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), DefSize = wxFont:getPointSize(DefFont), DefFamily = wxFont:getFamily(DefFont), - F = wxFont:new(DefSize-1, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD), - SF = wxFont:new(DefSize-2, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), + F = wxFont:new(Scale * (DefSize-1), DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD), + SF = wxFont:new(Scale * (DefSize-2), DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), {F, SF} end, - BlackPen = wxPen:new({0,0,0}, [{width, 1}]), - Pens = [wxPen:new(Col, [{width, 1}, {style, ?wxSOLID}]) + BlackPen = wxPen:new({0,0,0}, [{width, Scale}]), + Pens = [wxPen:new(Col, [{width, Scale}, {style, ?wxSOLID}]) || Col <- tuple_to_list(colors())], - DotPens = [wxPen:new(Col, [{width, 1}, {style, ?wxDOT}]) + DotPens = [wxPen:new(Col, [{width, Scale}, {style, ?wxDOT}]) || Col <- tuple_to_list(colors())], #paint{usegc = UseGC, font = Font, diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl index 445f3dd6b1..00cf1b5fba 100644 --- a/lib/observer/src/observer_port_wx.erl +++ b/lib/observer/src/observer_port_wx.erl @@ -96,11 +96,12 @@ init([Notebook, Parent, Config]) -> wxListCtrl:setColumnWidth(Grid, Col, DefSize), Col + 1 end, - ListItems = [{"Id", ?wxLIST_FORMAT_LEFT, 150}, - {"Connected", ?wxLIST_FORMAT_LEFT, 150}, - {"Name", ?wxLIST_FORMAT_LEFT, 150}, - {"Controls", ?wxLIST_FORMAT_LEFT, 200}, - {"Slot", ?wxLIST_FORMAT_RIGHT, 50}], + Scale = observer_wx:get_scale(), + ListItems = [{"Id", ?wxLIST_FORMAT_LEFT, Scale*150}, + {"Connected", ?wxLIST_FORMAT_LEFT, Scale*150}, + {"Name", ?wxLIST_FORMAT_LEFT, Scale*150}, + {"Controls", ?wxLIST_FORMAT_LEFT, Scale*200}, + {"Slot", ?wxLIST_FORMAT_RIGHT, Scale*50}], lists:foldl(AddListEntry, 0, ListItems), wxListItem:destroy(Li), @@ -461,10 +462,11 @@ display_port_info(Parent, PortRec, Opened) -> do_display_port_info(Parent0, PortRec) -> Parent = observer_lib:get_wx_parent(Parent0), Title = "Port Info: " ++ PortRec#port.id_str, + Scale = observer_wx:get_scale(), Frame = wxMiniFrame:new(Parent, ?wxID_ANY, Title, [{style, ?wxSYSTEM_MENU bor ?wxCAPTION bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER}, - {size,{600,400}}]), + {size,{Scale * 600, Scale * 400}}]), ScrolledWin = wxScrolledWindow:new(Frame,[{style,?wxHSCROLL bor ?wxVSCROLL}]), wxScrolledWindow:enableScrolling(ScrolledWin,true,true), wxScrolledWindow:setScrollbars(ScrolledWin,20,20,0,0), diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl index 04e654a37e..4ab4a78462 100644 --- a/lib/observer/src/observer_pro_wx.erl +++ b/lib/observer/src/observer_pro_wx.erl @@ -163,13 +163,14 @@ create_list_box(Panel, Holder) -> wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize), Col + 1 end, - ListItems = [{"Pid", ?wxLIST_FORMAT_CENTRE, 120}, - {"Name or Initial Func", ?wxLIST_FORMAT_LEFT, 200}, -%% {"Time", ?wxLIST_FORMAT_CENTRE, 50}, - {"Reds", ?wxLIST_FORMAT_RIGHT, 100}, - {"Memory", ?wxLIST_FORMAT_RIGHT, 100}, - {"MsgQ", ?wxLIST_FORMAT_RIGHT, 50}, - {"Current Function", ?wxLIST_FORMAT_LEFT, 200}], + Scale = observer_wx:get_scale(), + ListItems = [{"Pid", ?wxLIST_FORMAT_CENTRE, Scale*120}, + {"Name or Initial Func", ?wxLIST_FORMAT_LEFT, Scale*200}, +%% {"Time", ?wxLIST_FORMAT_CENTRE, Scale*50}, + {"Reds", ?wxLIST_FORMAT_RIGHT, Scale*100}, + {"Memory", ?wxLIST_FORMAT_RIGHT, Scale*100}, + {"MsgQ", ?wxLIST_FORMAT_RIGHT, Scale*50}, + {"Current Function", ?wxLIST_FORMAT_LEFT, Scale*200}], lists:foldl(AddListEntry, 0, ListItems), wxListItem:destroy(Li), diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index f436886735..bd5fed0951 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -59,8 +59,9 @@ init([Pid, ParentFrame, Parent]) -> {registered_name, Registered} -> io_lib:format("~tp (~p)",[Registered, Pid]); undefined -> throw(process_undefined) end, + Scale = observer_wx:get_scale(), Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [atom_to_list(node(Pid)), $:, Title], - [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {850,600}}]), + [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {Scale * 850, Scale * 600}}]), MenuBar = wxMenuBar:new(), create_menus(MenuBar), wxFrame:setMenuBar(Frame, MenuBar), @@ -245,12 +246,13 @@ init_dict_page(Parent, Pid, Table) -> init_stack_page(Parent, Pid) -> LCtrl = wxListCtrl:new(Parent, [{style, ?wxLC_REPORT bor ?wxLC_HRULES}]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), wxListItem:setText(Li, "Module:Function/Arg"), wxListCtrl:insertColumn(LCtrl, 0, Li), - wxListCtrl:setColumnWidth(LCtrl, 0, 300), + wxListCtrl:setColumnWidth(LCtrl, 0, Scale * 300), wxListItem:setText(Li, "File:LineNumber"), wxListCtrl:insertColumn(LCtrl, 1, Li), - wxListCtrl:setColumnWidth(LCtrl, 1, 300), + wxListCtrl:setColumnWidth(LCtrl, 1, Scale * 300), wxListItem:destroy(Li), Update = fun() -> case observer_wx:try_rpc(node(Pid), erlang, process_info, diff --git a/lib/observer/src/observer_trace_wx.erl b/lib/observer/src/observer_trace_wx.erl index 2c3b46a3a1..f458c8c34a 100644 --- a/lib/observer/src/observer_trace_wx.erl +++ b/lib/observer/src/observer_trace_wx.erl @@ -188,8 +188,9 @@ create_proc_port_view(Parent) -> wxListCtrl:setColumnWidth(Procs, Col, DefSize), Col + 1 end, - ProcListItems = [{"Process Id", ?wxLIST_FORMAT_CENTER, 120}, - {"Trace Options", ?wxLIST_FORMAT_LEFT, 300}], + Scale = observer_wx:get_scale(), + ProcListItems = [{"Process Id", ?wxLIST_FORMAT_CENTER, Scale*120}, + {"Trace Options", ?wxLIST_FORMAT_LEFT, Scale*300}], lists:foldl(AddProc, 0, ProcListItems), AddPort = fun({Name, Align, DefSize}, Col) -> @@ -199,8 +200,8 @@ create_proc_port_view(Parent) -> wxListCtrl:setColumnWidth(Ports, Col, DefSize), Col + 1 end, - PortListItems = [{"Port Id", ?wxLIST_FORMAT_CENTER, 120}, - {"Trace Options", ?wxLIST_FORMAT_LEFT, 300}], + PortListItems = [{"Port Id", ?wxLIST_FORMAT_CENTER, Scale*120}, + {"Trace Options", ?wxLIST_FORMAT_LEFT, Scale*300}], lists:foldl(AddPort, 0, PortListItems), wxListItem:destroy(Li), @@ -242,14 +243,15 @@ create_matchspec_view(Parent) -> Funcs = wxListCtrl:new(Splitter, [{winid, ?FUNCS_WIN}, {style, Style}]), Li = wxListItem:new(), + Scale = observer_wx:get_scale(), wxListItem:setText(Li, "Modules"), wxListCtrl:insertColumn(Modules, 0, Li), wxListItem:setText(Li, "Functions"), wxListCtrl:insertColumn(Funcs, 0, Li), - wxListCtrl:setColumnWidth(Funcs, 0, 150), + wxListCtrl:setColumnWidth(Funcs, 0, Scale*150), wxListItem:setText(Li, "Match Spec"), wxListCtrl:insertColumn(Funcs, 1, Li), - wxListCtrl:setColumnWidth(Funcs, 1, 300), + wxListCtrl:setColumnWidth(Funcs, 1, Scale*300), wxListItem:destroy(Li), wxSplitterWindow:setSashGravity(Splitter, 0.0), @@ -969,7 +971,8 @@ output_file(true, true, Opts) -> create_logwindow(_Parent, false) -> {false, false}; create_logwindow(Parent, true) -> - LogWin = wxFrame:new(Parent, ?LOG_WIN, "Trace Log", [{size, {750, 800}}]), + Scale = observer_wx:get_scale(), + LogWin = wxFrame:new(Parent, ?LOG_WIN, "Trace Log", [{size, {750*Scale, 800*Scale}}]), MB = wxMenuBar:new(), File = wxMenu:new(), wxMenu:append(File, ?LOG_CLEAR, "Clear Log\tCtrl-C"), diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl index ea292b92af..514d55ff24 100644 --- a/lib/observer/src/observer_traceoptions_wx.erl +++ b/lib/observer/src/observer_traceoptions_wx.erl @@ -167,9 +167,10 @@ select_nodes(Parent, Nodes) -> check_selector(Parent, Choices). module_selector(Parent, Node) -> + Scale = observer_wx:get_scale(), Dialog = wxDialog:new(Parent, ?wxID_ANY, "Select Module or Event", [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, - {size, {400, 400}}]), + {size, {400*Scale, 400*Scale}}]), Panel = wxPanel:new(Dialog), PanelSz = wxBoxSizer:new(?wxVERTICAL), MainSz = wxBoxSizer:new(?wxVERTICAL), @@ -237,9 +238,10 @@ function_selector(Parent, Node, Module) -> end. check_selector(Parent, ParsedChoices) -> + Scale = observer_wx:get_scale(), Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Functions", [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, - {size, {400, 400}}]), + {size, {400*Scale, 400*Scale}}]), Panel = wxPanel:new(Dialog), PanelSz = wxBoxSizer:new(?wxVERTICAL), @@ -331,9 +333,10 @@ select_matchspec(Pid, Parent, AllMatchSpecs, Key) -> {value,{Key,MSs0},Rest} -> {MSs0,Rest}; false -> {[],AllMatchSpecs} end, + Scale = observer_wx:get_scale(), Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Match Specifications", [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, - {size, {400, 400}}]), + {size, {400*Scale, 400*Scale}}]), Panel = wxPanel:new(Dialog), PanelSz = wxBoxSizer:new(?wxVERTICAL), diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl index d6dcee2cda..7bd67a0f0b 100644 --- a/lib/observer/src/observer_tv_table.erl +++ b/lib/observer/src/observer_tv_table.erl @@ -99,7 +99,8 @@ init([Parent, Opts]) -> ets -> "TV Ets: " ++ Title0; mnesia -> "TV Mnesia: " ++ Title0 end, - Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {800, 600}}]), + Scale = observer_wx:get_scale(), + Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {Scale * 800, Scale * 600}}]), IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"), Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), wxFrame:setIcon(Frame, Icon), diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl index 814f3a1260..247b3e869f 100644 --- a/lib/observer/src/observer_tv_wx.erl +++ b/lib/observer/src/observer_tv_wx.erl @@ -87,12 +87,13 @@ init([Notebook, Parent, Config]) -> wxListCtrl:setColumnWidth(Grid, Col, DefSize), Col + 1 end, - ListItems = [{"Table Name", ?wxLIST_FORMAT_LEFT, 200}, - {"Objects", ?wxLIST_FORMAT_RIGHT, 100}, - {"Size (kB)", ?wxLIST_FORMAT_RIGHT, 100}, - {"Owner Pid", ?wxLIST_FORMAT_CENTER, 150}, - {"Owner Name", ?wxLIST_FORMAT_LEFT, 200}, - {"Table Id", ?wxLIST_FORMAT_LEFT, 250} + Scale = observer_wx:get_scale(), + ListItems = [{"Table Name", ?wxLIST_FORMAT_LEFT, Scale*200}, + {"Objects", ?wxLIST_FORMAT_RIGHT, Scale*100}, + {"Size (kB)", ?wxLIST_FORMAT_RIGHT, Scale*100}, + {"Owner Pid", ?wxLIST_FORMAT_CENTER, Scale*150}, + {"Owner Name", ?wxLIST_FORMAT_LEFT, Scale*200}, + {"Table Id", ?wxLIST_FORMAT_LEFT, Scale*250} ], lists:foldl(AddListEntry, 0, ListItems), wxListItem:destroy(Li), diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl index 453e3bdc2d..71db586845 100644 --- a/lib/observer/src/observer_wx.erl +++ b/lib/observer/src/observer_wx.erl @@ -22,7 +22,7 @@ -export([start/0, stop/0]). -export([create_menus/2, get_attrib/1, get_tracer/0, get_active_node/0, get_menubar/0, - set_status/1, create_txt_dialog/4, try_rpc/4, return_to_localnode/2]). + get_scale/0, set_status/1, create_txt_dialog/4, try_rpc/4, return_to_localnode/2]). -export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3, handle_call/3, handle_info/2, check_page_title/1]). @@ -91,14 +91,24 @@ get_active_node() -> get_menubar() -> wx_object:call(observer, get_menubar). +get_scale() -> + ScaleStr = os:getenv("OBSERVER_SCALE", "1"), + try list_to_integer(ScaleStr) of + Scale when Scale < 1 -> 1; + Scale -> Scale + catch _:_ -> + 1 + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init(_Args) -> register(observer, self()), wx:new(), catch wxSystemOptions:setOption("mac.listctrl.always_use_generic", 1), + Scale = get_scale(), Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Observer", - [{size, {850, 600}}, {style, ?wxDEFAULT_FRAME_STYLE}]), + [{size, {Scale * 850, Scale * 600}}, {style, ?wxDEFAULT_FRAME_STYLE}]), IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"), Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), wxFrame:setIcon(Frame, Icon), @@ -771,7 +781,11 @@ ensure_sasl_started(Node) -> ensure_mf_h_handler_used(Node) -> %% is log_mf_h used ? - Handlers = rpc:block_call(Node, gen_event, which_handlers, [error_logger]), + Handlers = + case rpc:block_call(Node, gen_event, which_handlers, [error_logger]) of + {badrpc,{'EXIT',noproc}} -> []; % OTP-21+ and no event handler exists + Hs -> Hs + end, case lists:any(fun(L)-> L == log_mf_h end, Handlers) of false -> throw("Error: log_mf_h handler not used in sasl."), error; diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl index d5d3649525..d6b5eff9b5 100644 --- a/lib/observer/test/crashdump_helper.erl +++ b/lib/observer/test/crashdump_helper.erl @@ -204,5 +204,4 @@ dump_persistent_terms() -> create_persistent_terms() -> persistent_term:put({?MODULE,first}, {pid,42.0}), persistent_term:put({?MODULE,second}, [1,2,3]), - persistent_term:get(). - + {persistent_term:get({?MODULE,first}),persistent_term:get({?MODULE,second})}. diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl index 8c5e618f4a..31cf7011d4 100644 --- a/lib/observer/test/crashdump_viewer_SUITE.erl +++ b/lib/observer/test/crashdump_viewer_SUITE.erl @@ -615,9 +615,8 @@ special(File,Procs) -> #proc{dict=Dict} = ProcDetails, %% io:format("~p\n", [Dict]), - Pts1 = crashdump_helper:create_persistent_terms(), - Pts2 = proplists:get_value(pts,Dict), - true = lists:sort(Pts1) =:= lists:sort(Pts2), + Pts = crashdump_helper:create_persistent_terms(), + Pts = proplists:get_value(pts,Dict), io:format(" persistent terms ok",[]), ok; _ -> diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c index 8c799f6ff1..fb4f61417e 100644 --- a/lib/odbc/c_src/odbcserver.c +++ b/lib/odbc/c_src/odbcserver.c @@ -2749,6 +2749,11 @@ static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle, Boolean ext errmsg_buffer_size = errmsg_buffer_size - errmsg_size; acc_errmsg_size = acc_errmsg_size + errmsg_size; current_errmsg_pos = current_errmsg_pos + errmsg_size; + } else if(result == SQL_SUCCESS_WITH_INFO && errmsg_size >= errmsg_buffer_size) { + memcpy(diagnos.sqlState, current_sql_state, SQL_STATE_SIZE); + diagnos.nativeError = nativeError; + acc_errmsg_size = errmsg_buffer_size; + break; } else { break; } diff --git a/lib/odbc/doc/src/odbc.xml b/lib/odbc/doc/src/odbc.xml index 4bb1f035f9..4d941b3b36 100644 --- a/lib/odbc/doc/src/odbc.xml +++ b/lib/odbc/doc/src/odbc.xml @@ -29,7 +29,7 @@ <date></date> <rev></rev> </header> - <module>odbc</module> + <module since="">odbc</module> <modulesummary>Erlang ODBC application</modulesummary> <description> <p>This application provides an Erlang interface to communicate @@ -130,8 +130,8 @@ </section> <funcs> <func> - <name>commit(Ref, CommitMode) -></name> - <name>commit(Ref, CommitMode, TimeOut) -> ok | {error, Reason} </name> + <name since="">commit(Ref, CommitMode) -></name> + <name since="">commit(Ref, CommitMode, TimeOut) -> ok | {error, Reason} </name> <fsummary>Commits or rollbacks a transaction. </fsummary> <type> <v>Ref = connection_reference() </v> @@ -145,7 +145,7 @@ </desc> </func> <func> - <name>connect(ConnectStr, Options) -> {ok, Ref} | {error, Reason} </name> + <name since="">connect(ConnectStr, Options) -> {ok, Ref} | {error, Reason} </name> <fsummary>Opens a connection to the database. </fsummary> <type> <v>ConnectStr = string()</v> @@ -236,7 +236,7 @@ </desc> </func> <func> - <name>disconnect(Ref) -> ok | {error, Reason} </name> + <name since="">disconnect(Ref) -> ok | {error, Reason} </name> <fsummary>Closes a connection to a database. </fsummary> <type> <v>Ref = connection_reference()</v> @@ -255,8 +255,8 @@ </desc> </func> <func> - <name>describe_table(Ref, Table) -> </name> - <name>describe_table(Ref, Table, Timeout) -> {ok, Description} | {error, Reason} </name> + <name since="">describe_table(Ref, Table) -> </name> + <name since="">describe_table(Ref, Table, Timeout) -> {ok, Description} | {error, Reason} </name> <fsummary>Queries the database to find out the data types of the columns of the table <c>Table</c>. </fsummary> <type> <v>Ref = connection_reference()</v> @@ -271,8 +271,8 @@ </desc> </func> <func> - <name>first(Ref) -></name> - <name>first(Ref, Timeout) -> {selected, ColNames, Rows} | {error, Reason} </name> + <name since="">first(Ref) -></name> + <name since="">first(Ref, Timeout) -> {selected, ColNames, Rows} | {error, Reason} </name> <fsummary>Returns the first row of the result set and positions a cursor at this row.</fsummary> <type> <v>Ref = connection_reference()</v> @@ -287,8 +287,8 @@ </desc> </func> <func> - <name>last(Ref) -></name> - <name>last(Ref, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name> + <name since="">last(Ref) -></name> + <name since="">last(Ref, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name> <fsummary>Returns the last row of the result set and positions a cursor at this row. </fsummary> <type> <v>Ref = connection_reference()</v> @@ -303,8 +303,8 @@ </desc> </func> <func> - <name>next(Ref) -> </name> - <name>next(Ref, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name> + <name since="">next(Ref) -> </name> + <name since="">next(Ref, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name> <fsummary>Returns the next row of the result set relative the current cursor position and positions the cursor at this row. </fsummary> <type> <v>Ref = connection_reference()</v> @@ -325,8 +325,8 @@ </desc> </func> <func> - <name>param_query(Ref, SQLQuery, Params) -> </name> - <name>param_query(Ref, SQLQuery, Params, TimeOut) -> ResultTuple | {error, Reason} </name> + <name since="">param_query(Ref, SQLQuery, Params) -> </name> + <name since="">param_query(Ref, SQLQuery, Params, TimeOut) -> ResultTuple | {error, Reason} </name> <fsummary>Executes a parameterized SQL query.</fsummary> <type> <v>Ref = connection_reference()</v> @@ -353,8 +353,8 @@ </desc> </func> <func> - <name>prev(Ref) -> </name> - <name>prev(ConnectionReference, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name> + <name since="">prev(Ref) -> </name> + <name since="">prev(ConnectionReference, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name> <fsummary>Returns the previous row of the result set relative the current cursor position and positions the cursor at this row. </fsummary> <type> <v>Ref = connection_reference()</v> @@ -371,8 +371,8 @@ </func> <func> - <name>start() -> </name> - <name>start(Type) -> ok | {error, Reason}</name> + <name since="">start() -> </name> + <name since="">start(Type) -> ok | {error, Reason}</name> <fsummary>Starts the odb application. </fsummary> <type> @@ -389,7 +389,7 @@ </func> <func> - <name>stop() -> ok </name> + <name since="">stop() -> ok </name> <fsummary> Stops the odbc application.</fsummary> <desc> @@ -400,8 +400,8 @@ </func> <func> - <name>sql_query(Ref, SQLQuery) -> </name> - <name>sql_query(Ref, SQLQuery, TimeOut) -> ResultTuple | [ResultTuple] |{error, Reason}</name> + <name since="">sql_query(Ref, SQLQuery) -> </name> + <name since="">sql_query(Ref, SQLQuery, TimeOut) -> ResultTuple | [ResultTuple] |{error, Reason}</name> <fsummary>Executes a SQL query or a batch of SQL queries. If it is a SELECT query the result set is returned, on the format<c>{selected, ColNames, Rows}</c>. For other query types the tuple <c>{updated, NRows}</c>is returned, and for batched queries, if the driver supports them, this function can also return a list of result tuples.</fsummary> <type> <v>Ref = connection_reference()</v> @@ -429,8 +429,8 @@ </desc> </func> <func> - <name>select_count(Ref, SelectQuery) -> </name> - <name>select_count(Ref, SelectQuery, TimeOut) -> {ok, NrRows} | {error, Reason} </name> + <name since="">select_count(Ref, SelectQuery) -> </name> + <name since="">select_count(Ref, SelectQuery, TimeOut) -> {ok, NrRows} | {error, Reason} </name> <fsummary>Executes a SQL SELECT query and associates the result set with the connection. A cursor is positioned before the first row in the result set and the tuple <c>{ok, NrRows}</c>is returned. </fsummary> <type> <v>Ref = connection_reference()</v> @@ -453,8 +453,8 @@ </desc> </func> <func> - <name>select(Ref, Position, N) -></name> - <name>select(Ref, Position, N, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name> + <name since="">select(Ref, Position, N) -></name> + <name since="">select(Ref, Position, N, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name> <fsummary>Selects <c>N</c>consecutive rows of the result set.</fsummary> <type> <v>Ref = connection_reference()</v> diff --git a/lib/os_mon/doc/src/cpu_sup.xml b/lib/os_mon/doc/src/cpu_sup.xml index bada165a06..b7adb2bcd2 100644 --- a/lib/os_mon/doc/src/cpu_sup.xml +++ b/lib/os_mon/doc/src/cpu_sup.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>cpu_sup</module> + <module since="">cpu_sup</module> <modulesummary>A CPU Load and CPU Utilization Supervisor Process</modulesummary> <description> <p><c>cpu_sup</c> is a process which supervises the CPU load @@ -76,7 +76,7 @@ </description> <funcs> <func> - <name>nprocs() -> UnixProcesses | {error, Reason}</name> + <name since="">nprocs() -> UnixProcesses | {error, Reason}</name> <fsummary>Get the number of UNIX processes running on this host</fsummary> <type> <v>UnixProcesses = int()</v> @@ -90,7 +90,7 @@ </desc> </func> <func> - <name>avg1() -> SystemLoad | {error, Reason}</name> + <name since="">avg1() -> SystemLoad | {error, Reason}</name> <fsummary>Get the system load average for the last minute</fsummary> <type> <v>SystemLoad = int()</v> @@ -104,7 +104,7 @@ </desc> </func> <func> - <name>avg5() -> SystemLoad | {error, Reason}</name> + <name since="">avg5() -> SystemLoad | {error, Reason}</name> <fsummary>Get the system load average for the last five minutes</fsummary> <type> <v>SystemLoad = int()</v> @@ -118,7 +118,7 @@ </desc> </func> <func> - <name>avg15() -> SystemLoad | {error, Reason}</name> + <name since="">avg15() -> SystemLoad | {error, Reason}</name> <fsummary>Get the system load average for the last fifteen minutes</fsummary> <type> <v>SystemLoad = int()</v> @@ -132,7 +132,7 @@ </desc> </func> <func> - <name>util() -> CpuUtil | {error, Reason}</name> + <name since="">util() -> CpuUtil | {error, Reason}</name> <fsummary>Get the CPU utilization</fsummary> <type> <v>CpuUtil = float()</v> @@ -156,7 +156,7 @@ </desc> </func> <func> - <name>util(Opts) -> UtilSpec | {error, Reason}</name> + <name since="">util(Opts) -> UtilSpec | {error, Reason}</name> <fsummary>Get the CPU utilization</fsummary> <type> <v>Opts = [detailed | per_cpu]</v> diff --git a/lib/os_mon/doc/src/disksup.xml b/lib/os_mon/doc/src/disksup.xml index 610ef2c907..116a6dfd19 100644 --- a/lib/os_mon/doc/src/disksup.xml +++ b/lib/os_mon/doc/src/disksup.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>disksup</module> + <module since="">disksup</module> <modulesummary>A Disk Supervisor Process</modulesummary> <description> <p><c>disksup</c> is a process which supervises the available disk @@ -92,7 +92,7 @@ </section> <funcs> <func> - <name>get_disk_data() -> [DiskData]</name> + <name since="">get_disk_data() -> [DiskData]</name> <fsummary>Get data for the disks in the system</fsummary> <type> <v>DiskData = {Id, KByte, Capacity}</v> @@ -112,7 +112,7 @@ </desc> </func> <func> - <name>get_check_interval() -> MS</name> + <name since="">get_check_interval() -> MS</name> <fsummary>Get time interval, in milliseconds, for the periodic disk space check</fsummary> <type> <v>MS = int()</v> @@ -123,7 +123,7 @@ </desc> </func> <func> - <name>set_check_interval(Minutes) -> ok</name> + <name since="">set_check_interval(Minutes) -> ok</name> <fsummary>Set time interval, in minutes, for the periodic disk space check</fsummary> <type> <v>Minutes = int()>=1</v> @@ -138,7 +138,7 @@ </desc> </func> <func> - <name>get_almost_full_threshold() -> Percent</name> + <name since="">get_almost_full_threshold() -> Percent</name> <fsummary>Get threshold, in percent, for disk space utilization</fsummary> <type> <v>Percent = int()</v> @@ -148,7 +148,7 @@ </desc> </func> <func> - <name>set_almost_full_threshold(Float) -> ok</name> + <name since="">set_almost_full_threshold(Float) -> ok</name> <fsummary>Set threshold, as percentage represented by a float, for disk space utilization</fsummary> <type> <v>Float = float(), 0=<Float=<1</v> diff --git a/lib/os_mon/doc/src/memsup.xml b/lib/os_mon/doc/src/memsup.xml index c669e4670a..51c78b07c2 100644 --- a/lib/os_mon/doc/src/memsup.xml +++ b/lib/os_mon/doc/src/memsup.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>memsup</module> + <module since="">memsup</module> <modulesummary>A Memory Supervisor Process</modulesummary> <description> <p><c>memsup</c> is a process which supervises the memory usage for @@ -127,7 +127,7 @@ </section> <funcs> <func> - <name>get_memory_data() -> {Total,Allocated,Worst}</name> + <name since="">get_memory_data() -> {Total,Allocated,Worst}</name> <fsummary>Get data for the memory in the system</fsummary> <type> <v>Total = Allocated = int()</v> @@ -155,7 +155,7 @@ </desc> </func> <func> - <name>get_system_memory_data() -> MemDataList</name> + <name since="">get_system_memory_data() -> MemDataList</name> <fsummary>Get system dependent memory data</fsummary> <type> <v>MemDataList = [{Tag, Size}]</v> @@ -216,7 +216,7 @@ </desc> </func> <func> - <name>get_os_wordsize() -> Wordsize</name> + <name since="">get_os_wordsize() -> Wordsize</name> <fsummary>Get the wordsize of running os.</fsummary> <type> <v>Wordsize = 32 | 64 | unsupported_os</v> @@ -226,7 +226,7 @@ </desc> </func> <func> - <name>get_check_interval() -> MS</name> + <name since="">get_check_interval() -> MS</name> <fsummary>Get time interval, in milliseconds, for the periodic memory check</fsummary> <type> <v>MS = int()</v> @@ -237,7 +237,7 @@ </desc> </func> <func> - <name>set_check_interval(Minutes) -> ok</name> + <name since="">set_check_interval(Minutes) -> ok</name> <fsummary>Set time interval, in minutes, for the periodic memory check</fsummary> <type> <v>Minutes = int()>0</v> @@ -252,7 +252,7 @@ </desc> </func> <func> - <name>get_procmem_high_watermark() -> int()</name> + <name since="">get_procmem_high_watermark() -> int()</name> <fsummary>Get threshold, in percent, for process memory allocation</fsummary> <desc> <p>Returns the threshold, in percent, for process memory @@ -260,7 +260,7 @@ </desc> </func> <func> - <name>set_procmem_high_watermark(Float) -> ok</name> + <name since="">set_procmem_high_watermark(Float) -> ok</name> <fsummary>Set threshold, as percentage represented by a float, for process memory allocation</fsummary> <desc> <p>Changes the threshold, given as a float, for process memory @@ -273,7 +273,7 @@ </desc> </func> <func> - <name>get_sysmem_high_watermark() -> int()</name> + <name since="">get_sysmem_high_watermark() -> int()</name> <fsummary>Get threshold, in percent, for system memory allocation</fsummary> <desc> <p>Returns the threshold, in percent, for system memory @@ -281,7 +281,7 @@ </desc> </func> <func> - <name>set_sysmem_high_watermark(Float) -> ok</name> + <name since="">set_sysmem_high_watermark(Float) -> ok</name> <fsummary>Set threshold, given as a float, for system memory allocation</fsummary> <desc> <p>Changes the threshold, given as a float, for system memory @@ -294,7 +294,7 @@ </desc> </func> <func> - <name>get_helper_timeout() -> Seconds</name> + <name since="">get_helper_timeout() -> Seconds</name> <fsummary>Get the timeout value, in seconds, for memory checks</fsummary> <type> <v>Seconds = int()</v> @@ -304,7 +304,7 @@ </desc> </func> <func> - <name>set_helper_timeout(Seconds) -> ok</name> + <name since="">set_helper_timeout(Seconds) -> ok</name> <fsummary>Set the timeout value, in seconds, for memory checks</fsummary> <type> <v>Seconds = int() (>= 1)</v> diff --git a/lib/os_mon/doc/src/nteventlog.xml b/lib/os_mon/doc/src/nteventlog.xml index d32427227c..08cf165a24 100644 --- a/lib/os_mon/doc/src/nteventlog.xml +++ b/lib/os_mon/doc/src/nteventlog.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>nteventlog</module> + <module since="">nteventlog</module> <modulesummary>Interface to Windows Event Log</modulesummary> <description> <p><c>nteventlog</c> provides a generic interface to the Windows @@ -61,8 +61,8 @@ </description> <funcs> <func> - <name>start(Identifier, MFA) -> Result</name> - <name>start_link(Identifier, MFA) -> Result</name> + <name since="">start(Identifier, MFA) -> Result</name> + <name since="">start_link(Identifier, MFA) -> Result</name> <fsummary>Start the NT eventlog server</fsummary> <type> <v>Identifier = string() | atom()</v> @@ -82,7 +82,7 @@ </desc> </func> <func> - <name>stop() -> stopped</name> + <name since="">stop() -> stopped</name> <fsummary>Stop the NT eventlog server</fsummary> <type> <v>Result = stopped</v> diff --git a/lib/os_mon/doc/src/os_mon_mib.xml b/lib/os_mon/doc/src/os_mon_mib.xml index e995bf3de1..f6d0b20094 100644 --- a/lib/os_mon/doc/src/os_mon_mib.xml +++ b/lib/os_mon/doc/src/os_mon_mib.xml @@ -29,7 +29,7 @@ <date></date> <rev></rev> </header> - <module>os_mon_mib</module> + <module since="">os_mon_mib</module> <modulesummary>Loading and Unloading of OTP-OS-MON-MIB</modulesummary> <description> <p>Functions for loading and unloading the OTP-OS-MON-MIB into/from @@ -42,7 +42,7 @@ </description> <funcs> <func> - <name>load(Agent) -> ok | {error, Reason}</name> + <name since="">load(Agent) -> ok | {error, Reason}</name> <fsummary>Load the OTP-OS-MON-MIB</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -53,7 +53,7 @@ </desc> </func> <func> - <name>unload(Agent) -> ok | {error, Reason}</name> + <name since="">unload(Agent) -> ok | {error, Reason}</name> <fsummary>Unload the OTP-OS-MON-MIB</fsummary> <type> <v>Agent = pid() | atom() </v> diff --git a/lib/os_mon/doc/src/os_sup.xml b/lib/os_mon/doc/src/os_sup.xml index d517f387b4..4a84165a6c 100644 --- a/lib/os_mon/doc/src/os_sup.xml +++ b/lib/os_mon/doc/src/os_sup.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>os_sup</module> + <module since="">os_sup</module> <modulesummary>Interface to OS System Messages</modulesummary> <description> <p><c>os_sup</c> is a process providing a message passing service @@ -159,8 +159,8 @@ </section> <funcs> <func> - <name>enable() -> ok | {error, Res}</name> - <name>enable(Dir, Conf) -> ok | {error, Error}</name> + <name since="">enable() -> ok | {error, Res}</name> + <name since="">enable(Dir, Conf) -> ok | {error, Error}</name> <fsummary>Enable the service (Solaris only)</fsummary> <type> <v>Dir = Conf = Res = string()</v> @@ -194,8 +194,8 @@ </desc> </func> <func> - <name>disable() -> ok | {error, Res}</name> - <name>disable(Dir, Conf) -> ok | {error, Error}</name> + <name since="">disable() -> ok | {error, Res}</name> + <name since="">disable(Dir, Conf) -> ok | {error, Error}</name> <fsummary>Disable the service (Solaris only)</fsummary> <type> <v>Dir = Conf = Res = string()</v> diff --git a/lib/otp_mibs/doc/src/otp_mib.xml b/lib/otp_mibs/doc/src/otp_mib.xml index 530c529c69..e7d338c165 100644 --- a/lib/otp_mibs/doc/src/otp_mib.xml +++ b/lib/otp_mibs/doc/src/otp_mib.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>otp_mib</module> + <module since="">otp_mib</module> <modulesummary>Handles the OTP-MIB</modulesummary> <description> <p>The SNMP application should be used to start an SNMP agent. Then @@ -41,7 +41,7 @@ </description> <funcs> <func> - <name>load(Agent) -> ok | {error, Reason}</name> + <name since="">load(Agent) -> ok | {error, Reason}</name> <fsummary>Load the OTP-MIB</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -52,7 +52,7 @@ </desc> </func> <func> - <name>unload(Agent) -> ok | {error, Reason}</name> + <name since="">unload(Agent) -> ok | {error, Reason}</name> <fsummary>Unload the OTP-MIB</fsummary> <type> <v>Agent = pid() | atom()</v> diff --git a/lib/parsetools/doc/src/leex.xml b/lib/parsetools/doc/src/leex.xml index 1227625287..3b82f60201 100644 --- a/lib/parsetools/doc/src/leex.xml +++ b/lib/parsetools/doc/src/leex.xml @@ -21,7 +21,7 @@ <rev>A</rev> <file>leex.xml</file> </header> - <module>leex</module> + <module since="">leex</module> <modulesummary>Lexical analyzer generator for Erlang</modulesummary> <description> <p>A regular expression based lexical analyzer generator for @@ -38,7 +38,8 @@ Token = tuple()</code> </section> <funcs> <func> - <name>file(FileName, [, Options]) -> LeexRet</name> + <name since="">file(FileName) -> LeexRet</name> + <name since="OTP R16B02">file(FileName, Options) -> LeexRet</name> <fsummary>Generate a lexical analyzer</fsummary> <type> <v>FileName = filename()</v> @@ -124,7 +125,7 @@ Token = tuple()</code> </desc> </func> <func> - <name>format_error(ErrorInfo) -> Chars</name> + <name since="">format_error(ErrorInfo) -> Chars</name> <fsummary>Return an English description of a an error tuple.</fsummary> <type> <v>Chars = [char() | Chars]</v> @@ -145,8 +146,8 @@ Token = tuple()</code> <funcs> <func> - <name>string(String) -> StringRet</name> - <name>string(String, StartLine) -> StringRet</name> + <name since="">string(String) -> StringRet</name> + <name since="">string(String, StartLine) -> StringRet</name> <fsummary>Generated by Leex</fsummary> <type> <v>String = string()</v> @@ -163,9 +164,9 @@ Token = tuple()</code> </func> <func> - <name>token(Cont, Chars) -> {more,Cont1} | {done,TokenRet,RestChars} + <name since="">token(Cont, Chars) -> {more,Cont1} | {done,TokenRet,RestChars} </name> - <name>token(Cont, Chars, StartLine) -> {more,Cont1} + <name since="">token(Cont, Chars, StartLine) -> {more,Cont1} | {done,TokenRet,RestChars} </name> <fsummary>Generated by Leex</fsummary> @@ -198,9 +199,9 @@ io:request(InFile, {get_until,Prompt,Module,token,[Line]}) </func> <func> - <name>tokens(Cont, Chars) -> {more,Cont1} | {done,TokensRet,RestChars} + <name since="">tokens(Cont, Chars) -> {more,Cont1} | {done,TokensRet,RestChars} </name> - <name>tokens(Cont, Chars, StartLine) -> + <name since="">tokens(Cont, Chars, StartLine) -> {more,Cont1} | {done,TokensRet,RestChars} </name> <fsummary>Generated by Leex</fsummary> diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml index 5f95b5c150..67a2c95c25 100644 --- a/lib/parsetools/doc/src/yecc.xml +++ b/lib/parsetools/doc/src/yecc.xml @@ -32,7 +32,7 @@ <rev>B</rev> <file>yecc.sgml</file> </header> - <module>yecc</module> + <module since="">yecc</module> <modulesummary>LALR-1 Parser Generator</modulesummary> <description> <p>An LALR-1 parser generator for Erlang, similar to <c>yacc</c>. @@ -46,7 +46,7 @@ </description> <funcs> <func> - <name>file(Grammarfile [, Options]) -> YeccRet</name> + <name since="">file(Grammarfile [, Options]) -> YeccRet</name> <fsummary>Give information about resolved and unresolved parse action conflicts.</fsummary> <type> <v>Grammarfile = filename()</v> @@ -137,7 +137,7 @@ </desc> </func> <func> - <name>format_error(Reason) -> Chars</name> + <name since="">format_error(Reason) -> Chars</name> <fsummary>Return an English description of a an error tuple.</fsummary> <type> <v>Reason = - as returned by yecc:file/1,2 -</v> diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index ee3877ddd0..b7589f6653 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -31,7 +31,7 @@ <date></date> <rev></rev> </header> - <module>public_key</module> + <module since="">public_key</module> <modulesummary>API module for public-key infrastructure.</modulesummary> <description> <p>Provides functions to handle public-key infrastructure, @@ -176,7 +176,7 @@ <funcs> <func> - <name name="compute_key" arity="2"/> + <name name="compute_key" arity="2" since="OTP R16B01"/> <fsummary>Computes shared secret.</fsummary> <desc> <p>Computes shared secret.</p> @@ -184,7 +184,7 @@ </func> <func> - <name name="compute_key" arity="3"/> + <name name="compute_key" arity="3" since="OTP R16B01"/> <fsummary>Computes shared secret.</fsummary> <desc> <p>Computes shared secret.</p> @@ -192,8 +192,8 @@ </func> <func> - <name name="decrypt_private" arity="2"/> - <name name="decrypt_private" arity="3"/> + <name name="decrypt_private" arity="2" since="OTP R14B"/> + <name name="decrypt_private" arity="3" since="OTP R14B"/> <fsummary>Public-key decryption.</fsummary> <desc> <p>Public-key decryption using the private key. See also <seealso @@ -202,8 +202,8 @@ </func> <func> - <name name="decrypt_public" arity="2"/> - <name name="decrypt_public" arity="3"/> + <name name="decrypt_public" arity="2" since="OTP R14B"/> + <name name="decrypt_public" arity="3" since="OTP R14B"/> <fsummary>Public-key decryption.</fsummary> <desc> <p>Public-key decryption using the public key. See also <seealso @@ -212,7 +212,7 @@ </func> <func> - <name name="der_decode" arity="2"/> + <name name="der_decode" arity="2" since="OTP R14B"/> <fsummary>Decodes a public-key ASN.1 DER encoded entity.</fsummary> <desc> <p>Decodes a public-key ASN.1 DER encoded entity.</p> @@ -220,7 +220,7 @@ </func> <func> - <name name="der_encode" arity="2"/> + <name name="der_encode" arity="2" since="OTP R14B"/> <fsummary>Encodes a public-key entity with ASN.1 DER encoding.</fsummary> <desc> <p>Encodes a public-key entity with ASN.1 DER encoding.</p> @@ -228,7 +228,7 @@ </func> <func> - <name name="dh_gex_group" arity="4"/> + <name name="dh_gex_group" arity="4" since="OTP 18.2"/> <fsummary>Selects a group for Diffie-Hellman key exchange</fsummary> <desc> <p>Selects a group for Diffie-Hellman key exchange with the key size in the range <c>MinSize...MaxSize</c> @@ -249,8 +249,8 @@ </func> <func> - <name name="encrypt_private" arity="2"/> - <name name="encrypt_private" arity="3"/> + <name name="encrypt_private" arity="2" since="OTP R14B"/> + <name name="encrypt_private" arity="3" since="OTP 21.1"/> <fsummary>Public-key encryption using the private key.</fsummary> <desc> <p>Public-key encryption using the private key. @@ -260,8 +260,8 @@ </func> <func> - <name name="encrypt_public" arity="2"/> - <name name="encrypt_public" arity="3"/> + <name name="encrypt_public" arity="2" since="OTP R14B"/> + <name name="encrypt_public" arity="3" since="OTP 21.1"/> <fsummary>Public-key encryption using the public key.</fsummary> <desc> <p>Public-key encryption using the public key. See also <seealso @@ -270,7 +270,7 @@ </func> <func> - <name name="generate_key" arity="1"/> + <name name="generate_key" arity="1" since="OTP R16B01"/> <fsummary>Generates a new keypair.</fsummary> <desc> <p>Generates a new keypair. Note that except for Diffie-Hellman @@ -281,7 +281,7 @@ </func> <func> - <name name="pem_decode" arity="1"/> + <name name="pem_decode" arity="1" since="OTP R14B"/> <fsummary>Decodes PEM binary data and returns entries as ASN.1 DER encoded entities.</fsummary> <desc> @@ -291,7 +291,7 @@ </func> <func> - <name name="pem_encode" arity="1"/> + <name name="pem_encode" arity="1" since="OTP R14B"/> <fsummary>Creates a PEM binary.</fsummary> <desc> <p>Creates a PEM binary.</p> @@ -299,8 +299,8 @@ </func> <func> - <name name="pem_entry_decode" arity="1"/> - <name name="pem_entry_decode" arity="2"/> + <name name="pem_entry_decode" arity="1" since="OTP R14B"/> + <name name="pem_entry_decode" arity="2" since="OTP R14B"/> <fsummary>Decodes a PEM entry.</fsummary> <desc> <p>Decodes a PEM entry. <c>pem_decode/1</c> returns a list of PEM @@ -311,8 +311,8 @@ </func> <func> - <name name="pem_entry_encode" arity="2"/> - <name name="pem_entry_encode" arity="3"/> + <name name="pem_entry_encode" arity="2" since="OTP R14B"/> + <name name="pem_entry_encode" arity="3" since="OTP R14B"/> <fsummary>Creates a PEM entry that can be fed to <c>pem_encode/1</c>.</fsummary> <desc> <p>Creates a PEM entry that can be feed to <c>pem_encode/1</c>.</p> @@ -326,7 +326,7 @@ </func> <func> - <name name="pkix_decode_cert" arity="2"/> + <name name="pkix_decode_cert" arity="2" since=""/> <fsummary>Decodes an ASN.1 DER-encoded PKIX x509 certificate.</fsummary> <desc> <p>Decodes an ASN.1 DER-encoded PKIX certificate. Option <c>otp</c> @@ -337,7 +337,7 @@ </func> <func> - <name name="pkix_encode" arity="3"/> + <name name="pkix_encode" arity="3" since="OTP R14B"/> <fsummary>DER encodes a PKIX x509 certificate or part of such a certificate.</fsummary> <desc> @@ -349,7 +349,7 @@ </func> <func> - <name name="pkix_is_issuer" arity="2"/> + <name name="pkix_is_issuer" arity="2" since="OTP R14B"/> <fsummary>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</fsummary> <desc> <p>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</p> @@ -357,7 +357,7 @@ </func> <func> - <name name="pkix_is_fixed_dh_cert" arity="1"/> + <name name="pkix_is_fixed_dh_cert" arity="1" since="OTP R14B"/> <fsummary>Checks if a certificate is a fixed Diffie-Hellman certificate.</fsummary> <desc> <p>Checks if a certificate is a fixed Diffie-Hellman certificate.</p> @@ -365,7 +365,7 @@ </func> <func> - <name name="pkix_is_self_signed" arity="1"/> + <name name="pkix_is_self_signed" arity="1" since="OTP R14B"/> <fsummary>Checks if a certificate is self-signed.</fsummary> <desc> <p>Checks if a certificate is self-signed.</p> @@ -373,7 +373,7 @@ </func> <func> - <name name="pkix_issuer_id" arity="2"/> + <name name="pkix_issuer_id" arity="2" since="OTP R14B"/> <fsummary>Returns the issuer id.</fsummary> <desc> <p>Returns the issuer id.</p> @@ -381,7 +381,7 @@ </func> <func> - <name name="pkix_normalize_name" arity="1"/> + <name name="pkix_normalize_name" arity="1" since="OTP R14B"/> <fsummary>Normalizes an issuer name so that it can be easily compared to another issuer name.</fsummary> <desc> @@ -391,7 +391,7 @@ </func> <func> - <name>pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, {PublicKeyInfo, PolicyTree}} | {error, {bad_cert, Reason}} </name> + <name since="OTP R16B">pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, {PublicKeyInfo, PolicyTree}} | {error, {bad_cert, Reason}} </name> <fsummary>Performs a basic path validation according to RFC 5280.</fsummary> <type> <v>TrustedCert = #'OTPCertificate'{} | der_encoded() | atom()</v> @@ -491,7 +491,7 @@ fun(OtpCert :: #'OTPCertificate'{}, </func> <func> - <name name="pkix_crl_issuer" arity="1"/> + <name name="pkix_crl_issuer" arity="1" since="OTP 17.5"/> <fsummary>Returns the issuer of the <c>CRL</c>.</fsummary> <desc> <p>Returns the issuer of the <c>CRL</c>.</p> @@ -499,7 +499,7 @@ fun(OtpCert :: #'OTPCertificate'{}, </func> <func> - <name name="pkix_crls_validate" arity="3"/> + <name name="pkix_crls_validate" arity="3" since="OTP R16B"/> <fsummary>Performs CRL validation.</fsummary> <desc> <p>Performs CRL validation. It is intended to be called from @@ -551,7 +551,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name name="pkix_crl_verify" arity="2"/> + <name name="pkix_crl_verify" arity="2" since="OTP 17.5"/> <fsummary> Verify that <c>Cert</c> is the <c> CRL</c> signer. </fsummary> <desc> <p>Verify that <c>Cert</c> is the <c>CRL</c> signer.</p> @@ -559,7 +559,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name name="pkix_dist_point" arity="1"/> + <name name="pkix_dist_point" arity="1" since="OTP 17.5"/> <fsummary>Creates a distribution point for CRLs issued by the same issuer as <c>Cert</c>.</fsummary> <desc> <p>Creates a distribution point for CRLs issued by the same issuer as <c>Cert</c>. @@ -570,7 +570,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name name="pkix_dist_points" arity="1"/> + <name name="pkix_dist_points" arity="1" since="OTP 17.5"/> <fsummary> Extracts distribution points from the certificates extensions.</fsummary> <desc> <p> Extracts distribution points from the certificates extensions.</p> @@ -578,7 +578,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name name="pkix_match_dist_point" arity="2"/> + <name name="pkix_match_dist_point" arity="2" since="OTP 19.0"/> <fsummary>Checks whether the given distribution point matches the Issuing Distribution Point of the CRL.</fsummary> <desc> @@ -590,7 +590,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name name="pkix_sign" arity="2"/> + <name name="pkix_sign" arity="2" since="OTP R14B"/> <fsummary>Signs certificate.</fsummary> <desc> <p>Signs an 'OTPTBSCertificate'. Returns the corresponding @@ -599,7 +599,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name name="pkix_sign_types" arity="1"/> + <name name="pkix_sign_types" arity="1" since="OTP R16B01"/> <fsummary>Translates signature algorithm OID to Erlang digest and signature algorithm types.</fsummary> <desc> <p>Translates signature algorithm OID to Erlang digest and signature types. @@ -609,8 +609,8 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name>pkix_test_data(Options) -> Config </name> - <name>pkix_test_data([chain_opts()]) -> [conf_opt()]</name> + <name since="OTP 20.1">pkix_test_data(Options) -> Config </name> + <name since="OTP 20.1">pkix_test_data([chain_opts()]) -> [conf_opt()]</name> <fsummary>Creates certificate test data.</fsummary> <type> <v>Options = #{chain_type() := chain_opts()} </v> @@ -644,7 +644,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, <v>conf_opt() = {cert, der_encoded()} | {key, PrivateKey} |{cacerts, [der_encoded()]}</v> <d> This is a subset of the type - <seealso marker="ssl:ssl#type-ssloption"> ssl:ssl_option()</seealso>. + <seealso marker="ssl:ssl#type-tls_option"> ssl:tls_option()</seealso>. <c>PrivateKey</c> is what <seealso marker="#generate_key-1">generate_key/1</seealso> returns. @@ -742,7 +742,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name>pkix_test_root_cert(Name, Options) -> RootCert</name> + <name since="OTP 20.2">pkix_test_root_cert(Name, Options) -> RootCert</name> <fsummary>Generates a test data root cert.</fsummary> <type> <v>Name = string()</v> @@ -772,7 +772,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name name="pkix_verify" arity="2"/> + <name name="pkix_verify" arity="2" since="OTP R14B"/> <fsummary>Verifies PKIX x.509 certificate signature.</fsummary> <desc> <p>Verifies PKIX x.509 certificate signature.</p> @@ -780,8 +780,8 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </func> <func> - <name>pkix_verify_hostname(Cert, ReferenceIDs) -> boolean()</name> - <name>pkix_verify_hostname(Cert, ReferenceIDs, Opts) -> boolean()</name> + <name since="OTP 19.3">pkix_verify_hostname(Cert, ReferenceIDs) -> boolean()</name> + <name since="OTP 19.3">pkix_verify_hostname(Cert, ReferenceIDs, Opts) -> boolean()</name> <fsummary>Verifies that a PKIX x.509 certificate <i>presented identifier</i> (e.g hostname) is an expected one.</fsummary> <type> @@ -864,7 +864,7 @@ end </func> <func> - <name>pkix_verify_hostname_match_fun(Protcol) -> fun(RefId | FQDN::string(), PresentedID) -> boolean() | default</name> + <name since="OTP 21.0">pkix_verify_hostname_match_fun(Protcol) -> fun(RefId | FQDN::string(), PresentedID) -> boolean() | default</name> <fsummary>Returns a fun that is intendended as argument to the match_fun option in pkix_verify_hostname/3. </fsummary> <type> @@ -889,8 +889,8 @@ end <func> - <name name="sign" arity="3"/> - <name name="sign" arity="4"/> + <name name="sign" arity="3" since=""/> + <name name="sign" arity="4" since="OTP 20.1"/> <fsummary>Creates a digital signature.</fsummary> <desc> <p>Creates a digital signature.</p> @@ -901,7 +901,7 @@ end </func> <func> - <name name="ssh_decode" arity="2"/> + <name name="ssh_decode" arity="2" since="OTP R14B03"/> <fsummary>Decodes an SSH file-binary.</fsummary> <desc> <p>Decodes an SSH file-binary. In the case of <c>known_hosts</c> or @@ -933,7 +933,7 @@ end </func> <func> - <name name="ssh_encode" arity="2"/> + <name name="ssh_encode" arity="2" since="OTP R14B03"/> <fsummary>Encodes a list of SSH file entries to a binary.</fsummary> <desc> <p>Encodes a list of SSH file entries (public keys and attributes) to a binary. Possible @@ -947,9 +947,9 @@ end </func> <func> - <name>ssh_hostkey_fingerprint(HostKey) -> string()</name> - <name>ssh_hostkey_fingerprint(DigestType, HostKey) -> string()</name> - <name>ssh_hostkey_fingerprint([DigestType], HostKey) -> [string()]</name> + <name since="OTP 19.2">ssh_hostkey_fingerprint(HostKey) -> string()</name> + <name since="OTP 19.2">ssh_hostkey_fingerprint(DigestType, HostKey) -> string()</name> + <name since="OTP 19.2">ssh_hostkey_fingerprint([DigestType], HostKey) -> [string()]</name> <fsummary>Calculates a ssh fingerprint for a hostkey.</fsummary> <type> <v>HostKey = <seealso marker="#type-public_key">public_key()</seealso></v> @@ -982,8 +982,8 @@ end </func> <func> - <name name="verify" arity="4"/> - <name name="verify" arity="5"/> + <name name="verify" arity="4" since="OTP R14B"/> + <name name="verify" arity="5" since="OTP 20.1"/> <fsummary>Verifies a digital signature.</fsummary> <desc> <p>Verifies a digital signature.</p> @@ -993,7 +993,7 @@ end </func> <func> - <name name="short_name_hash" arity="1"/> + <name name="short_name_hash" arity="1" since="OTP 19.0"/> <fsummary>Generates a short hash of an issuer name.</fsummary> <desc> <p>Generates a short hash of an issuer name. The hash is diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 75d40d2e8a..fd85d3722d 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -66,7 +66,7 @@ -export_type([public_key/0, private_key/0, pem_entry/0, pki_asn1_type/0, asn1_type/0, ssh_file/0, der_encoded/0, - key_params/0, digest_type/0]). + key_params/0, digest_type/0, issuer_name/0]). -type public_key() :: rsa_public_key() | dsa_public_key() | ec_public_key() | ed_public_key() . -type private_key() :: rsa_private_key() | dsa_private_key() | ec_private_key() | ed_private_key() . diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml index 874cda8369..5afbad0ba8 100644 --- a/lib/reltool/doc/src/reltool.xml +++ b/lib/reltool/doc/src/reltool.xml @@ -33,7 +33,7 @@ <date></date> <rev>%VSN%</rev> </header> - <module>reltool</module> + <module since="">reltool</module> <modulesummary>Main API of the Reltool application</modulesummary> <description> <p>This is an interface module for the Reltool application.</p> @@ -591,7 +591,7 @@ target_spec() = [target_spec()] <funcs> <func> - <name>create_target(Server, TargetDir) -> ok | {error, Reason}</name> + <name since="">create_target(Server, TargetDir) -> ok | {error, Reason}</name> <fsummary>Create a target system</fsummary> <type> <v>Server = server()</v> @@ -604,7 +604,7 @@ target_spec() = [target_spec()] </func> <func> - <name>eval_target_spec(TargetSpec, RootDir, TargetDir) -> ok | {error, Reason}</name> + <name since="">eval_target_spec(TargetSpec, RootDir, TargetDir) -> ok | {error, Reason}</name> <fsummary>Create a target system</fsummary> <type> <v>TargetSpec = target_spec()</v> @@ -655,7 +655,7 @@ target_spec() = [target_spec()] </func> <func> - <name>get_config(Server) -> {ok, Config} | {error, Reason}</name> + <name since="">get_config(Server) -> {ok, Config} | {error, Reason}</name> <fsummary>Get reltool configuration</fsummary> <type> <v>Server = server()</v> @@ -667,7 +667,7 @@ target_spec() = [target_spec()] </func> <func> - <name>get_config(Server, InclDefaults, InclDerived) -> {ok, Config} | {error, Reason}</name> + <name since="">get_config(Server, InclDefaults, InclDerived) -> {ok, Config} | {error, Reason}</name> <fsummary>Get reltool configuration</fsummary> <type> <v>Server = server()</v> @@ -685,7 +685,7 @@ target_spec() = [target_spec()] </func> <func> - <name>get_rel(Server, Relname) -> {ok, RelFile} | {error, Reason}</name> + <name since="">get_rel(Server, Relname) -> {ok, RelFile} | {error, Reason}</name> <fsummary>Get contents of a release file</fsummary> <type> <v>Server = server()</v> @@ -698,7 +698,7 @@ target_spec() = [target_spec()] </func> <func> - <name>get_script(Server, Relname) -> {ok, ScriptFile | {error, Reason}</name> + <name since="">get_script(Server, Relname) -> {ok, ScriptFile | {error, Reason}</name> <fsummary>Get contents of a boot script file</fsummary> <type> <v>Server = server()</v> @@ -711,7 +711,7 @@ target_spec() = [target_spec()] </func> <func> - <name>get_status(Server) -> {ok, [Warning]} | {error, Reason}</name> + <name since="OTP R14B">get_status(Server) -> {ok, [Warning]} | {error, Reason}</name> <fsummary>Get contents of a release file</fsummary> <type> <v>Server = server()</v> @@ -722,7 +722,7 @@ target_spec() = [target_spec()] </func> <func> - <name>get_server(WindowPid) -> {ok, ServerPid} | {error, Reason}</name> + <name since="">get_server(WindowPid) -> {ok, ServerPid} | {error, Reason}</name> <fsummary>Start server process with options</fsummary> <type> <v>WindowPid = window_pid()</v> @@ -733,7 +733,7 @@ target_spec() = [target_spec()] </func> <func> - <name>get_target_spec(Server) -> {ok, TargetSpec} | {error, Reason}</name> + <name since="">get_target_spec(Server) -> {ok, TargetSpec} | {error, Reason}</name> <fsummary>Return a specification of the target system</fsummary> <type> <v>Server = server()</v> @@ -747,7 +747,7 @@ target_spec() = [target_spec()] </func> <func> - <name>install(RelName, TargetDir) -> ok | {error, Reason}</name> + <name since="">install(RelName, TargetDir) -> ok | {error, Reason}</name> <fsummary>Install a target system</fsummary> <type> <v>RelName = rel_name()</v> @@ -758,7 +758,7 @@ target_spec() = [target_spec()] </func> <func> - <name>start() -> {ok, WindowPid} | {error, Reason}</name> + <name since="">start() -> {ok, WindowPid} | {error, Reason}</name> <fsummary>Start main window process</fsummary> <type> <v>WindowPid = window_pid()</v> @@ -768,7 +768,7 @@ target_spec() = [target_spec()] </func> <func> - <name>start(Options) -> {ok, WindowPid} | {error, Reason}</name> + <name since="">start(Options) -> {ok, WindowPid} | {error, Reason}</name> <fsummary>Start main window process with options</fsummary> <type> <v>Options = options()</v> @@ -779,7 +779,7 @@ target_spec() = [target_spec()] </func> <func> - <name>start_link(Options) -> {ok, WindowPid} | {error, Reason}</name> + <name since="">start_link(Options) -> {ok, WindowPid} | {error, Reason}</name> <fsummary>Start main window process with options</fsummary> <type> <v>Options = options()</v> @@ -790,7 +790,7 @@ target_spec() = [target_spec()] </func> <func> - <name>start_server(Options) -> {ok, ServerPid} | {error, Reason}</name> + <name since="">start_server(Options) -> {ok, ServerPid} | {error, Reason}</name> <fsummary>Start server process with options</fsummary> <type> <v>Options = options()</v> @@ -803,7 +803,7 @@ target_spec() = [target_spec()] </func> <func> - <name>stop(Pid) -> ok | {error, Reason}</name> + <name since="">stop(Pid) -> ok | {error, Reason}</name> <fsummary>Stop a server or window process</fsummary> <type> <v>Pid = server_pid() | window_pid()</v> diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml index 3262cafefc..941a880778 100644 --- a/lib/runtime_tools/doc/src/dbg.xml +++ b/lib/runtime_tools/doc/src/dbg.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>dbg.sgml</file> </header> - <module>dbg</module> + <module since="">dbg</module> <modulesummary>The Text Based Trace Facility</modulesummary> <description> <p>This module implements a text based interface to the @@ -68,7 +68,7 @@ </description> <funcs> <func> - <name>fun2ms(LiteralFun) -> MatchSpec</name> + <name since="">fun2ms(LiteralFun) -> MatchSpec</name> <fsummary>Pseudo function that transforms fun syntax to match_spec.</fsummary> <type> <v>LiteralFun = fun() literal</v> @@ -145,14 +145,14 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>h() -> ok </name> + <name since="">h() -> ok </name> <fsummary>Give a list of available help items on standard output.</fsummary> <desc> <p>Gives a list of items for brief online help.</p> </desc> </func> <func> - <name>h(Item) -> ok </name> + <name since="">h(Item) -> ok </name> <fsummary>Give brief help for an item.</fsummary> <type> <v>Item = atom()</v> @@ -163,14 +163,14 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>p(Item) -> {ok, MatchDesc} | {error, term()} </name> + <name since="">p(Item) -> {ok, MatchDesc} | {error, term()} </name> <fsummary>Trace messages to and from Item.</fsummary> <desc> <p>Equivalent to <c>p(Item, [m])</c>.</p> </desc> </func> <func> - <name>p(Item, Flags) -> {ok, MatchDesc} | {error, term()}</name> + <name since="">p(Item, Flags) -> {ok, MatchDesc} | {error, term()}</name> <fsummary>Trace Item according to Flags.</fsummary> <type> <v>MatchDesc = [MatchNum]</v> @@ -303,14 +303,14 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>c(Mod, Fun, Args)</name> + <name since="">c(Mod, Fun, Args)</name> <fsummary>Evaluate <c>apply(M,F,Args)</c>with <c>all</c>trace flags set.</fsummary> <desc> <p>Equivalent to <c>c(Mod, Fun, Args, all)</c>.</p> </desc> </func> <func> - <name>c(Mod, Fun, Args, Flags)</name> + <name since="">c(Mod, Fun, Args, Flags)</name> <fsummary>Evaluate <c>apply(M,F,Args)</c>with <c>Flags</c>trace flags set.</fsummary> <desc> <p>Evaluates the expression <c>apply(Mod, Fun, Args)</c> with the trace @@ -319,35 +319,35 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>i() -> ok</name> + <name since="">i() -> ok</name> <fsummary>Display information about all traced processes and ports.</fsummary> <desc> <p>Displays information about all traced processes and ports.</p> </desc> </func> <func> - <name>tp(Module,MatchSpec)</name> + <name since="">tp(Module,MatchSpec)</name> <fsummary>Set pattern for traced global function calls</fsummary> <desc> <p>Same as tp({Module, '_', '_'}, MatchSpec)</p> </desc> </func> <func> - <name>tp(Module,Function,MatchSpec)</name> + <name since="">tp(Module,Function,MatchSpec)</name> <fsummary>Set pattern for traced global function calls</fsummary> <desc> <p>Same as tp({Module, Function, '_'}, MatchSpec)</p> </desc> </func> <func> - <name>tp(Module, Function, Arity, MatchSpec)</name> + <name since="">tp(Module, Function, Arity, MatchSpec)</name> <fsummary>Set pattern for traced global function calls</fsummary> <desc> <p>Same as tp({Module, Function, Arity}, MatchSpec)</p> </desc> </func> <func> - <name>tp({Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name> + <name since="">tp({Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name> <fsummary>Set pattern for traced global function calls</fsummary> <type> <v>Module = atom() | '_'</v> @@ -410,28 +410,28 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>tpl(Module,MatchSpec)</name> + <name since="">tpl(Module,MatchSpec)</name> <fsummary>Set pattern for traced local (as well as global) function calls</fsummary> <desc> <p>Same as tpl({Module, '_', '_'}, MatchSpec)</p> </desc> </func> <func> - <name>tpl(Module,Function,MatchSpec)</name> + <name since="">tpl(Module,Function,MatchSpec)</name> <fsummary>Set pattern for traced local (as well as global) function calls</fsummary> <desc> <p>Same as tpl({Module, Function, '_'}, MatchSpec)</p> </desc> </func> <func> - <name>tpl(Module, Function, Arity, MatchSpec)</name> + <name since="">tpl(Module, Function, Arity, MatchSpec)</name> <fsummary>Set pattern for traced local (as well as global) function calls</fsummary> <desc> <p>Same as tpl({Module, Function, Arity}, MatchSpec)</p> </desc> </func> <func> - <name>tpl({Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name> + <name since="">tpl({Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name> <fsummary>Set pattern for traced local (as well as global) function calls</fsummary> <desc> <p>This function works as <seealso marker="#tp-2"><c>tp/2</c></seealso>, but enables @@ -442,7 +442,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ <func> - <name>tpe(Event, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name> + <name since="OTP 19.0">tpe(Event, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name> <fsummary>Set pattern for traced event</fsummary> <type> <v>Event = send | 'receive'</v> @@ -484,35 +484,35 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>ctp()</name> + <name since="">ctp()</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctp({'_', '_', '_'})</p> </desc> </func> <func> - <name>ctp(Module)</name> + <name since="">ctp(Module)</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctp({Module, '_', '_'})</p> </desc> </func> <func> - <name>ctp(Module, Function)</name> + <name since="">ctp(Module, Function)</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctp({Module, Function, '_'})</p> </desc> </func> <func> - <name>ctp(Module, Function, Arity)</name> + <name since="">ctp(Module, Function, Arity)</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctp({Module, Function, Arity})</p> </desc> </func> <func> - <name>ctp({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name> + <name since="">ctp({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <type> <v>Module = atom() | '_'</v> @@ -533,35 +533,35 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>ctpl()</name> + <name since="">ctpl()</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctpl({'_', '_', '_'})</p> </desc> </func> <func> - <name>ctpl(Module)</name> + <name since="">ctpl(Module)</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctpl({Module, '_', '_'})</p> </desc> </func> <func> - <name>ctpl(Module, Function)</name> + <name since="">ctpl(Module, Function)</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctpl({Module, Function, '_'})</p> </desc> </func> <func> - <name>ctpl(Module, Function, Arity)</name> + <name since="">ctpl(Module, Function, Arity)</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctpl({Module, Function, Arity})</p> </desc> </func> <func> - <name>ctpl({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name> + <name since="">ctpl({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>This function works as <seealso marker="#ctp-1"><c>ctp/1</c></seealso>, but only disables @@ -570,35 +570,35 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>ctpg()</name> + <name since="">ctpg()</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctpg({'_', '_', '_'})</p> </desc> </func> <func> - <name>ctpg(Module)</name> + <name since="">ctpg(Module)</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctpg({Module, '_', '_'})</p> </desc> </func> <func> - <name>ctpg(Module, Function)</name> + <name since="">ctpg(Module, Function)</name> <fsummary>>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctpg({Module, Function, '_'})</p> </desc> </func> <func> - <name>ctpg(Module, Function, Arity)</name> + <name since="">ctpg(Module, Function, Arity)</name> <fsummary>>Clear call trace pattern for the specified functions</fsummary> <desc> <p>Same as ctpg({Module, Function, Arity})</p> </desc> </func> <func> - <name>ctpg({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name> + <name since="">ctpg({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name> <fsummary>Clear call trace pattern for the specified functions</fsummary> <desc> <p>This function works as <seealso marker="#ctp-1"><c>ctp/1</c></seealso>, but only disables @@ -607,7 +607,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>ctpe(Event) -> {ok, MatchDesc} | {error, term()}</name> + <name since="OTP 19.0">ctpe(Event) -> {ok, MatchDesc} | {error, term()}</name> <fsummary>Clear trace pattern for the specified event</fsummary> <type> <v>Event = send | 'receive'</v> @@ -623,7 +623,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>ltp() -> ok</name> + <name since="">ltp() -> ok</name> <fsummary>List saved and built-in match specifications on the console.</fsummary> <desc> <p>Use this function to recall all match specifications previously @@ -654,7 +654,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>dtp() -> ok</name> + <name since="">dtp() -> ok</name> <fsummary>Delete all saved match specifications.</fsummary> <desc> <p>Use this function to "forget" all match specifications @@ -665,7 +665,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>dtp(N) -> ok</name> + <name since="">dtp(N) -> ok</name> <fsummary>Delete a specific saved match_spec.</fsummary> <type> <v>N = integer()</v> @@ -676,7 +676,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>wtp(Name) -> ok | {error, IOError}</name> + <name since="">wtp(Name) -> ok | {error, IOError}</name> <fsummary>Write all saved and built-in match specifications to a file</fsummary> <type> <v>Name = string()</v> @@ -699,7 +699,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>rtp(Name) -> ok | {error, Error}</name> + <name since="">rtp(Name) -> ok | {error, Error}</name> <fsummary>Read saved match specifications from file.</fsummary> <type> <v>Name = string()</v> @@ -728,7 +728,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>n(Nodename) -> {ok, Nodename} | {error, Reason}</name> + <name since="">n(Nodename) -> {ok, Nodename} | {error, Reason}</name> <fsummary>Add a remote node to the list of traced nodes</fsummary> <type> <v>Nodename = atom()</v> @@ -767,7 +767,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>cn(Nodename) -> ok</name> + <name since="">cn(Nodename) -> ok</name> <fsummary>Clear a node from the list of traced nodes.</fsummary> <type> <v>Nodename = atom()</v> @@ -782,14 +782,14 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>ln() -> ok</name> + <name since="">ln() -> ok</name> <fsummary>Show the list of traced nodes on the console.</fsummary> <desc> <p>Shows the list of traced nodes on the console.</p> </desc> </func> <func> - <name>tracer() -> {ok, pid()} | {error, already_started}</name> + <name since="">tracer() -> {ok, pid()} | {error, already_started}</name> <fsummary>Start a tracer server that handles trace messages.</fsummary> <desc> <p>This function starts a server on the local node that will @@ -805,7 +805,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>tracer(Type, Data) -> {ok, pid()} | {error, Error}</name> + <name since="">tracer(Type, Data) -> {ok, pid()} | {error, Error}</name> <fsummary>Start a tracer server with additional parameters</fsummary> <type> <v>Type = port | process | module</v> @@ -859,7 +859,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>tracer(Nodename, Type, Data) -> {ok, Nodename} | {error, Reason}</name> + <name since="">tracer(Nodename, Type, Data) -> {ok, Nodename} | {error, Reason}</name> <fsummary>Start a tracer server on given node with additional parameters</fsummary> <type> <v>Nodename = atom()</v> @@ -881,7 +881,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>trace_port(Type, Parameters) -> fun()</name> + <name since="">trace_port(Type, Parameters) -> fun()</name> <fsummary>Create and returns a trace port generating<em>fun</em></fsummary> <type> <v>Type = ip | file</v> @@ -958,28 +958,28 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>flush_trace_port()</name> + <name since="">flush_trace_port()</name> <fsummary>Equivalent to flush_trace_port(node()).</fsummary> <desc> <p>Equivalent to <c>flush_trace_port(node())</c>.</p> </desc> </func> <func> - <name>flush_trace_port(Nodename) -> ok | {error, Reason}</name> + <name since="">flush_trace_port(Nodename) -> ok | {error, Reason}</name> <fsummary>Flush internal data buffers in a trace driver on the given node.</fsummary> <desc> <p>Equivalent to <c>trace_port_control(Nodename,flush)</c>.</p> </desc> </func> <func> - <name>trace_port_control(Operation)</name> + <name since="">trace_port_control(Operation)</name> <fsummary>Equivalent to trace_port_control(node(),Operation).</fsummary> <desc> <p>Equivalent to <c>trace_port_control(node(),Operation)</c>.</p> </desc> </func> <func> - <name>trace_port_control(Nodename,Operation) -> ok | {ok, Result} | {error, Reason}</name> + <name since="">trace_port_control(Nodename,Operation) -> ok | {ok, Result} | {error, Reason}</name> <fsummary>Perform a control operation on the active trace port driver on the given node.</fsummary> <type> <v>Nodename = atom()</v> @@ -1013,7 +1013,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ </desc> </func> <func> - <name>trace_client(Type, Parameters) -> pid()</name> + <name since="">trace_client(Type, Parameters) -> pid()</name> <fsummary>Start a trace client that reads messages created by a trace port driver</fsummary> <type> <v>Type = ip | file | follow_file</v> @@ -1080,7 +1080,7 @@ hello</pre> </desc> </func> <func> - <name>trace_client(Type, Parameters, HandlerSpec) -> pid()</name> + <name since="">trace_client(Type, Parameters, HandlerSpec) -> pid()</name> <fsummary>Start a trace client that reads messages created by a trace port driver, with a user defined handler</fsummary> <type> <v>Type = ip | file | follow_file</v> @@ -1110,7 +1110,7 @@ hello</pre> </desc> </func> <func> - <name>stop_trace_client(Pid) -> ok</name> + <name since="">stop_trace_client(Pid) -> ok</name> <fsummary>Stop a trace client gracefully.</fsummary> <type> <v>Pid = pid()</v> @@ -1123,14 +1123,14 @@ hello</pre> </desc> </func> <func> - <name>get_tracer()</name> + <name since="">get_tracer()</name> <fsummary>Equivalent to get_tracer(node()).</fsummary> <desc> <p>Equivalent to <c>get_tracer(node())</c>.</p> </desc> </func> <func> - <name>get_tracer(Nodename) -> {ok, Tracer}</name> + <name since="">get_tracer(Nodename) -> {ok, Tracer}</name> <fsummary>Return the process or port to which all trace messages are sent.</fsummary> <type> <v>Nodename = atom()</v> @@ -1142,7 +1142,7 @@ hello</pre> </desc> </func> <func> - <name>stop() -> ok</name> + <name since="">stop() -> ok</name> <fsummary>Stop the <c>dbg</c>server and the tracing of all processes.</fsummary> <desc> <p>Stops the <c>dbg</c> server and clears all trace flags for @@ -1153,7 +1153,7 @@ hello</pre> </desc> </func> <func> - <name>stop_clear() -> ok</name> + <name since="">stop_clear() -> ok</name> <fsummary>Stop the <c>dbg</c>server and the tracing of all processes, and clears trace patterns.</fsummary> <desc> <p>Same as stop/0, but also clears all trace patterns on global functions calls.</p> diff --git a/lib/runtime_tools/doc/src/dyntrace.xml b/lib/runtime_tools/doc/src/dyntrace.xml index 0cdcecab68..4935dfcd71 100644 --- a/lib/runtime_tools/doc/src/dyntrace.xml +++ b/lib/runtime_tools/doc/src/dyntrace.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>dyntrace.xml</file> </header> - <module>dyntrace</module> + <module since="OTP R15B01">dyntrace</module> <modulesummary>Interface to dynamic tracing</modulesummary> <description> <p>This module implements interfaces to dynamic tracing, should such be compiled into the virtual machine. For a standard and/or commercial build, no dynamic tracing is available, in which case none of the functions in this module is usable or give any effect.</p> @@ -47,7 +47,7 @@ </description> <funcs> <func> - <name>available() -> boolean()</name> + <name since="OTP R15B01">available() -> boolean()</name> <fsummary>Check if dynamic tracing is available</fsummary> <desc> <p>This function uses the NIF library to determine if dynamic @@ -59,42 +59,42 @@ </desc> </func> <func> - <name>p() -> true | false | error | badarg</name> + <name since="OTP R15B01">p() -> true | false | error | badarg</name> <fsummary>Trigger the user trace probe.</fsummary> <desc> <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message only containing the user tag and zeroes/empty strings in all other fields.</p> </desc> </func> <func> - <name>p(integer() | string()) -> true | false | error | badarg</name> + <name since="OTP R15B01">p(integer() | string()) -> true | false | error | badarg</name> <fsummary>Trigger the user trace probe.</fsummary> <desc> <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer or string parameter in the first integer/string field.</p> </desc> </func> <func> - <name>p(integer() | string(), integer() | string()) -> true | false | error | badarg</name> + <name since="OTP R15B01">p(integer() | string(), integer() | string()) -> true | false | error | badarg</name> <fsummary>Trigger the user trace probe.</fsummary> <desc> <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters. I.e. <c>p(1,"Hello")</c> is ok, as is <c>p(1,1)</c> and <c>p("Hello","Again")</c>, but not <c>p("Hello",1)</c>.</p> </desc> </func> <func> - <name>p(integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name> + <name since="OTP R15B01">p(integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name> <fsummary>Trigger the user trace probe.</fsummary> <desc> <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> </desc> </func> <func> - <name>p(integer() | string(), integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name> + <name since="OTP R15B01">p(integer() | string(), integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name> <fsummary>Trigger the user trace probe.</fsummary> <desc> <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> </desc> </func> <func> - <name>p(integer(), integer() | string(), integer() | string(), integer() | string(), string()) -> true | false | error | badarg</name> + <name since="OTP R15B01">p(integer(), integer() | string(), integer() | string(), integer() | string(), string()) -> true | false | error | badarg</name> <fsummary>Trigger the user trace probe.</fsummary> <desc> <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> @@ -102,7 +102,7 @@ </desc> </func> <func> - <name>p(integer(), integer(), integer() | string(), integer() | string(), string(), string()) -> true | false | error | badarg</name> + <name since="OTP R15B01">p(integer(), integer(), integer() | string(), integer() | string(), string(), string()) -> true | false | error | badarg</name> <fsummary>Trigger the user trace probe.</fsummary> <desc> <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> @@ -110,7 +110,7 @@ </desc> </func> <func> - <name>p(integer(), integer(), integer(), integer() | string(), string(), string(), string()) -> true | false | error | badarg</name> + <name since="OTP R15B01">p(integer(), integer(), integer(), integer() | string(), string(), string(), string()) -> true | false | error | badarg</name> <fsummary>Trigger the user trace probe.</fsummary> <desc> <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p> @@ -118,14 +118,14 @@ </desc> </func> <func> - <name>p(integer(), integer(), integer(), integer(), string(), string(), string(), string()) -> true | false | error | badarg</name> + <name since="OTP R15B01">p(integer(), integer(), integer(), integer(), string(), string(), string(), string()) -> true | false | error | badarg</name> <fsummary>Trigger the user trace probe.</fsummary> <desc> <p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing all the integer()'s and string()'s provided, as well as any user tag set in the current process.</p> </desc> </func> <func> - <name>get_tag() -> binary() | undefined</name> + <name since="OTP R15B01">get_tag() -> binary() | undefined</name> <fsummary>Get the user tag set in the process.</fsummary> <desc> <p>This function returns the user tag set in the current @@ -134,7 +134,7 @@ </desc> </func> <func> - <name>get_tag() -> binary() | undefined</name> + <name since="OTP R15B01">get_tag() -> binary() | undefined</name> <fsummary>Get the user tag set in the process or sent to the process.</fsummary> <desc> <p>This function returns the user tag set in the current @@ -151,7 +151,7 @@ </func> <func> - <name>put_tag(Item) -> binary() | undefined </name> + <name since="OTP R15B01">put_tag(Item) -> binary() | undefined </name> <fsummary>Set the user tag of the current process.</fsummary> <type> <v>Item = iodata()</v> @@ -163,7 +163,7 @@ </desc> </func> <func> - <name>spread_tag(boolean()) -> TagData</name> + <name since="OTP R15B01">spread_tag(boolean()) -> TagData</name> <fsummary>Start or stop spreading dynamic trace user tags with the next message.</fsummary> <type> <v>TagData = opaque data that can be used as parameter to <seealso marker="#restore_tag/1">restore_tag/1</seealso></v> @@ -185,7 +185,7 @@ f() -> </desc> </func> <func> - <name>restore_tag(TagData) -> true</name> + <name since="OTP R15B01">restore_tag(TagData) -> true</name> <fsummary>Restore to a previous state of user tag spreading.</fsummary> <type> <v>TagData = opaque data returned by <seealso marker="#spread_tag/1">spread_tag/1</seealso></v> diff --git a/lib/runtime_tools/doc/src/erts_alloc_config.xml b/lib/runtime_tools/doc/src/erts_alloc_config.xml index ffc4ec5285..5bcce1b5e3 100644 --- a/lib/runtime_tools/doc/src/erts_alloc_config.xml +++ b/lib/runtime_tools/doc/src/erts_alloc_config.xml @@ -29,7 +29,7 @@ <rev>1</rev> <file>erts_alloc_config.sgml</file> </header> - <module>erts_alloc_config</module> + <module since="">erts_alloc_config</module> <modulesummary>Configuration tool for erts_alloc</modulesummary> <description> <note> @@ -136,7 +136,7 @@ </description> <funcs> <func> - <name>save_scenario() -> ok | {error, Error}</name> + <name since="">save_scenario() -> ok | {error, Error}</name> <fsummary>Saves information about current runtime scenario</fsummary> <type> <v>Error = term()</v> @@ -154,7 +154,7 @@ </desc> </func> <func> - <name>make_config() -> ok | {error, Error}</name> + <name since="">make_config() -> ok | {error, Error}</name> <fsummary>Creates an erts_alloc configuration</fsummary> <type> <v>Error = term()</v> @@ -165,7 +165,7 @@ </desc> </func> <func> - <name>make_config(FileNameOrIODev) -> ok | {error, Error}</name> + <name since="">make_config(FileNameOrIODev) -> ok | {error, Error}</name> <fsummary>Creates an erts_alloc configuration</fsummary> <type> <v>FileNameOrIODev = string() | io_device()</v> @@ -190,7 +190,7 @@ </desc> </func> <func> - <name>stop() -> ok | {error, Error}</name> + <name since="">stop() -> ok | {error, Error}</name> <fsummary></fsummary> <type> <v>Error = term()</v> diff --git a/lib/runtime_tools/doc/src/msacc.xml b/lib/runtime_tools/doc/src/msacc.xml index 129da3d230..ae089de8d0 100644 --- a/lib/runtime_tools/doc/src/msacc.xml +++ b/lib/runtime_tools/doc/src/msacc.xml @@ -31,7 +31,7 @@ <rev>A</rev> <file>msacc.xml</file> </header> - <module>msacc</module> + <module since="OTP 19.0">msacc</module> <modulesummary>Convenience functions for microstate accounting</modulesummary> <description> <p>This module implements some convenience functions for analyzing @@ -146,7 +146,7 @@ ok </datatypes> <funcs> <func> - <name name="available" arity="0"/> + <name name="available" arity="0" since="OTP 19.0"/> <fsummary>Check if microstate accounting is available</fsummary> <desc> <p>This function checks whether microstate accounting @@ -154,7 +154,7 @@ ok </desc> </func> <func> - <name name="start" arity="0"/> + <name name="start" arity="0" since="OTP 19.0"/> <fsummary>Start microstate accounting.</fsummary> <desc> <p>Start microstate accounting. Returns whether it was @@ -162,7 +162,7 @@ ok </desc> </func> <func> - <name name="start" arity="1"/> + <name name="start" arity="1" since="OTP 19.0"/> <fsummary>Start microstate accounting for a time.</fsummary> <desc> <p>Resets all counters and then starts microstate accounting @@ -170,7 +170,7 @@ ok </desc> </func> <func> - <name name="stop" arity="0"/> + <name name="stop" arity="0" since="OTP 19.0"/> <fsummary>Stop microstate accounting.</fsummary> <desc> <p>Stop microstate accounting. @@ -178,7 +178,7 @@ ok </desc> </func> <func> - <name name="reset" arity="0"/> + <name name="reset" arity="0" since="OTP 19.0"/> <fsummary>Reset microstate accounting counters</fsummary> <desc> <p>Reset microstate accounting counters. @@ -186,7 +186,7 @@ ok </desc> </func> <func> - <name name="print" arity="0"/> + <name name="print" arity="0" since="OTP 19.0"/> <fsummary>Print microstate statistics</fsummary> <desc> <p> @@ -199,7 +199,7 @@ ok </desc> </func> <func> - <name name="print" arity="1"/> + <name name="print" arity="1" since="OTP 19.0"/> <fsummary>Print microstate statistics</fsummary> <desc> <p>Print the given microstate statistics values to stdout. @@ -211,7 +211,7 @@ ok </desc> </func> <func> - <name name="print" arity="2"/> + <name name="print" arity="2" since="OTP 19.0"/> <fsummary>Print microstate statistics</fsummary> <desc> <p>Print the given microstate statistics values to standard out. @@ -234,7 +234,7 @@ ok </desc> </func> <func> - <name name="print" arity="3"/> + <name name="print" arity="3" since="OTP 19.0"/> <fsummary>Print microstate statistics</fsummary> <desc> <p>Print the given microstate statistics values to the given file @@ -243,7 +243,7 @@ ok </desc> </func> <func> - <name name="stats" arity="0"/> + <name name="stats" arity="0" since="OTP 19.0"/> <fsummary></fsummary> <desc> <p>Returns a runtime system independent version of the microstate @@ -254,7 +254,7 @@ ok </desc> </func> <func> - <name name="stats" arity="2" clause_i="1"/> + <name name="stats" arity="2" clause_i="1" since="OTP 19.0"/> <fsummary></fsummary> <desc> <p>Returns the system time for the given microstate statistics values. @@ -269,7 +269,7 @@ ok </desc> </func> <func> - <name name="stats" arity="2" clause_i="2"/> + <name name="stats" arity="2" clause_i="2" since="OTP 19.0"/> <fsummary></fsummary> <desc> <p>Returns fractions of real-time or run-time spent in the various @@ -277,7 +277,7 @@ ok </desc> </func> <func> - <name name="stats" arity="2" clause_i="3"/> + <name name="stats" arity="2" clause_i="3" since="OTP 19.0"/> <fsummary></fsummary> <desc> <p>Returns a list of microstate statistics values where the values @@ -285,7 +285,7 @@ ok </desc> </func> <func> - <name name="to_file" arity="1"/> + <name name="to_file" arity="1" since="OTP 19.0"/> <fsummary></fsummary> <desc> <p>Dumps the current microstate statistics counters to a file that can @@ -294,7 +294,7 @@ ok </desc> </func> <func> - <name name="from_file" arity="1"/> + <name name="from_file" arity="1" since="OTP 19.0"/> <fsummary></fsummary> <desc> <p>Read a file dump produced by <seealso marker="#to_file/1"> diff --git a/lib/runtime_tools/doc/src/scheduler.xml b/lib/runtime_tools/doc/src/scheduler.xml index dd8bf73bae..b033430183 100644 --- a/lib/runtime_tools/doc/src/scheduler.xml +++ b/lib/runtime_tools/doc/src/scheduler.xml @@ -32,7 +32,7 @@ <rev></rev> <file>scheduler.xml</file> </header> - <module>scheduler</module> + <module since="OTP 21.0">scheduler</module> <modulesummary>Measure scheduler utilization</modulesummary> <description> <p>This module contains utility functions for easier measurement and @@ -84,7 +84,7 @@ <funcs> <func> - <name name="sample" arity="0"/> + <name name="sample" arity="0" since="OTP 21.0"/> <fsummary>Get scheduler utilization sample.</fsummary> <desc> <p>Return a scheduler utilization sample for normal and dirty-cpu @@ -93,7 +93,7 @@ </func> <func> - <name name="sample_all" arity="0"/> + <name name="sample_all" arity="0" since="OTP 21.0"/> <fsummary>Get scheduler utilization sample.</fsummary> <desc> <p>Return a scheduler utilization sample for all schedulers, @@ -102,7 +102,7 @@ </func> <func> - <name name="utilization" arity="1" clause_i="1"/> + <name name="utilization" arity="1" clause_i="1" since="OTP 21.0"/> <fsummary>Measure scheduler utilizations during a period of time.</fsummary> <desc> <p>Measure utilization for normal and dirty-cpu schedulers during @@ -111,7 +111,7 @@ </func> <func> - <name name="utilization" arity="1" clause_i="2"/> + <name name="utilization" arity="1" clause_i="2" since="OTP 21.0"/> <fsummary>Measure scheduler utilizations since sample.</fsummary> <desc> <p>Calculate scheduler utilizations for the time interval from when @@ -121,7 +121,7 @@ </func> <func> - <name name="utilization" arity="2"/> + <name name="utilization" arity="2" since="OTP 21.0"/> <fsummary>Measure scheduler utilizations between two samples.</fsummary> <desc> <p>Calculates scheduler utilizations for the time interval between diff --git a/lib/runtime_tools/doc/src/system_information.xml b/lib/runtime_tools/doc/src/system_information.xml index 53dc595e64..a356b5c6f8 100644 --- a/lib/runtime_tools/doc/src/system_information.xml +++ b/lib/runtime_tools/doc/src/system_information.xml @@ -32,14 +32,14 @@ <rev></rev> <file>system_information.xml</file> </header> - <module>system_information</module> + <module since="OTP 17.0">system_information</module> <modulesummary>System Information</modulesummary> <description> <p></p> </description> <funcs> <func> - <name name="sanity_check" arity="0"/> + <name name="sanity_check" arity="0" since="OTP 17.0"/> <fsummary>Perform a sanity check</fsummary> <desc> <p>Performs a sanity check on the system. If no issues @@ -88,7 +88,7 @@ </desc> </func> <func> - <name name="to_file" arity="1"/> + <name name="to_file" arity="1" since="OTP 17.0"/> <fsummary>Write miscellaneous system information to file</fsummary> <desc><p>Writes miscellaneous system information to file. This information will typically be requested by the Erlang/OTP team diff --git a/lib/runtime_tools/examples/dist.systemtap b/lib/runtime_tools/examples/dist.systemtap index bb20d617e1..4102a5243c 100644 --- a/lib/runtime_tools/examples/dist.systemtap +++ b/lib/runtime_tools/examples/dist.systemtap @@ -19,18 +19,18 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ -probe process("beam").mark("dist-monitor") +probe process("beam.smp").mark("dist-monitor") { printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n", pid(), @@ -38,38 +38,38 @@ probe process("beam").mark("dist-monitor") user_string($arg5)); } -probe process("beam").mark("dist-port_busy") +probe process("beam.smp").mark("dist-port_busy") { printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); - blocked_procs[user_string($arg4)] = timestamp; + blocked_procs[user_string($arg4)] = local_clock_ns(); } -probe process("beam").mark("dist-port_busy") +probe process("beam.smp").mark("dist-port_busy") { printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); - blocked_procs[user_string($arg4)] = timestamp; + blocked_procs[user_string($arg4)] = local_clock_ns(); } -probe process("beam").mark("dist-output") +probe process("beam.smp").mark("dist-output") { printf("dist output: node %s, port %s, remote_node %s bytes %d\n", user_string($arg1), user_string($arg2), user_string($arg3), $arg4); } -probe process("beam").mark("dist-outputv") +probe process("beam.smp").mark("dist-outputv") { printf("port outputv: node %s, port %s, remote_node %s bytes %d\n", user_string($arg1), user_string($arg2), user_string($arg3), $arg4); } -probe process("beam").mark("process-scheduled") +probe process("beam.smp").mark("process-scheduled") { pidstr = user_string($arg1); if (pidstr in blocked_procs) { printf("blocked pid %s scheduled now, waited %d microseconds\n", - pidstr, (timestamp - blocked_procs[pidstr]) / 1000); + pidstr, (local_clock_ns() - blocked_procs[pidstr]) / 1000); delete blocked_procs[pidstr]; } } diff --git a/lib/runtime_tools/examples/driver1.systemtap b/lib/runtime_tools/examples/driver1.systemtap index e1ee8ecffc..f5bc28b42d 100644 --- a/lib/runtime_tools/examples/driver1.systemtap +++ b/lib/runtime_tools/examples/driver1.systemtap @@ -19,108 +19,102 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ -probe process("beam").mark("driver-init") +probe process("beam.smp").mark("driver__init") { printf("driver init name %s major %d minor %d flags %d\n", user_string($arg1), $arg2, $arg3, $arg4); } -probe process("beam").mark("driver-start") +probe process("beam.smp").mark("driver__start") { printf("driver start pid %s driver name %s port %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("driver-stop") +probe process("beam.smp").mark("driver__stop") { printf("driver stop pid %s driver name %s port %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("driver-finish") +probe process("beam.smp").mark("driver__finish") { printf("driver finish driver name %s\n", user_string($arg1)); } -probe process("beam").mark("driver-flush") +probe process("beam.smp").mark("driver__flush") { printf("driver flush pid %s port %s port name %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("driver-output") +probe process("beam.smp").mark("driver__output") { printf("driver output pid %s port %s port name %s bytes %d\n", user_string($arg1), user_string($arg2), user_string($arg3), $arg4); } -probe process("beam").mark("driver-outputv") +probe process("beam.smp").mark("driver__outputv") { printf("driver outputv pid %s port %s port name %s bytes %d\n", user_string($arg1), user_string($arg2), user_string($arg3), $arg4); } -probe process("beam").mark("driver-control") +probe process("beam.smp").mark("driver__control") { printf("driver control pid %s port %s port name %s command %d bytes %d\n", user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); } -probe process("beam").mark("driver-call") +probe process("beam.smp").mark("driver__call") { printf("driver call pid %s port %s port name %s command %d bytes %d\n", user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); } -probe process("beam").mark("driver-event") -{ - printf("driver event pid %s port %s port name %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-ready_input") +probe process("beam.smp").mark("driver__ready_input") { printf("driver ready_input pid %s port %s port name %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("driver-ready_output") +probe process("beam.smp").mark("driver__ready_output") { printf("driver ready_output pid %s port %s port name %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("driver-timeout") +probe process("beam.smp").mark("driver__timeout") { printf("driver timeout pid %s port %s port name %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("driver-ready_async") +probe process("beam.smp").mark("driver__ready_async") { printf("driver ready_async pid %s port %s port name %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("driver-process_exit") +probe process("beam.smp").mark("driver__process_exit") { printf("driver process_exit pid %s port %s port name %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("driver-stop_select") +probe process("beam.smp").mark("driver__stop_select") { printf("driver stop_select driver name %s\n", user_string($arg1)); } diff --git a/lib/runtime_tools/examples/function-calls.systemtap b/lib/runtime_tools/examples/function-calls.systemtap index 9c44b2d014..6bb173b3ec 100644 --- a/lib/runtime_tools/examples/function-calls.systemtap +++ b/lib/runtime_tools/examples/function-calls.systemtap @@ -18,51 +18,51 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ -probe process("beam").mark("local-function-entry") +probe process("beam.smp").mark("local-function-entry") { printf("pid %s enter (local) %s depth %d\n", user_string($arg1), user_string($arg2), $arg3); } -probe process("beam").mark("global-function-entry") +probe process("beam.smp").mark("global-function-entry") { printf("pid %s enter (global) %s depth %d\n", user_string($arg1), user_string($arg2), $arg3); } -probe process("beam").mark("function-return") +probe process("beam.smp").mark("function-return") { printf("pid %s return %s depth %d\n", user_string($arg1), user_string($arg2), $arg3); } -probe process("beam").mark("bif-entry") +probe process("beam.smp").mark("bif-entry") { printf("pid %s BIF entry mfa %s\n", user_string($arg1), user_string($arg2)); } -probe process("beam").mark("bif-return") +probe process("beam.smp").mark("bif-return") { printf("pid %s BIF return mfa %s\n", user_string($arg1), user_string($arg2)); } -probe process("beam").mark("nif-entry") +probe process("beam.smp").mark("nif-entry") { printf("pid %s NIF entry mfa %s\n", user_string($arg1), user_string($arg2)); } -probe process("beam").mark("nif-return") +probe process("beam.smp").mark("nif-return") { printf("pid %s NIF return mfa %s\n", user_string($arg1), user_string($arg2)); } diff --git a/lib/runtime_tools/examples/garbage-collection.systemtap b/lib/runtime_tools/examples/garbage-collection.systemtap index e414eea821..14f0d6851c 100644 --- a/lib/runtime_tools/examples/garbage-collection.systemtap +++ b/lib/runtime_tools/examples/garbage-collection.systemtap @@ -18,33 +18,33 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ -probe process("beam").mark("gc_major-start") +probe process("beam.smp").mark("gc_major-start") { printf("GC major start pid %s need %d words\n", user_string($arg1), $arg2); } -probe process("beam").mark("gc_minor-start") +probe process("beam.smp").mark("gc_minor-start") { printf("GC minor start pid %s need %d words\n", user_string($arg1), $arg2); } -probe process("beam").mark("gc_major-end") +probe process("beam.smp").mark("gc_major-end") { printf("GC major end pid %s reclaimed %d words\n", user_string($arg1), $arg2); } -probe process("beam").mark("gc_minor-start") +probe process("beam.smp").mark("gc_minor-start") { printf("GC minor end pid %s reclaimed %d words\n", user_string($arg1), $arg2); } diff --git a/lib/runtime_tools/examples/memory1.systemtap b/lib/runtime_tools/examples/memory1.systemtap index 04df4d64c4..2fdc5a796c 100644 --- a/lib/runtime_tools/examples/memory1.systemtap +++ b/lib/runtime_tools/examples/memory1.systemtap @@ -18,34 +18,34 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ -probe process("beam").mark("copy-struct") +probe process("beam.smp").mark("copy-struct") { printf("copy_struct %d bytes\n", $arg1); } -probe process("beam").mark("copy-object") +probe process("beam.smp").mark("copy-object") { printf("copy_object pid %s %d bytes\n", user_string($arg1), $arg2); } -probe process("beam").mark("process-heap_grow") +probe process("beam.smp").mark("process-heap_grow") { printf("proc heap grow pid %s %d -> %d bytes\n", user_string($arg1), $arg2, $arg3); } -probe process("beam").mark("process-heap_shrink") +probe process("beam.smp").mark("process-heap_shrink") { printf("proc heap shrink pid %s %d -> %d bytes\n", user_string($arg1), $arg2, $arg3); diff --git a/lib/runtime_tools/examples/messages.systemtap b/lib/runtime_tools/examples/messages.systemtap index f2ef56a22b..49b7f46d69 100644 --- a/lib/runtime_tools/examples/messages.systemtap +++ b/lib/runtime_tools/examples/messages.systemtap @@ -18,15 +18,15 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ probe begin @@ -38,7 +38,7 @@ probe begin printf("\n"); } -probe process("beam").mark("message-send") +probe process("beam.smp").mark("message-send") { if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { printf("send: %s -> %s: %d words\n", @@ -51,7 +51,7 @@ probe process("beam").mark("message-send") } } -probe process("beam").mark("message-send-remote") +probe process("beam.smp").mark("message-send-remote") { if ($arg5 == 0 && $arg6 == 0 && $arg7 == 0) { printf("send : %s -> %s %s: %d words\n", @@ -64,7 +64,7 @@ probe process("beam").mark("message-send-remote") } } -probe process("beam").mark("message-queued") +probe process("beam.smp").mark("message-queued") { if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { printf("queued: %s: %d words, queue len %d\n", user_string($arg1), $arg2, $arg3); @@ -75,7 +75,7 @@ probe process("beam").mark("message-queued") } } -probe process("beam").mark("message-receive") +probe process("beam.smp").mark("message-receive") { if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { printf("receive: %s: %d words, queue len %d\n", diff --git a/lib/runtime_tools/examples/port1.systemtap b/lib/runtime_tools/examples/port1.systemtap index f7ce03a65e..235581b0b1 100644 --- a/lib/runtime_tools/examples/port1.systemtap +++ b/lib/runtime_tools/examples/port1.systemtap @@ -18,15 +18,15 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ probe begin @@ -96,19 +96,19 @@ probe begin driver_map["udp_inet", 62] = "BINDX"; } -probe process("beam").mark("port-open") +probe process("beam.smp").mark("port-open") { printf("port open pid %s port name %s port %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("port-command") +probe process("beam.smp").mark("port-command") { printf("port command pid %s port %s port name %s command type %s\n", user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); } -probe process("beam").mark("port-control") +probe process("beam.smp").mark("port-control") { cmd = driver_map[user_string($arg3), $arg4]; cmd_str = (cmd == "") ? "unknown" : cmd; @@ -118,36 +118,36 @@ probe process("beam").mark("port-control") /* port-exit is fired as a result of port_close() or exit signal */ -probe process("beam").mark("port-exit") +probe process("beam.smp").mark("port-exit") { printf("port exit pid %s port %s port name %s reason %s\n", user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); } -probe process("beam").mark("port-connect") +probe process("beam.smp").mark("port-connect") { printf("port connect pid %s port %s port name %s new pid %s\n", user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); } -probe process("beam").mark("port-busy") +probe process("beam.smp").mark("port-busy") { printf("port busy %s\n", user_string($arg1)); } -probe process("beam").mark("port-not_busy") +probe process("beam.smp").mark("port-not_busy") { printf("port not busy %s\n", user_string($arg1)); } -probe process("beam").mark("aio_pool-add") +probe process("beam.smp").mark("aio_pool-add") { printf("async I/O pool add thread %d queue len %d\n", $arg1, $arg2); } -probe process("beam").mark("aio_pool-get") +probe process("beam.smp").mark("aio_pool-get") { printf("async I/O pool get thread %d queue len %d\n", $arg1, $arg2); } -global driver_map;
\ No newline at end of file +global driver_map; diff --git a/lib/runtime_tools/examples/process-scheduling.systemtap b/lib/runtime_tools/examples/process-scheduling.systemtap index b0b74257b3..231c589f64 100644 --- a/lib/runtime_tools/examples/process-scheduling.systemtap +++ b/lib/runtime_tools/examples/process-scheduling.systemtap @@ -18,28 +18,28 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ -probe process("beam").mark("process-scheduled") +probe process("beam.smp").mark("process-scheduled") { printf(" Schedule pid %s mfa %s\n", user_string($arg1), user_string($arg2)); } -probe process("beam").mark("process-unscheduled") +probe process("beam.smp").mark("process-unscheduled") { printf("Unschedule pid %s\n", user_string($arg1)); } -probe process("beam").mark("process-hibernate") +probe process("beam.smp").mark("process-hibernate") { printf(" Hibernate pid %s resume mfa %s\n", user_string($arg1), user_string($arg2)); diff --git a/lib/runtime_tools/examples/spawn-exit.systemtap b/lib/runtime_tools/examples/spawn-exit.systemtap index 89bca14496..a7b4a0a3ea 100644 --- a/lib/runtime_tools/examples/spawn-exit.systemtap +++ b/lib/runtime_tools/examples/spawn-exit.systemtap @@ -18,34 +18,34 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ -probe process("beam").mark("process-spawn") +probe process("beam.smp").mark("process-spawn") { printf("pid %s mfa %s\n", user_string($arg1), user_string($arg2)); } -probe process("beam").mark("process-exit") +probe process("beam.smp").mark("process-exit") { printf("pid %s reason %s\n", user_string($arg1), user_string($arg2)); } -probe process("beam").mark("process-exit_signal") +probe process("beam.smp").mark("process-exit_signal") { printf("sender %s -> pid %s reason %s\n", user_string($arg1), user_string($arg2), user_string($arg3)); } -probe process("beam").mark("process-exit_signal-remote") +probe process("beam.smp").mark("process-exit_signal-remote") { printf("sender %s -> node %s pid %s reason %s\n", user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); diff --git a/lib/runtime_tools/examples/user-probe-n.systemtap b/lib/runtime_tools/examples/user-probe-n.systemtap index 25f7503283..8a0a89c931 100644 --- a/lib/runtime_tools/examples/user-probe-n.systemtap +++ b/lib/runtime_tools/examples/user-probe-n.systemtap @@ -18,18 +18,19 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ -probe process("beam").mark("user_trace-n0") + +probe process("beam.smp").mark("user_trace-n0") { printf("probe n0: %s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", user_string($arg1), @@ -41,7 +42,7 @@ probe process("beam").mark("user_trace-n0") $arg9 == NULL ? "" : user_string($arg9)); } -probe process("beam").mark("user_trace-n1") +probe process("beam.smp").mark("user_trace-n1") { printf("probe n1: %s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", user_string($arg1), diff --git a/lib/runtime_tools/examples/user-probe.systemtap b/lib/runtime_tools/examples/user-probe.systemtap index 1777476e54..ce9dde30f8 100644 --- a/lib/runtime_tools/examples/user-probe.systemtap +++ b/lib/runtime_tools/examples/user-probe.systemtap @@ -18,23 +18,23 @@ * %CopyrightEnd% */ /* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note: This file assumes that you're using the SMP-enabled Erlang + * virtual machine, "beam.smp". * Note that other variations of the virtual machine also have * different names, e.g. the debug build of the SMP-enabled VM * is "beam.debug.smp". * * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. + * "beam.smp" with "beam.debug.smp" or the VM name appropriate + * to your environment. */ -probe process("beam").mark("user_trace-s1") +probe process("beam.smp").mark("user_trace-s1") { printf("%s\n", user_string($arg1)); } -probe process("beam").mark("user_trace-i4s4") +probe process("beam.smp").mark("user_trace-i4s4") { printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", user_string($arg1), diff --git a/lib/sasl/doc/src/alarm_handler.xml b/lib/sasl/doc/src/alarm_handler.xml index 4160757164..6e74f833cd 100644 --- a/lib/sasl/doc/src/alarm_handler.xml +++ b/lib/sasl/doc/src/alarm_handler.xml @@ -34,7 +34,7 @@ <rev>A</rev> <file>alarm_handler.sgml.t1</file> </header> - <module>alarm_handler</module> + <module since="">alarm_handler</module> <modulesummary>An Alarm Handling Process</modulesummary> <description> <p>The alarm handler process is a @@ -81,7 +81,7 @@ <funcs> <func> - <name>clear_alarm(AlarmId) -> void()</name> + <name since="">clear_alarm(AlarmId) -> void()</name> <fsummary>Clears the specified alarms.</fsummary> <type> <v>AlarmId = term()</v> @@ -94,7 +94,7 @@ </func> <func> - <name>get_alarms() -> [alarm()]</name> + <name since="">get_alarms() -> [alarm()]</name> <fsummary>Gets all active alarms.</fsummary> <desc> <p>Returns a list of all active alarms. This function can only @@ -103,7 +103,7 @@ </func> <func> - <name>set_alarm(alarm())</name> + <name since="">set_alarm(alarm())</name> <fsummary>Sets an alarm with an id.</fsummary> <type> <v>alarm() = {AlarmId, AlarmDescription}</v> diff --git a/lib/sasl/doc/src/rb.xml b/lib/sasl/doc/src/rb.xml index d5df4fd345..0ed7e91c11 100644 --- a/lib/sasl/doc/src/rb.xml +++ b/lib/sasl/doc/src/rb.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>rb.sgml</file> </header> - <module>rb</module> + <module since="">rb</module> <modulesummary>The Report Browser Tool</modulesummary> <description> <p>The Report Browser (RB) tool is used to browse and @@ -43,8 +43,8 @@ <funcs> <func> - <name>filter(Filters)</name> - <name>filter(Filters, Dates)</name> + <name since="OTP R13B04">filter(Filters)</name> + <name since="OTP R13B04">filter(Filters, Dates)</name> <fsummary>Filters reports and displays them on the screen.</fsummary> <type> <v>Filters = [filter()]</v> @@ -86,7 +86,7 @@ </func> <func> - <name>grep(RegExp)</name> + <name since="">grep(RegExp)</name> <fsummary>Searches the reports for a regular expression.</fsummary> <type> <v>RegExp = string() | {string(), Options} | re:mp() | {re:mp(), Options}</v> @@ -109,8 +109,8 @@ </func> <func> - <name>h()</name> - <name>help()</name> + <name since="">h()</name> + <name since="">help()</name> <fsummary>Displays help information.</fsummary> <desc> <p>Displays online help information.</p> @@ -118,8 +118,8 @@ </func> <func> - <name>list()</name> - <name>list(Type)</name> + <name since="">list()</name> + <name since="">list(Type)</name> <fsummary>Lists all reports.</fsummary> <type> <v>Type = type()</v> @@ -137,8 +137,8 @@ </func> <func> - <name>log_list()</name> - <name>log_list(Type)</name> + <name since="OTP R16B02">log_list()</name> + <name since="OTP R16B02">log_list(Type)</name> <fsummary>Logs report lists.</fsummary> <type> <v>Type = type()</v> @@ -157,8 +157,8 @@ </func> <func> - <name>rescan()</name> - <name>rescan(Options)</name> + <name since="">rescan()</name> + <name since="">rescan(Options)</name> <fsummary>Rescans the report directory.</fsummary> <type> <v>Options = [opt()]</v> @@ -171,8 +171,8 @@ </func> <func> - <name>show()</name> - <name>show(Report)</name> + <name since="">show()</name> + <name since="">show(Report)</name> <fsummary>Displays reports.</fsummary> <type> <v>Report = integer() | type()</v> @@ -186,8 +186,8 @@ </func> <func> - <name>start()</name> - <name>start(Options)</name> + <name since="">start()</name> + <name since="">start(Options)</name> <fsummary>Starts the <c>rb_server</c>.</fsummary> <type> <v>Options = [opt()]</v> @@ -256,7 +256,7 @@ </func> <func> - <name>start_log(FileName)</name> + <name since="">start_log(FileName)</name> <fsummary>Redirects all output to <c>FileName</c>.</fsummary> <type> <v>FileName = string() | atom() | pid()</v> @@ -268,7 +268,7 @@ </func> <func> - <name>stop()</name> + <name since="">stop()</name> <fsummary>Stops the <c>rb_server</c>.</fsummary> <desc> <p>Stops <c>rb_server</c>.</p> @@ -276,7 +276,7 @@ </func> <func> - <name>stop_log()</name> + <name since="">stop_log()</name> <fsummary>Stops logging to file.</fsummary> <desc> <p>Closes the log file. The output from the RB tool is diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml index 9ba276aeac..f8ee0306d8 100644 --- a/lib/sasl/doc/src/release_handler.xml +++ b/lib/sasl/doc/src/release_handler.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>release_handler</module> + <module since="">release_handler</module> <modulesummary>Unpacking and Installation of Release Packages</modulesummary> <description> <p>The <em>release handler</em> process belongs to the SASL @@ -168,8 +168,8 @@ <funcs> <func> - <name>check_install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name> - <name>check_install_release(Vsn,Opts) -> {ok, OtherVsn, Descr} | {error, Reason}</name> + <name since="">check_install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name> + <name since="OTP R14B04">check_install_release(Vsn,Opts) -> {ok, OtherVsn, Descr} | {error, Reason}</name> <fsummary>Checks installation of a release in the system.</fsummary> <type> <v>Vsn = OtherVsn = string()</v> @@ -202,7 +202,7 @@ </func> <func> - <name>create_RELEASES(Root, RelDir, RelFile, AppDirs) -> ok | {error, Reason}</name> + <name since="">create_RELEASES(Root, RelDir, RelFile, AppDirs) -> ok | {error, Reason}</name> <fsummary>Creates an initial <c>RELEASES</c> file.</fsummary> <type> <v>Root = RelDir = RelFile = string()</v> @@ -233,7 +233,7 @@ </func> <func> - <name>install_file(Vsn, File) -> ok | {error, Reason}</name> + <name since="">install_file(Vsn, File) -> ok | {error, Reason}</name> <fsummary>Installs a release file in the release structure.</fsummary> <type> <v>Vsn = File = string()</v> @@ -252,8 +252,8 @@ </func> <func> - <name>install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name> - <name>install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason}</name> + <name since="">install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name> + <name since="">install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason}</name> <fsummary>Installs a release in the system.</fsummary> <type> <v>Vsn = OtherVsn = string()</v> @@ -383,7 +383,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>make_permanent(Vsn) -> ok | {error, Reason}</name> + <name since="">make_permanent(Vsn) -> ok | {error, Reason}</name> <fsummary>Makes the specified release version permanent.</fsummary> <type> <v>Vsn = string()</v> @@ -396,7 +396,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>remove_release(Vsn) -> ok | {error, Reason}</name> + <name since="">remove_release(Vsn) -> ok | {error, Reason}</name> <fsummary>Removes a release from the system.</fsummary> <type> <v>Vsn = string()</v> @@ -410,7 +410,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>reboot_old_release(Vsn) -> ok | {error, Reason}</name> + <name since="">reboot_old_release(Vsn) -> ok | {error, Reason}</name> <fsummary>Reboots the system from an old release.</fsummary> <type> <v>Vsn = string()</v> @@ -425,7 +425,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>set_removed(Vsn) -> ok | {error, Reason}</name> + <name since="">set_removed(Vsn) -> ok | {error, Reason}</name> <fsummary>Marks a release as removed.</fsummary> <type> <v>Vsn = string()</v> @@ -440,7 +440,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>set_unpacked(RelFile, AppDirs) -> {ok, Vsn} | {error, Reason}</name> + <name since="">set_unpacked(RelFile, AppDirs) -> {ok, Vsn} | {error, Reason}</name> <fsummary>Marks a release as unpacked.</fsummary> <type> <v>RelFile = string()</v> @@ -466,7 +466,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>unpack_release(Name) -> {ok, Vsn} | {error, Reason}</name> + <name since="">unpack_release(Name) -> {ok, Vsn} | {error, Reason}</name> <fsummary>Unpacks a release package.</fsummary> <type> <v>Name = Vsn = string()</v> @@ -482,7 +482,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>which_releases() -> [{Name, Vsn, Apps, Status}]</name> + <name since="">which_releases() -> [{Name, Vsn, Apps, Status}]</name> <fsummary>Returns all known releases.</fsummary> <type> <v>Name = Vsn = string()</v> @@ -495,7 +495,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>which_releases(Status) -> [{Name, Vsn, Apps, Status}]</name> + <name since="OTP R15B">which_releases(Status) -> [{Name, Vsn, Apps, Status}]</name> <fsummary>Returns all known releases of a specific status.</fsummary> <type> <v>Name = Vsn = string()</v> @@ -537,7 +537,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <funcs> <func> - <name>upgrade_app(App, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> + <name since="">upgrade_app(App, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> <fsummary>Upgrades to a new application version.</fsummary> <type> <v>App = atom()</v> @@ -586,8 +586,8 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>downgrade_app(App, Dir) -></name> - <name>downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> + <name since="">downgrade_app(App, Dir) -></name> + <name since="">downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> <fsummary>Downgrades to a previous application version.</fsummary> <type> <v>App = atom()</v> @@ -633,7 +633,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>upgrade_script(App, Dir) -> {ok, NewVsn, Script}</name> + <name since="">upgrade_script(App, Dir) -> {ok, NewVsn, Script}</name> <fsummary>Finds an application upgrade script.</fsummary> <type> <v>App = atom()</v> @@ -671,7 +671,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>downgrade_script(App, OldVsn, Dir) -> {ok, Script}</name> + <name since="">downgrade_script(App, OldVsn, Dir) -> {ok, Script}</name> <fsummary>Finds an application downgrade script.</fsummary> <type> <v>App = atom()</v> @@ -710,7 +710,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </func> <func> - <name>eval_appup_script(App, ToVsn, ToDir, Script) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> + <name since="">eval_appup_script(App, ToVsn, ToDir, Script) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> <fsummary>Evaluates an application upgrade or downgrade script.</fsummary> <type> <v>App = atom()</v> diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml index 4842c732b1..6facb8ddae 100644 --- a/lib/sasl/doc/src/systools.xml +++ b/lib/sasl/doc/src/systools.xml @@ -30,7 +30,7 @@ <date></date> <rev></rev> </header> - <module>systools</module> + <module since="">systools</module> <modulesummary>A Set of Release Handling Tools</modulesummary> <description> <p>This module contains functions to generate boot scripts @@ -40,8 +40,8 @@ <funcs> <func> - <name>make_relup(Name, UpFrom, DownTo) -> Result</name> - <name>make_relup(Name, UpFrom, DownTo, [Opt]) -> Result</name> + <name since="">make_relup(Name, UpFrom, DownTo) -> Result</name> + <name since="">make_relup(Name, UpFrom, DownTo, [Opt]) -> Result</name> <fsummary>Generates a release upgrade file <c>relup</c>.</fsummary> <type> <v>Name = string()</v> @@ -136,8 +136,8 @@ </func> <func> - <name>make_script(Name) -> Result</name> - <name>make_script(Name, [Opt]) -> Result</name> + <name since="">make_script(Name) -> Result</name> + <name since="">make_script(Name, [Opt]) -> Result</name> <fsummary>Generates a boot script <c>.script/.boot</c>.</fsummary> <type> <v>Name = string()</v> @@ -263,8 +263,8 @@ </func> <func> - <name>make_tar(Name) -> Result</name> - <name>make_tar(Name, [Opt]) -> Result</name> + <name since="">make_tar(Name) -> Result</name> + <name since="">make_tar(Name, [Opt]) -> Result</name> <fsummary>Creates a release package.</fsummary> <type> <v>Name = string()</v> @@ -369,7 +369,7 @@ myapp-1/ebin/myapp.app </func> <func> - <name>script2boot(File) -> ok | error</name> + <name since="">script2boot(File) -> ok | error</name> <fsummary>Generates a binary version of a boot script.</fsummary> <type> <v>File = string()</v> diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml index 480ed2e825..d20f1a8d06 100644 --- a/lib/snmp/doc/src/snmp.xml +++ b/lib/snmp/doc/src/snmp.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp.xml</file> </header> - <module>snmp</module> + <module since="">snmp</module> <modulesummary>Interface functions to the SNMP toolkit</modulesummary> <description> <p>The module <c>snmp</c> contains interface functions to the @@ -56,7 +56,7 @@ <funcs> <func> - <name>config() -> ok | {error, Reason}</name> + <name since="">config() -> ok | {error, Reason}</name> <fsummary>Configure with a simple interactive tool</fsummary> <desc> <p>A simple interactive configuration tool. Simple @@ -78,8 +78,8 @@ </func> <func> - <name>start() -> ok | {error, Reason}</name> - <name>start(Type) -> ok | {error, Reason}</name> + <name since="">start() -> ok | {error, Reason}</name> + <name since="">start(Type) -> ok | {error, Reason}</name> <fsummary>Start the SNMP application</fsummary> <type> <v>Type = start_type()</v> @@ -93,8 +93,8 @@ </func> <func> - <name>start_agent() -> ok | {error, Reason}</name> - <name>start_agent(Type) -> ok | {error, Reason}</name> + <name since="">start_agent() -> ok | {error, Reason}</name> + <name since="">start_agent(Type) -> ok | {error, Reason}</name> <fsummary>Start the agent part of the SNMP application</fsummary> <type> <v>Type = start_type()</v> @@ -117,8 +117,8 @@ </func> <func> - <name>start_manager() -> ok | {error, Reason}</name> - <name>start_manager(Type) -> ok | {error, Reason}</name> + <name since="">start_manager() -> ok | {error, Reason}</name> + <name since="">start_manager(Type) -> ok | {error, Reason}</name> <fsummary>Start the manager part of the SNMP application</fsummary> <type> <v>Type = start_type()</v> @@ -141,7 +141,7 @@ </func> <func> - <name>date_and_time() -> DateAndTime</name> + <name since="">date_and_time() -> DateAndTime</name> <fsummary>Return the current date and time as an OCTET STRING</fsummary> <type> <v>DateAndTime = [int()]</v> @@ -155,7 +155,7 @@ </func> <func> - <name>date_and_time_to_universal_time_dst(DateAndTime) -> [utc()]</name> + <name since="">date_and_time_to_universal_time_dst(DateAndTime) -> [utc()]</name> <fsummary>Convert a DateAndTime value to a list of possible utc()</fsummary> <type> <v>DateAndTime = [int()]</v> @@ -171,8 +171,8 @@ </func> <func> - <name>date_and_time_to_string(DateAndTime) -> string()</name> - <name>date_and_time_to_string(DateAndTime, Validate) -> string()</name> + <name since="">date_and_time_to_string(DateAndTime) -> string()</name> + <name since="">date_and_time_to_string(DateAndTime, Validate) -> string()</name> <fsummary>Convert a DateAndTime value to a string</fsummary> <type> <v>DateAndTime = [int()]</v> @@ -194,7 +194,7 @@ </func> <func> - <name>date_and_time_to_string2(DateAndTime) -> string()</name> + <name since="">date_and_time_to_string2(DateAndTime) -> string()</name> <fsummary>Convert a DateAndTime value to a string</fsummary> <type> <v>DateAndTime = [int()]</v> @@ -210,7 +210,7 @@ </func> <func> - <name>local_time_to_date_and_time_dst(Local) -> [DateAndTime]</name> + <name since="">local_time_to_date_and_time_dst(Local) -> [DateAndTime]</name> <fsummary>Convert a Local time value to a list of possible DateAndTime(s)</fsummary> <type> <v>Local = {{Y,Mo,D},{H,M,S}}</v> @@ -226,7 +226,7 @@ </func> <func> - <name>universal_time_to_date_and_time(UTC) -> DateAndTime</name> + <name since="">universal_time_to_date_and_time(UTC) -> DateAndTime</name> <fsummary>Convert a UTC value to DateAndTime</fsummary> <type> <v>UTC = {{Y,Mo,D},{H,M,S}}</v> @@ -241,8 +241,8 @@ </func> <func> - <name>validate_date_and_time(DateAndTime) -> bool()</name> - <name>validate_date_and_time(DateAndTime, Validate) -> bool()</name> + <name since="">validate_date_and_time(DateAndTime) -> bool()</name> + <name since="">validate_date_and_time(DateAndTime, Validate) -> bool()</name> <fsummary>Check if a DateAndTime value is correct</fsummary> <type> <v>DateAndTime = term()</v> @@ -279,7 +279,7 @@ </func> <func> - <name>passwd2localized_key(Alg, Passwd, EngineID) -> Key</name> + <name since="">passwd2localized_key(Alg, Passwd, EngineID) -> Key</name> <fsummary>Generates an localized key</fsummary> <type> <v>Alg = algorithm()</v> @@ -298,7 +298,7 @@ </func> <func> - <name>octet_string_to_bits(S) -> Val</name> + <name since="">octet_string_to_bits(S) -> Val</name> <fsummary>Convert an OCTET-STRING to BITS</fsummary> <type> <v>Val = bits()</v> @@ -312,7 +312,7 @@ </func> <func> - <name>bits_to_octet_string(B) -> Val</name> + <name since="">bits_to_octet_string(B) -> Val</name> <fsummary>Convert an OCTET-STRING to BITS</fsummary> <type> <v>Val = octet_string()</v> @@ -326,7 +326,7 @@ </func> <func> - <name>read_mib(FileName) -> {ok, mib()} | {error, Reason}</name> + <name since="">read_mib(FileName) -> {ok, mib()} | {error, Reason}</name> <fsummary></fsummary> <type> <v>FileName = string()</v> @@ -341,10 +341,10 @@ </func> <func> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R16B03">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> @@ -412,10 +412,10 @@ </func> <func> - <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R16B03">log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> @@ -440,7 +440,7 @@ </func> <func> - <name>change_log_size(LogName, NewSize) -> ok | {error, Reason}</name> + <name since="">change_log_size(LogName, NewSize) -> ok | {error, Reason}</name> <fsummary>Change the size of the Audit Trail Log</fsummary> <type> <v>LogName = string()</v> @@ -463,8 +463,8 @@ </func> <func> - <name>print_version_info() -> void()</name> - <name>print_version_info(Prefix) -> void()</name> + <name since="">print_version_info() -> void()</name> + <name since="">print_version_info(Prefix) -> void()</name> <fsummary>Formatted print of result of the versions functions</fsummary> <type> <v>Prefix = string() | integer()</v> @@ -484,8 +484,8 @@ </func> <func> - <name>versions1() -> {ok, Info} | {error, Reason}</name> - <name>versions2() -> {ok, Info} | {error, Reason}</name> + <name since="">versions1() -> {ok, Info} | {error, Reason}</name> + <name since="">versions2() -> {ok, Info} | {error, Reason}</name> <fsummary>Retrieve various system and application info</fsummary> <type> <v>Info = [info()]</v> @@ -504,8 +504,8 @@ </func> <func> - <name>print_versions(VersionInfo) -> void()</name> - <name>print_versions(Prefix, VersionInfo) -> void()</name> + <name since="">print_versions(VersionInfo) -> void()</name> + <name since="">print_versions(Prefix, VersionInfo) -> void()</name> <fsummary>Formatted print of result of the versions functions</fsummary> <type> <v>VersionInfo = [version_info()]</v> @@ -527,7 +527,7 @@ </func> <func> - <name>enable_trace() -> void()</name> + <name since="">enable_trace() -> void()</name> <fsummary>Starts a tracer</fsummary> <!-- <type> @@ -543,7 +543,7 @@ </func> <func> - <name>disable_trace() -> void()</name> + <name since="">disable_trace() -> void()</name> <fsummary>Stop the tracer</fsummary> <!-- <type> @@ -558,7 +558,7 @@ </func> <func> - <name>set_trace(Targets) -> void()</name> + <name since="">set_trace(Targets) -> void()</name> <fsummary>Set trace target</fsummary> <type> <v>Targets = target() | targets()</v> @@ -582,7 +582,7 @@ </func> <func> - <name>reset_trace(Targets) -> void()</name> + <name since="">reset_trace(Targets) -> void()</name> <fsummary>Reset trace target</fsummary> <type> <v>Targets = module() | modules()</v> @@ -598,7 +598,7 @@ </func> <func> - <name>set_trace(Targets, Opts) -> void()</name> + <name since="">set_trace(Targets, Opts) -> void()</name> <fsummary>Set trace target</fsummary> <type> <v>Targets = target() | targets()</v> diff --git a/lib/snmp/doc/src/snmp_community_mib.xml b/lib/snmp/doc/src/snmp_community_mib.xml index 61dea05950..9800fb6c00 100644 --- a/lib/snmp/doc/src/snmp_community_mib.xml +++ b/lib/snmp/doc/src/snmp_community_mib.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_community_mib.xml</file> </header> - <module>snmp_community_mib</module> + <module since="">snmp_community_mib</module> <modulesummary>Instrumentation Functions for SNMP-COMMUNITY-MIB</modulesummary> <description> <p>The module <c>snmp_community_mib</c> implements the instrumentation @@ -45,7 +45,7 @@ <funcs> <func> - <name>configure(ConfDir) -> void()</name> + <name since="">configure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-COMMUNITY-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -77,7 +77,7 @@ </func> <func> - <name>reconfigure(ConfDir) -> void()</name> + <name since="">reconfigure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-COMMUNITY-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -108,8 +108,8 @@ </func> <func> - <name>add_community(Idx, CommName, SecName, CtxName, TransportTag) -> Ret</name> - <name>add_community(Idx, CommName, SecName, EngineId, CtxName, TransportTag) -> Ret</name> + <name since="">add_community(Idx, CommName, SecName, CtxName, TransportTag) -> Ret</name> + <name since="OTP R14B03">add_community(Idx, CommName, SecName, EngineId, CtxName, TransportTag) -> Ret</name> <fsummary>Added one community</fsummary> <type> <v>Idx = string()</v> @@ -132,7 +132,7 @@ </func> <func> - <name>delete_community(Key) -> Ret</name> + <name since="">delete_community(Key) -> Ret</name> <fsummary>Delete one community</fsummary> <type> <v>Key = term()</v> diff --git a/lib/snmp/doc/src/snmp_framework_mib.xml b/lib/snmp/doc/src/snmp_framework_mib.xml index 64e5df6ff5..d84327d4d5 100644 --- a/lib/snmp/doc/src/snmp_framework_mib.xml +++ b/lib/snmp/doc/src/snmp_framework_mib.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_framework_mib.xml</file> </header> - <module>snmp_framework_mib</module> + <module since="">snmp_framework_mib</module> <modulesummary>Instrumentation Functions for SNMP-FRAMEWORK-MIB</modulesummary> <description> <p>The module <c>snmp_framework_mib</c> implements instrumentation @@ -44,7 +44,7 @@ </description> <funcs> <func> - <name>configure(ConfDir) -> void()</name> + <name since="">configure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-FRAMEWORK-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -75,7 +75,7 @@ </desc> </func> <func> - <name>init() -> void()</name> + <name since="">init() -> void()</name> <fsummary>Initialize the SNMP-FRAMEWORK-MIB</fsummary> <desc> <p>This function is called from the supervisor at system @@ -88,7 +88,7 @@ </desc> </func> <func> - <name>add_context(Ctx) -> Ret</name> + <name since="">add_context(Ctx) -> Ret</name> <fsummary>Added one context</fsummary> <type> <v>Ctx = string()</v> @@ -103,7 +103,7 @@ </desc> </func> <func> - <name>delete_context(Key) -> Ret</name> + <name since="">delete_context(Key) -> Ret</name> <fsummary>Delete one context</fsummary> <type> <v>Key = term()</v> diff --git a/lib/snmp/doc/src/snmp_generic.xml b/lib/snmp/doc/src/snmp_generic.xml index 44762dec59..6fb714907c 100644 --- a/lib/snmp/doc/src/snmp_generic.xml +++ b/lib/snmp/doc/src/snmp_generic.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_generic.xml</file> </header> - <module>snmp_generic</module> + <module since="">snmp_generic</module> <modulesummary>Generic Functions for Implementing SNMP Objects in a Database</modulesummary> <description> <marker id="description"></marker> @@ -127,8 +127,8 @@ value() = term() <funcs> <func> - <name>get_status_col(Name, Cols)</name> - <name>get_status_col(NameDb, Cols) -> {ok, StatusVal} | false</name> + <name since="">get_status_col(Name, Cols)</name> + <name since="">get_status_col(NameDb, Cols) -> {ok, StatusVal} | false</name> <fsummary>Get the value of the status column from <c>Cols</c></fsummary> <type> <v>Name = name()</v> @@ -148,7 +148,7 @@ value() = term() </func> <func> - <name>get_index_types(Name)</name> + <name since="">get_index_types(Name)</name> <fsummary>Get the index types of <c>Name</c></fsummary> <type> <v>Name = name()</v> @@ -163,7 +163,7 @@ value() = term() </func> <func> - <name>get_table_info(Name, Item) -> table_info_result()</name> + <name since="OTP R15B01">get_table_info(Name, Item) -> table_info_result()</name> <fsummary>Get table info item of MIB table <c>Name</c></fsummary> <type> <v>Name = name()</v> @@ -187,8 +187,8 @@ value() = term() </func> <func> - <name>table_func(Op1, NameDb)</name> - <name>table_func(Op2, RowIndex, Cols, NameDb) -> Ret</name> + <name since="">table_func(Op1, NameDb)</name> + <name since="">table_func(Op2, RowIndex, Cols, NameDb) -> Ret</name> <fsummary>Default instrumentation function for tables</fsummary> <type> <v>Op1 = new | delete </v> @@ -232,7 +232,7 @@ value() = term() </func> <func> - <name>table_get_elements(NameDb, RowIndex, Cols) -> Values</name> + <name since="">table_get_elements(NameDb, RowIndex, Cols) -> Values</name> <fsummary>Get elements in a table row</fsummary> <type> <v>NameDb = name_db()</v> @@ -249,7 +249,7 @@ value() = term() </func> <func> - <name>table_next(NameDb, RestOid) -> RowIndex | endOfTable</name> + <name since="">table_next(NameDb, RestOid) -> RowIndex | endOfTable</name> <fsummary>Find the next row in the table</fsummary> <type> <v>NameDb = name_db()</v> @@ -265,7 +265,7 @@ value() = term() </func> <func> - <name>table_row_exists(NameDb, RowIndex) -> bool()</name> + <name since="">table_row_exists(NameDb, RowIndex) -> bool()</name> <fsummary>Check if a row in a table exists</fsummary> <type> <v>NameDb = name_db()</v> @@ -279,7 +279,7 @@ value() = term() </func> <func> - <name>table_set_elements(NameDb, RowIndex, Cols) -> bool()</name> + <name since="">table_set_elements(NameDb, RowIndex, Cols) -> bool()</name> <fsummary>Set elements in a table row</fsummary> <type> <v>NameDb = name_db()</v> @@ -300,8 +300,8 @@ value() = term() </func> <func> - <name>variable_func(Op1, NameDb)</name> - <name>variable_func(Op2, Val, NameDb) -> Ret</name> + <name since="">variable_func(Op1, NameDb)</name> + <name since="">variable_func(Op2, Val, NameDb) -> Ret</name> <fsummary>Default instrumentation function for tables</fsummary> <type> <v>Op1 = new | delete | get</v> @@ -325,7 +325,7 @@ value() = term() </func> <func> - <name>variable_get(NameDb) -> {value, Value} | undefined</name> + <name since="">variable_get(NameDb) -> {value, Value} | undefined</name> <fsummary>Get the value of a variable</fsummary> <type> <v>NameDb = name_db()</v> @@ -339,7 +339,7 @@ value() = term() </func> <func> - <name>variable_set(NameDb, NewVal) -> true | false</name> + <name since="">variable_set(NameDb, NewVal) -> true | false</name> <fsummary>Set a value for a variable</fsummary> <type> <v>NameDb = name_db()</v> diff --git a/lib/snmp/doc/src/snmp_index.xml b/lib/snmp/doc/src/snmp_index.xml index 646e9661a3..1497f4cf67 100644 --- a/lib/snmp/doc/src/snmp_index.xml +++ b/lib/snmp/doc/src/snmp_index.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_index.xml</file> </header> - <module>snmp_index</module> + <module since="">snmp_index</module> <modulesummary>Abstract Data Type for SNMP Indexing</modulesummary> <description> <p>The module <c>snmp_index</c> implements an Abstract @@ -159,7 +159,7 @@ get_next_pid(Oid, SnmpIndex) -> </section> <funcs> <func> - <name>delete(Index) -> true</name> + <name since="">delete(Index) -> true</name> <fsummary>Delete an index table</fsummary> <type> <v>Index = NewIndex = index()</v> @@ -173,7 +173,7 @@ get_next_pid(Oid, SnmpIndex) -> </desc> </func> <func> - <name>delete(Index, Key) -> NewIndex</name> + <name since="">delete(Index, Key) -> NewIndex</name> <fsummary>Delete an item from the index</fsummary> <type> <v>Index = NewIndex = index()</v> @@ -185,7 +185,7 @@ get_next_pid(Oid, SnmpIndex) -> </desc> </func> <func> - <name>get(Index, KeyOid) -> {ok, {KeyOid, Value}} | undefined</name> + <name since="">get(Index, KeyOid) -> {ok, {KeyOid, Value}} | undefined</name> <fsummary>Get the item with <c>KeyOid</c></fsummary> <type> <v>Index = index()</v> @@ -198,7 +198,7 @@ get_next_pid(Oid, SnmpIndex) -> </desc> </func> <func> - <name>get_last(Index) -> {ok, {KeyOid, Value}} | undefined</name> + <name since="">get_last(Index) -> {ok, {KeyOid, Value}} | undefined</name> <fsummary>Get the last item in the index structure</fsummary> <type> <v>Index = index()</v> @@ -210,7 +210,7 @@ get_next_pid(Oid, SnmpIndex) -> </desc> </func> <func> - <name>get_next(Index, KeyOid) -> {ok, {NextKeyOid, Value}} | undefined</name> + <name since="">get_next(Index, KeyOid) -> {ok, {NextKeyOid, Value}} | undefined</name> <fsummary>Get the next item</fsummary> <type> <v>Index = index()</v> @@ -224,7 +224,7 @@ get_next_pid(Oid, SnmpIndex) -> </desc> </func> <func> - <name>insert(Index, Key, Value) -> NewIndex</name> + <name since="">insert(Index, Key, Value) -> NewIndex</name> <fsummary>Insert an item into the index</fsummary> <type> <v>Index = NewIndex = index()</v> @@ -238,7 +238,7 @@ get_next_pid(Oid, SnmpIndex) -> </desc> </func> <func> - <name>key_to_oid(Index, Key) -> KeyOid</name> + <name since="">key_to_oid(Index, Key) -> KeyOid</name> <fsummary>Convert a key to an OBJECT IDENTIFIER</fsummary> <type> <v>Index = index()</v> @@ -250,7 +250,7 @@ get_next_pid(Oid, SnmpIndex) -> </desc> </func> <func> - <name>new(KeyTypes) -> Index</name> + <name since="">new(KeyTypes) -> Index</name> <fsummary>Create a new snmp index structure</fsummary> <type> <v>KeyTypes = key_types()</v> diff --git a/lib/snmp/doc/src/snmp_notification_mib.xml b/lib/snmp/doc/src/snmp_notification_mib.xml index d2e288ec15..9395edf155 100644 --- a/lib/snmp/doc/src/snmp_notification_mib.xml +++ b/lib/snmp/doc/src/snmp_notification_mib.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_notification_mib.xml</file> </header> - <module>snmp_notification_mib</module> + <module since="">snmp_notification_mib</module> <modulesummary>Instrumentation Functions for SNMP-NOTIFICATION-MIB</modulesummary> <description> <p>The module <c>snmp_notification_mib</c> implements the @@ -43,7 +43,7 @@ </description> <funcs> <func> - <name>configure(ConfDir) -> void()</name> + <name since="">configure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-NOTIFICATION-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -70,7 +70,7 @@ </desc> </func> <func> - <name>reconfigure(ConfDir) -> void()</name> + <name since="">reconfigure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-NOTIFICATION-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -98,7 +98,7 @@ </desc> </func> <func> - <name>add_notify(Name, Tag, Type) -> Ret</name> + <name since="">add_notify(Name, Tag, Type) -> Ret</name> <fsummary>Added one notify definition</fsummary> <type> <v>Name = string()</v> @@ -115,7 +115,7 @@ </desc> </func> <func> - <name>delete_notify(Key) -> Ret</name> + <name since="">delete_notify(Key) -> Ret</name> <fsummary>Delete one notify definition</fsummary> <type> <v>Key = term()</v> diff --git a/lib/snmp/doc/src/snmp_pdus.xml b/lib/snmp/doc/src/snmp_pdus.xml index 1d086e6f48..f403b6edf4 100644 --- a/lib/snmp/doc/src/snmp_pdus.xml +++ b/lib/snmp/doc/src/snmp_pdus.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_pdus.xml</file> </header> - <module>snmp_pdus</module> + <module since="">snmp_pdus</module> <modulesummary>Encode and Decode Functions for SNMP PDUs</modulesummary> <description> <p>RFC1157, RFC1905 and/or RFC2272 should be studied carefully @@ -55,7 +55,7 @@ </description> <funcs> <func> - <name>dec_message([byte()]) -> Message</name> + <name since="">dec_message([byte()]) -> Message</name> <fsummary>Decode an SNMP Message</fsummary> <type> <v>Message = #message</v> @@ -71,7 +71,7 @@ </desc> </func> <func> - <name>dec_message_only([byte()]) -> Message</name> + <name since="">dec_message_only([byte()]) -> Message</name> <fsummary>Decode an SNMP Message, but not the data part</fsummary> <type> <v>Message = #message</v> @@ -84,7 +84,7 @@ </desc> </func> <func> - <name>dec_pdu([byte()]) -> Pdu</name> + <name since="">dec_pdu([byte()]) -> Pdu</name> <fsummary>Decode an SNMP Pdu</fsummary> <type> <v>Pdu = #pdu</v> @@ -94,7 +94,7 @@ </desc> </func> <func> - <name>dec_scoped_pdu([byte()]) -> ScopedPdu</name> + <name since="">dec_scoped_pdu([byte()]) -> ScopedPdu</name> <fsummary>Decode an SNMP ScopedPdu</fsummary> <type> <v>ScopedPdu = #scoped_pdu</v> @@ -104,7 +104,7 @@ </desc> </func> <func> - <name>dec_scoped_pdu_data([byte()]) -> ScopedPduData</name> + <name since="">dec_scoped_pdu_data([byte()]) -> ScopedPduData</name> <fsummary>Decode an SNMP ScopedPduData</fsummary> <type> <v>ScopedPduData = #scoped_pdu | EncryptedPDU</v> @@ -116,7 +116,7 @@ </desc> </func> <func> - <name>dec_usm_security_parameters([byte()]) -> UsmSecParams</name> + <name since="">dec_usm_security_parameters([byte()]) -> UsmSecParams</name> <fsummary>Decode SNMP UsmSecurityParameters</fsummary> <type> <v>UsmSecParams = #usmSecurityParameters</v> @@ -126,7 +126,7 @@ </desc> </func> <func> - <name>enc_encrypted_scoped_pdu(EncryptedScopedPdu) -> [byte()]</name> + <name since="">enc_encrypted_scoped_pdu(EncryptedScopedPdu) -> [byte()]</name> <fsummary>Encode an encrypted SNMP scopedPDU</fsummary> <type> <v>EncryptedScopedPdu = [byte()]</v> @@ -142,7 +142,7 @@ </desc> </func> <func> - <name>enc_message(Message) -> [byte()]</name> + <name since="">enc_message(Message) -> [byte()]</name> <fsummary>Encode an SNMP Message</fsummary> <type> <v>Message = #message</v> @@ -152,7 +152,7 @@ </desc> </func> <func> - <name>enc_message_only(Message) -> [byte()]</name> + <name since="">enc_message_only(Message) -> [byte()]</name> <fsummary>Encode an SNMP Message, but not the data part</fsummary> <type> <v>Message = #message</v> @@ -166,7 +166,7 @@ </desc> </func> <func> - <name>enc_pdu(Pd) -> [byte()]</name> + <name since="">enc_pdu(Pd) -> [byte()]</name> <fsummary>Encode an SNMP Pdu</fsummary> <type> <v>Pdu = #pdu</v> @@ -176,7 +176,7 @@ </desc> </func> <func> - <name>enc_scoped_pdu(ScopedPdu) -> [byte()]</name> + <name since="">enc_scoped_pdu(ScopedPdu) -> [byte()]</name> <fsummary>Encode an SNMP scopedPDU</fsummary> <type> <v>ScopedPdu = #scoped_pdu</v> @@ -190,7 +190,7 @@ </desc> </func> <func> - <name>enc_usm_security_parameters(UsmSecParams) -> [byte()]</name> + <name since="">enc_usm_security_parameters(UsmSecParams) -> [byte()]</name> <fsummary>Encode SNMP UsmSecurityParameters</fsummary> <type> <v>UsmSecParams = #usmSecurityParameters</v> diff --git a/lib/snmp/doc/src/snmp_standard_mib.xml b/lib/snmp/doc/src/snmp_standard_mib.xml index 35efbba483..eb4e2fd097 100644 --- a/lib/snmp/doc/src/snmp_standard_mib.xml +++ b/lib/snmp/doc/src/snmp_standard_mib.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_standard_mib.xml</file> </header> - <module>snmp_standard_mib</module> + <module since="">snmp_standard_mib</module> <modulesummary>Instrumentation Functions for STANDARD-MIB and SNMPv2-MIB</modulesummary> <description> <p>The module <c>snmp_standard_mib</c> implements the instrumentation functions for the @@ -42,7 +42,7 @@ </description> <funcs> <func> - <name>configure(ConfDir) -> void()</name> + <name since="">configure(ConfDir) -> void()</name> <fsummary>Configure the STANDARD-MIB and SNMPv2-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -71,8 +71,8 @@ </desc> </func> <func> - <name>inc(Name) -> void()</name> - <name>inc(Name, N) -> void()</name> + <name since="">inc(Name) -> void()</name> + <name since="">inc(Name, N) -> void()</name> <fsummary>Increment a variable in the MIB</fsummary> <type> <v>Name = atom()</v> @@ -84,7 +84,7 @@ </desc> </func> <func> - <name>reconfigure(ConfDir) -> void()</name> + <name since="">reconfigure(ConfDir) -> void()</name> <fsummary>Configure the STANDARD-MIB and SNMPv2-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -114,14 +114,14 @@ </desc> </func> <func> - <name>reset() -> void()</name> + <name since="">reset() -> void()</name> <fsummary>Reset all <c>snmp</c>counters to 0</fsummary> <desc> <p>Resets all <c>snmp</c> counters to 0.</p> </desc> </func> <func> - <name>sys_up_time() -> Time</name> + <name since="">sys_up_time() -> Time</name> <fsummary>Get the system up time</fsummary> <type> <v>Time = int()</v> diff --git a/lib/snmp/doc/src/snmp_target_mib.xml b/lib/snmp/doc/src/snmp_target_mib.xml index c3bcd3b4e3..c46edb810d 100644 --- a/lib/snmp/doc/src/snmp_target_mib.xml +++ b/lib/snmp/doc/src/snmp_target_mib.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_target_mib.xml</file> </header> - <module>snmp_target_mib</module> + <module since="">snmp_target_mib</module> <modulesummary>Instrumentation Functions for SNMP-TARGET-MIB</modulesummary> <description> <p>The module <c>snmp_target_mib</c> implements the instrumentation @@ -57,7 +57,7 @@ <funcs> <func> - <name>configure(ConfDir) -> void()</name> + <name since="">configure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-TARGET-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -85,7 +85,7 @@ </func> <func> - <name>reconfigure(ConfDir) -> void()</name> + <name since="">reconfigure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-TARGET-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -113,7 +113,7 @@ </func> <func> - <name>set_target_engine_id(TargetAddrName, EngineId) -> boolean()</name> + <name since="">set_target_engine_id(TargetAddrName, EngineId) -> boolean()</name> <fsummary>Set the engine id for a targetAddr row.</fsummary> <type> <v>TargetAddrName = string()</v> @@ -130,7 +130,7 @@ </func> <func> - <name>add_addr(Name, Domain, Addr, Timeout, Retry, TagList, Params, EngineId, TMask, MMS) -> Ret</name> + <name since="">add_addr(Name, Domain, Addr, Timeout, Retry, TagList, Params, EngineId, TMask, MMS) -> Ret</name> <fsummary>Add one target address definition</fsummary> <type> <v>Name = string()</v> @@ -156,7 +156,7 @@ </func> <func> - <name>delete_addr(Key) -> Ret</name> + <name since="">delete_addr(Key) -> Ret</name> <fsummary>Delete one target address definition</fsummary> <type> <v>Key = term()</v> @@ -171,7 +171,7 @@ </func> <func> - <name>add_params(Name, MPModel, SecModel, SecName, SecLevel) -> Ret</name> + <name since="">add_params(Name, MPModel, SecModel, SecName, SecLevel) -> Ret</name> <fsummary>Add one target parameter definition</fsummary> <type> <v>Name = string()</v> @@ -191,7 +191,7 @@ </desc> </func> <func> - <name>delete_params(Key) -> Ret</name> + <name since="">delete_params(Key) -> Ret</name> <fsummary>Delete one target parameter definition</fsummary> <type> <v>Key = term()</v> diff --git a/lib/snmp/doc/src/snmp_user_based_sm_mib.xml b/lib/snmp/doc/src/snmp_user_based_sm_mib.xml index cc376ac118..6c2203ed22 100644 --- a/lib/snmp/doc/src/snmp_user_based_sm_mib.xml +++ b/lib/snmp/doc/src/snmp_user_based_sm_mib.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_user_based_sm_mib.xml</file> </header> - <module>snmp_user_based_sm_mib</module> + <module since="">snmp_user_based_sm_mib</module> <modulesummary>Instrumentation Functions for SNMP-USER-BASED-SM-MIB</modulesummary> <description> <p>The module <c>snmp_user_based_sm_mib</c> implements the instrumentation @@ -43,7 +43,7 @@ </description> <funcs> <func> - <name>configure(ConfDir) -> void()</name> + <name since="">configure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-USER-BASED-SM-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -72,7 +72,7 @@ </desc> </func> <func> - <name>reconfigure(ConfDir) -> void()</name> + <name since="">reconfigure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-USER-BASED-SM-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -103,7 +103,7 @@ </desc> </func> <func> - <name>add_user(EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> Ret</name> + <name since="">add_user(EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> Ret</name> <fsummary>Add one user</fsummary> <type> <v>EngineID = string()</v> @@ -130,7 +130,7 @@ </desc> </func> <func> - <name>delete_user(Key) -> Ret</name> + <name since="">delete_user(Key) -> Ret</name> <fsummary>Delete one user</fsummary> <type> <v>Key = term()</v> diff --git a/lib/snmp/doc/src/snmp_view_based_acm_mib.xml b/lib/snmp/doc/src/snmp_view_based_acm_mib.xml index fdad735e71..c5e98a3eb5 100644 --- a/lib/snmp/doc/src/snmp_view_based_acm_mib.xml +++ b/lib/snmp/doc/src/snmp_view_based_acm_mib.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmp_view_based_acm_mib.xml</file> </header> - <module>snmp_view_based_acm_mib</module> + <module since="">snmp_view_based_acm_mib</module> <modulesummary>Instrumentation Functions for SNMP-VIEW-BASED-ACM-MIB</modulesummary> <description> <p>The module <c>snmp_view_based_acm_mib</c> implements the instrumentation functions for the @@ -45,7 +45,7 @@ <funcs> <func> - <name>configure(ConfDir) -> void()</name> + <name since="">configure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-VIEW-BASED-ACM-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -71,7 +71,7 @@ </func> <func> - <name>reconfigure(ConfDir) -> void()</name> + <name since="">reconfigure(ConfDir) -> void()</name> <fsummary>Configure the SNMP-VIEW-BASED-ACM-MIB</fsummary> <type> <v>ConfDir = string()</v> @@ -104,7 +104,7 @@ </func> <func> - <name>add_sec2group(SecModel, SecName, GroupName) -> Ret</name> + <name since="">add_sec2group(SecModel, SecName, GroupName) -> Ret</name> <fsummary>Add one security to group definition</fsummary> <type> <v>SecModel = v1 | v2c | usm</v> @@ -124,7 +124,7 @@ </func> <func> - <name>delete_sec2group(Key) -> Ret</name> + <name since="">delete_sec2group(Key) -> Ret</name> <fsummary>Delete one security to group definition</fsummary> <type> <v>Key = term()</v> @@ -139,7 +139,7 @@ </func> <func> - <name>add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) -> Ret</name> + <name since="">add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) -> Ret</name> <fsummary>Add one access definition</fsummary> <type> <v>GroupName = string()</v> @@ -163,7 +163,7 @@ </func> <func> - <name>delete_access(Key) -> Ret</name> + <name since="">delete_access(Key) -> Ret</name> <fsummary>Delete one access definition</fsummary> <type> <v>Key = term()</v> @@ -178,7 +178,7 @@ </func> <func> - <name>add_view_tree_fam(ViewIndex, SubTree, Status, Mask) -> Ret</name> + <name since="">add_view_tree_fam(ViewIndex, SubTree, Status, Mask) -> Ret</name> <fsummary>Add one view tree family definition</fsummary> <type> <v>ViewIndex = integer()</v> @@ -199,7 +199,7 @@ </func> <func> - <name>delete_view_tree_fam(Key) -> Ret</name> + <name since="">delete_view_tree_fam(Key) -> Ret</name> <fsummary>Delete one view tree family definition</fsummary> <type> <v>Key = term()</v> diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml index b78f14da01..dc2f4e6d66 100644 --- a/lib/snmp/doc/src/snmpa.xml +++ b/lib/snmp/doc/src/snmpa.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa.xml</file> </header> - <module>snmpa</module> + <module since="">snmpa</module> <modulesummary>Interface Functions to the SNMP toolkit agent</modulesummary> <description> <p>The module <c>snmpa</c> contains interface functions to the @@ -77,7 +77,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} <funcs> <func> - <name>add_agent_caps(SysORID, SysORDescr) -> SysORIndex</name> + <name since="">add_agent_caps(SysORID, SysORDescr) -> SysORIndex</name> <fsummary>Add an AGENT-CAPABILITY definition to the agent</fsummary> <type> <v>SysORID = oid()</v> @@ -93,7 +93,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>del_agent_caps(SysORIndex) -> void()</name> + <name since="">del_agent_caps(SysORIndex) -> void()</name> <fsummary>Delete an AGENT-CAPABILITY definition from the agent</fsummary> <type> <v>SysORIndex = integer()</v> @@ -108,7 +108,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>get_agent_caps() -> [[SysORIndex, SysORID, SysORDescr, SysORUpTime]]</name> + <name since="">get_agent_caps() -> [[SysORIndex, SysORID, SysORDescr, SysORUpTime]]</name> <fsummary>Return all AGENT-CAPABILITY definitions in the agent</fsummary> <type> <v>SysORIndex = integer()</v> @@ -125,8 +125,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>get(Agent, Vars) -> Values | {error, Reason}</name> - <name>get(Agent, Vars, Context) -> Values | {error, Reason}</name> + <name since="">get(Agent, Vars) -> Values | {error, Reason}</name> + <name since="">get(Agent, Vars, Context) -> Values | {error, Reason}</name> <fsummary>Perform a get operation on the agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -150,8 +150,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>get_next(Agent, Vars) -> Values | {error, Reason}</name> - <name>get_next(Agent, Vars, Context) -> Values | {error, Reason}</name> + <name since="">get_next(Agent, Vars) -> Values | {error, Reason}</name> + <name since="">get_next(Agent, Vars, Context) -> Values | {error, Reason}</name> <fsummary>Perform a get-next operation on the agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -176,7 +176,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} <!-- <func> - <name>get_symbolic_store_db() -> Db</name> + <name since="">get_symbolic_store_db() -> Db</name> <fsummary>Retrieve the symbolic store database reference</fsummary> <type> <v>Db = term()</v> @@ -193,8 +193,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} --> <func> - <name>backup(BackupDir) -> ok | {error, Reason}</name> - <name>backup(Agent, BackupDir) -> ok | {error, Reason}</name> + <name since="">backup(BackupDir) -> ok | {error, Reason}</name> + <name since="">backup(Agent, BackupDir) -> ok | {error, Reason}</name> <fsummary>Backup agent data</fsummary> <type> <v>BackupDir = string()</v> @@ -216,8 +216,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </desc> </func> <func> - <name>info() -> [{Key, Value}]</name> - <name>info(Agent) -> [{Key, Value}]</name> + <name since="">info() -> [{Key, Value}]</name> + <name since="">info(Agent) -> [{Key, Value}]</name> <fsummary>Return information about the agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -236,7 +236,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>old_info_format(NewInfo) -> OldInfo</name> + <name since="">old_info_format(NewInfo) -> OldInfo</name> <fsummary>Return information about the agent</fsummary> <type> <v>OldInfo = NewInfo = [{Key, Value}]</v> @@ -251,8 +251,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>load_mib(Mib) -> ok | {error, Reason}</name> - <name>load_mib(Agent, Mib) -> ok | {error, Reason}</name> + <name since="OTP R16B02">load_mib(Mib) -> ok | {error, Reason}</name> + <name since="OTP R16B02">load_mib(Agent, Mib) -> ok | {error, Reason}</name> <fsummary>Load single MIB into the agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -273,10 +273,10 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>load_mibs(Mibs) -> ok | {error, Reason}</name> - <name>load_mibs(Mibs, Force) -> ok | {error, Reason}</name> - <name>load_mibs(Agent, Mibs) -> ok | {error, Reason}</name> - <name>load_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name> + <name since="">load_mibs(Mibs) -> ok | {error, Reason}</name> + <name since="">load_mibs(Mibs, Force) -> ok | {error, Reason}</name> + <name since="">load_mibs(Agent, Mibs) -> ok | {error, Reason}</name> + <name since="OTP R16B02">load_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name> <fsummary>Load MIBs into the agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -305,8 +305,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>unload_mib(Mib) -> ok | {error, Reason}</name> - <name>unload_mib(Agent, Mib) -> ok | {error, Reason}</name> + <name since="OTP R16B02">unload_mib(Mib) -> ok | {error, Reason}</name> + <name since="OTP R16B02">unload_mib(Agent, Mib) -> ok | {error, Reason}</name> <fsummary>Unload single MIB from the agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -321,10 +321,10 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>unload_mibs(Mibs) -> ok | {error, Reason}</name> - <name>unload_mibs(Mibs, Force) -> ok | {error, Reason}</name> - <name>unload_mibs(Agent, Mibs) -> ok | {error, Reason}</name> - <name>unload_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name> + <name since="">unload_mibs(Mibs) -> ok | {error, Reason}</name> + <name since="">unload_mibs(Mibs, Force) -> ok | {error, Reason}</name> + <name since="">unload_mibs(Agent, Mibs) -> ok | {error, Reason}</name> + <name since="OTP R16B02">unload_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name> <fsummary>Unload MIBs from the agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -347,8 +347,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>which_mibs() -> Mibs</name> - <name>which_mibs(Agent) -> Mibs</name> + <name since="">which_mibs() -> Mibs</name> + <name since="">which_mibs(Agent) -> Mibs</name> <fsummary>Get a list of all the loaded mibs</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -365,8 +365,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>whereis_mib(MibName) -> {ok, MibFile} | {error, Reason}</name> - <name>whereis_mib(Agent, MibName) -> {ok, MibFile} | {error, Reason}</name> + <name since="">whereis_mib(MibName) -> {ok, MibFile} | {error, Reason}</name> + <name since="">whereis_mib(Agent, MibName) -> {ok, MibFile} | {error, Reason}</name> <fsummary>Get the path to the mib file</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -385,10 +385,10 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>current_request_id() -> {value, RequestId} | false</name> - <name>current_context() -> {value, Context} | false</name> - <name>current_community() -> {value, Community} | false</name> - <name>current_address() -> {value, Address} | false</name> + <name since="">current_request_id() -> {value, RequestId} | false</name> + <name since="">current_context() -> {value, Context} | false</name> + <name since="">current_community() -> {value, Community} | false</name> + <name since="">current_address() -> {value, Address} | false</name> <fsummary>Get the request-id, context, community and address of the current request</fsummary> <type> <v>RequestId = integer()</v> @@ -409,8 +409,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>enum_to_int(Name, Enum) -> {value, Int} | false</name> - <name>enum_to_int(Db, Name, Enum) -> {value, Int} | false</name> + <name since="">enum_to_int(Name, Enum) -> {value, Int} | false</name> + <name since="">enum_to_int(Db, Name, Enum) -> {value, Int} | false</name> <fsummary>Convert an enum value to an integer</fsummary> <type> <v>Db = term()</v> @@ -435,8 +435,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>int_to_enum(Name, Int) -> {value, Enum} | false</name> - <name>int_to_enum(Db, Name, Int) -> {value, Enum} | false</name> + <name since="">int_to_enum(Name, Int) -> {value, Enum} | false</name> + <name since="">int_to_enum(Db, Name, Int) -> {value, Enum} | false</name> <fsummary>Convert an integer to an enum value</fsummary> <type> <v>Db = term()</v> @@ -461,8 +461,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>name_to_oid(Name) -> {value, oid()} | false</name> - <name>name_to_oid(Db, Name) -> {value, oid()} | false</name> + <name since="">name_to_oid(Name) -> {value, oid()} | false</name> + <name since="">name_to_oid(Db, Name) -> {value, oid()} | false</name> <fsummary>Convert a symbolic name to an OID</fsummary> <type> <v>Db = term()</v> @@ -482,8 +482,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>oid_to_name(OID) -> {value, Name} | false</name> - <name>oid_to_name(Db, OID) -> {value, Name} | false</name> + <name since="">oid_to_name(OID) -> {value, Name} | false</name> + <name since="">oid_to_name(Db, OID) -> {value, Name} | false</name> <fsummary>Convert an OID to a symbolic name</fsummary> <type> <v>Db = term()</v> @@ -503,7 +503,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>which_aliasnames() -> Result</name> + <name since="">which_aliasnames() -> Result</name> <fsummary>Get all alias-names known to the agent</fsummary> <type> <v>Result = [atom()]</v> @@ -515,7 +515,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>which_tables() -> Result</name> + <name since="">which_tables() -> Result</name> <fsummary>Get all tables known to the agent</fsummary> <type> <v>Result = [atom()]</v> @@ -528,7 +528,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>which_variables() -> Result</name> + <name since="">which_variables() -> Result</name> <fsummary>Get all variables known to the agent</fsummary> <type> <v>Result = [atom()]</v> @@ -541,7 +541,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>which_notifications() -> Result</name> + <name since="">which_notifications() -> Result</name> <fsummary>Get all notifications known to the agent</fsummary> <type> <v>Result = [{Name, MibName, Info}]</v> @@ -557,15 +557,15 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>log_to_txt(LogDir)</name> - <name>log_to_txt(LogDir, Block | Mibs)</name> - <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_txt(LogDir)</name> + <name since="">log_to_txt(LogDir, Block | Mibs)</name> + <name since="">log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R16B03">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> @@ -600,14 +600,14 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R16B03">log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> @@ -641,7 +641,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>change_log_size(NewSize) -> ok | {error, Reason}</name> + <name since="">change_log_size(NewSize) -> ok | {error, Reason}</name> <fsummary>Change the size of the Audit Trail Log</fsummary> <type> <v>NewSize = {MaxBytes, MaxFiles}</v> @@ -662,8 +662,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name> - <name>set_log_type(Agent, NewType) -> {ok, OldType} | {error, Reason}</name> + <name since="">set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name> + <name since="">set_log_type(Agent, NewType) -> {ok, OldType} | {error, Reason}</name> <fsummary>Change the type of the Audit Trail Log</fsummary> <type> <v>NewType = OldType = atl_type()</v> @@ -684,8 +684,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>mib_of(Oid) -> {ok, MibName} | {error, Reason}</name> - <name>mib_of(Agent, Oid) -> {ok, MibName} | {error, Reason}</name> + <name since="">mib_of(Oid) -> {ok, MibName} | {error, Reason}</name> + <name since="">mib_of(Agent, Oid) -> {ok, MibName} | {error, Reason}</name> <fsummary>Which mib an Oid belongs to</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -704,8 +704,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>me_of(Oid) -> {ok, Me} | {error, Reason}</name> - <name>me_of(Agent, Oid) -> {ok, Me} | {error, Reason}</name> + <name since="">me_of(Oid) -> {ok, Me} | {error, Reason}</name> + <name since="">me_of(Agent, Oid) -> {ok, Me} | {error, Reason}</name> <fsummary>Retrieve the mib-entry of an Oid</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -724,8 +724,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>invalidate_mibs_cache() -> void()</name> - <name>invalidate_mibs_cache(Agent) -> void()</name> + <name since="">invalidate_mibs_cache() -> void()</name> + <name since="">invalidate_mibs_cache(Agent) -> void()</name> <fsummary>Invalidate the mib server cache</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -739,8 +739,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>enable_mibs_cache() -> void()</name> - <name>enable_mibs_cache(Agent) -> void()</name> + <name since="">enable_mibs_cache() -> void()</name> + <name since="">enable_mibs_cache(Agent) -> void()</name> <fsummary>Enable the mib server cache</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -753,8 +753,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>disable_mibs_cache() -> void()</name> - <name>disable_mibs_cache(Agent) -> void()</name> + <name since="">disable_mibs_cache() -> void()</name> + <name since="">disable_mibs_cache(Agent) -> void()</name> <fsummary>Disable the mib server cache</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -767,8 +767,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>which_mibs_cache_size() -> void()</name> - <name>which_mibs_cache_size(Agent) -> void()</name> + <name since="OTP R14B">which_mibs_cache_size() -> void()</name> + <name since="OTP R14B">which_mibs_cache_size(Agent) -> void()</name> <fsummary>The size of the mib server cache</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -781,12 +781,12 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>gc_mibs_cache() -> {ok, NumElementsGCed} | {error, Reason}</name> - <name>gc_mibs_cache(Agent) -> {ok, NumElementsGCed} | {error, Reason}</name> - <name>gc_mibs_cache(Age) -> {ok, NumElementsGCed} | {error, Reason}</name> - <name>gc_mibs_cache(Agent, Age) -> {ok, NumElementsGCed} | {error, Reason}</name> - <name>gc_mibs_cache(Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name> - <name>gc_mibs_cache(Agent, Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name> + <name since="">gc_mibs_cache() -> {ok, NumElementsGCed} | {error, Reason}</name> + <name since="">gc_mibs_cache(Agent) -> {ok, NumElementsGCed} | {error, Reason}</name> + <name since="">gc_mibs_cache(Age) -> {ok, NumElementsGCed} | {error, Reason}</name> + <name since="">gc_mibs_cache(Agent, Age) -> {ok, NumElementsGCed} | {error, Reason}</name> + <name since="">gc_mibs_cache(Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name> + <name since="">gc_mibs_cache(Agent, Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name> <fsummary>Perform mib server cache gc</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -808,8 +808,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>enable_mibs_cache_autogc() -> void()</name> - <name>enable_mibs_cache_autogc(Agent) -> void()</name> + <name since="">enable_mibs_cache_autogc() -> void()</name> + <name since="">enable_mibs_cache_autogc(Agent) -> void()</name> <fsummary>Enable automatic gc of the mib server cache</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -822,8 +822,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>disable_mibs_cache_autogc() -> void()</name> - <name>disable_mibs_cache_autogc(Agent) -> void()</name> + <name since="">disable_mibs_cache_autogc() -> void()</name> + <name since="">disable_mibs_cache_autogc(Agent) -> void()</name> <fsummary>Disable automatic gc of the mib server cache</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -836,8 +836,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>update_mibs_cache_age(NewAge) -> ok | {error, Reason}</name> - <name>update_mibs_cache_age(Agent, NewAge) -> ok | {error, Reason}</name> + <name since="">update_mibs_cache_age(NewAge) -> ok | {error, Reason}</name> + <name since="">update_mibs_cache_age(Agent, NewAge) -> ok | {error, Reason}</name> <fsummary>Change the mib server cache age property</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -852,8 +852,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>update_mibs_cache_gclimit(NewGcLimit) -> ok | {error, Reason}</name> - <name>update_mibs_cache_gclimit(Agent, NewGCLimit) -> ok | {error, Reason}</name> + <name since="">update_mibs_cache_gclimit(NewGcLimit) -> ok | {error, Reason}</name> + <name since="">update_mibs_cache_gclimit(Agent, NewGCLimit) -> ok | {error, Reason}</name> <fsummary>Change the mib server cache gclimit property</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -869,10 +869,10 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} <func> - <name>register_notification_filter(Id, Mod, Data) -> ok | {error, Reason}</name> - <name>register_notification_filter(Agent, Id, Mod, Data) -> ok | {error, Reason}</name> - <name>register_notification_filter(Id, Mod, Data, Where) -> ok | {error, Reason}</name> - <name>register_notification_filter(Agent, Id, Mod, Data, Where) -> ok | {error, Reason}</name> + <name since="">register_notification_filter(Id, Mod, Data) -> ok | {error, Reason}</name> + <name since="">register_notification_filter(Agent, Id, Mod, Data) -> ok | {error, Reason}</name> + <name since="">register_notification_filter(Id, Mod, Data, Where) -> ok | {error, Reason}</name> + <name since="">register_notification_filter(Agent, Id, Mod, Data, Where) -> ok | {error, Reason}</name> <fsummary>Register a notification filter</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -897,8 +897,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>unregister_notification_filter(Id) -> ok | {error, Reason}</name> - <name>unregister_notification_filter(Agent, Id) -> ok | {error, Reason}</name> + <name since="">unregister_notification_filter(Id) -> ok | {error, Reason}</name> + <name since="">unregister_notification_filter(Agent, Id) -> ok | {error, Reason}</name> <fsummary>Unregister a notification filter</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -913,8 +913,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>which_notification_filter() -> Filters</name> - <name>which_notification_filter(Agent) -> Filters</name> + <name since="">which_notification_filter() -> Filters</name> + <name since="">which_notification_filter(Agent) -> Filters</name> <fsummary>Which notification filter</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -929,8 +929,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>set_request_limit(NewLimit) -> {ok, OldLimit} | {error, Reason}</name> - <name>set_request_limit(Agent, NewLimit) -> {ok, OldLimit} | {error, Reason}</name> + <name since="">set_request_limit(NewLimit) -> {ok, OldLimit} | {error, Reason}</name> + <name since="">set_request_limit(Agent, NewLimit) -> {ok, OldLimit} | {error, Reason}</name> <fsummary>Change the request limit</fsummary> <type> <v>NewLimit = OldLimit = infinity | integer() >= 0</v> @@ -950,7 +950,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </func> <func> - <name>register_subagent(Agent, SubTreeOid, Subagent) -> ok | {error, Reason}</name> + <name since="">register_subagent(Agent, SubTreeOid, Subagent) -> ok | {error, Reason}</name> <fsummary>Register a sub-agent under a sub-tree</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -975,7 +975,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). </func> <func> - <name>unregister_subagent(Agent, SubagentOidOrPid) -> ok | {ok, SubAgentPid} | {error, Reason}</name> + <name since="">unregister_subagent(Agent, SubagentOidOrPid) -> ok | {ok, SubAgentPid} | {error, Reason}</name> <fsummary>Unregister a sub-agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -992,7 +992,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). <func> - <name>send_notification2(Agent, Notification, SendOpts) -> void()</name> + <name since="OTP R14B03">send_notification2(Agent, Notification, SendOpts) -> void()</name> <fsummary>Send notification</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -1119,11 +1119,11 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). <func> - <name>send_notification(Agent, Notification, Receiver)</name> - <name>send_notification(Agent, Notification, Receiver, Varbinds)</name> - <name>send_notification(Agent, Notification, Receiver, NotifyName, Varbinds)</name> - <name>send_notification(Agent, Notification, Receiver, NotifyName, ContextName, Varbinds) -> void() </name> - <name>send_notification(Agent, Notification, Receiver, NotifyName, ContextName, Varbinds, LocalEngineID) -> void() </name> + <name since="">send_notification(Agent, Notification, Receiver)</name> + <name since="">send_notification(Agent, Notification, Receiver, Varbinds)</name> + <name since="">send_notification(Agent, Notification, Receiver, NotifyName, Varbinds)</name> + <name since="">send_notification(Agent, Notification, Receiver, NotifyName, ContextName, Varbinds) -> void() </name> + <name since="OTP R14B">send_notification(Agent, Notification, Receiver, NotifyName, ContextName, Varbinds, LocalEngineID) -> void() </name> <fsummary>Send a notification</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -1324,13 +1324,13 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). <func> - <name>discovery(TargetName, Notification) -> {ok, ManagerEngineID} | {error, Reason}</name> - <name>discovery(TargetName, Notification, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name> - <name>discovery(TargetName, Notification, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name> - <name>discovery(TargetName, Notification, ContextName, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name> - <name>discovery(TargetName, Notification, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name> - <name>discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name> - <name>discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler, ExtraInfo) -> {ok, ManagerEngineID} | {error, Reason}</name> + <name since="">discovery(TargetName, Notification) -> {ok, ManagerEngineID} | {error, Reason}</name> + <name since="">discovery(TargetName, Notification, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name> + <name since="">discovery(TargetName, Notification, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name> + <name since="">discovery(TargetName, Notification, ContextName, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name> + <name since="">discovery(TargetName, Notification, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name> + <name since="">discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name> + <name since="">discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler, ExtraInfo) -> {ok, ManagerEngineID} | {error, Reason}</name> <fsummary>Initiate the discovery process with a manager</fsummary> <type> <v>TargetName = string()</v> @@ -1379,7 +1379,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). </func> <func> - <name>convert_config(OldConfig) -> AgentConfig</name> + <name since="">convert_config(OldConfig) -> AgentConfig</name> <fsummary>Convert old snmp config to new agent config</fsummary> <type> <v>OldConfig = list()</v> @@ -1403,8 +1403,8 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). </func> <func> - <name>restart_worker() -> void()</name> - <name>restart_worker(Agent) -> void()</name> + <name since="">restart_worker() -> void()</name> + <name since="">restart_worker(Agent) -> void()</name> <fsummary>Restart the worker process of a multi-threaded agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -1419,8 +1419,8 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). </func> <func> - <name>restart_set_worker() -> void()</name> - <name>restart_set_worker(Agent) -> void()</name> + <name since="">restart_set_worker() -> void()</name> + <name since="">restart_set_worker(Agent) -> void()</name> <fsummary>Restart the set worker process of a multi-threaded agent</fsummary> <type> <v>Agent = pid() | atom()</v> @@ -1435,7 +1435,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). </func> <func> - <name>print_mib_info() -> void()</name> + <name since="OTP R14B02">print_mib_info() -> void()</name> <fsummary>Print mib info</fsummary> <desc> <p>Prints the content of all the (snmp) tables and variables @@ -1446,7 +1446,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). </func> <func> - <name>print_mib_tables() -> void()</name> + <name since="OTP R14B02">print_mib_tables() -> void()</name> <fsummary>Print mib tables</fsummary> <desc> <p>Prints the content of all the (snmp) tables @@ -1457,7 +1457,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). </func> <func> - <name>print_mib_variables() -> void()</name> + <name since="OTP R14B02">print_mib_variables() -> void()</name> <fsummary>Print mib variables</fsummary> <desc> <p>Prints the content of all the (snmp) variables @@ -1468,7 +1468,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). </func> <func> - <name>verbosity(Ref,Verbosity) -> void()</name> + <name since="">verbosity(Ref,Verbosity) -> void()</name> <fsummary>Assign a new verbosity for the process</fsummary> <type> <v>Ref = pid() | sub_agents | master_agent | net_if | mib_server | symbolic_store | note_store | local_db</v> diff --git a/lib/snmp/doc/src/snmpa_conf.xml b/lib/snmp/doc/src/snmpa_conf.xml index 503e44a6a2..4134a81c0c 100644 --- a/lib/snmp/doc/src/snmpa_conf.xml +++ b/lib/snmp/doc/src/snmpa_conf.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_conf.xml</file> </header> - <module>snmpa_conf</module> + <module since="">snmpa_conf</module> <modulesummary>Utility functions for handling the agent config files.</modulesummary> <description> <p>The module <c>snmpa_conf</c> contains various utility functions to @@ -92,7 +92,7 @@ word() = 0..65535 <funcs> <func> - <name>agent_entry(Tag, Val) -> agent_entry()</name> + <name since="">agent_entry(Tag, Val) -> agent_entry()</name> <fsummary>Create an agent entry</fsummary> <type> <v>Tag = intAgentTransports | intAgentUDPPort | intAgentMaxPacketSize | snmpEngineMaxMessageSize | snmpEngineID</v> @@ -111,8 +111,8 @@ word() = 0..65535 </func> <func> - <name>write_agent_config(Dir, Conf) -> ok</name> - <name>write_agent_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_agent_config(Dir, Conf) -> ok</name> + <name since="">write_agent_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the agent config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -134,7 +134,7 @@ word() = 0..65535 </func> <func> - <name>append_agent_config(Dir, Conf) -> ok</name> + <name since="">append_agent_config(Dir, Conf) -> ok</name> <fsummary>Append the agent config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -153,7 +153,7 @@ word() = 0..65535 </func> <func> - <name>read_agent_config(Dir) -> Conf</name> + <name since="">read_agent_config(Dir) -> Conf</name> <fsummary>Read the agent config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -172,7 +172,7 @@ word() = 0..65535 </func> <func> - <name>standard_entry(Tag, Val) -> standard_entry()</name> + <name since="">standard_entry(Tag, Val) -> standard_entry()</name> <fsummary>Create an standard entry</fsummary> <type> <v>Tag = sysDescr | sysObjectID | sysContact | sysName | sysLocation | sysServices | snmpEnableAuthenTraps</v> @@ -192,8 +192,8 @@ word() = 0..65535 </func> <func> - <name>write_standard_config(Dir, Conf) -> ok</name> - <name>write_standard_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_standard_config(Dir, Conf) -> ok</name> + <name since="">write_standard_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the agent standard config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -216,7 +216,7 @@ word() = 0..65535 </func> <func> - <name>append_standard_config(Dir, Conf) -> ok</name> + <name since="">append_standard_config(Dir, Conf) -> ok</name> <fsummary>Append the agent standard config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -236,7 +236,7 @@ word() = 0..65535 </func> <func> - <name>read_standard_config(Dir) -> Conf</name> + <name since="">read_standard_config(Dir) -> Conf</name> <fsummary>Read the agent standard config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -255,7 +255,7 @@ word() = 0..65535 </func> <func> - <name>context_entry(Context) -> context_entry()</name> + <name since="">context_entry(Context) -> context_entry()</name> <fsummary>Create an context entry</fsummary> <type> <v>Context = string()</v> @@ -273,8 +273,8 @@ word() = 0..65535 </func> <func> - <name>write_context_config(Dir, Conf) -> ok</name> - <name>write_context_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_context_config(Dir, Conf) -> ok</name> + <name since="">write_context_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the agent context(s) to the config file</fsummary> <type> <v>Dir = string()</v> @@ -297,7 +297,7 @@ word() = 0..65535 </func> <func> - <name>append_context_config(Dir, Conf) -> ok</name> + <name since="">append_context_config(Dir, Conf) -> ok</name> <fsummary>Append the agent context(s) to the config file</fsummary> <type> <v>Dir = string()</v> @@ -317,7 +317,7 @@ word() = 0..65535 </func> <func> - <name>read_context_config(Dir) -> Conf</name> + <name since="">read_context_config(Dir) -> Conf</name> <fsummary>Read the agent context config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -336,8 +336,8 @@ word() = 0..65535 </func> <func> - <name>community_entry(CommunityIndex) -> community_entry()</name> - <name>community_entry(CommunityIndex, CommunityName, SecName, ContextName, TransportTag) -> community_entry()</name> + <name since="">community_entry(CommunityIndex) -> community_entry()</name> + <name since="">community_entry(CommunityIndex, CommunityName, SecName, ContextName, TransportTag) -> community_entry()</name> <fsummary>Create an community entry</fsummary> <type> <v>CommunityIndex = string()</v> @@ -364,8 +364,8 @@ word() = 0..65535 </func> <func> - <name>write_community_config(Dir, Conf) -> ok</name> - <name>write_community_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_community_config(Dir, Conf) -> ok</name> + <name since="">write_community_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the agent community config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -388,7 +388,7 @@ word() = 0..65535 </func> <func> - <name>append_community_config(Dir, Conf) -> ok</name> + <name since="">append_community_config(Dir, Conf) -> ok</name> <fsummary>Append the agent community config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -408,7 +408,7 @@ word() = 0..65535 </func> <func> - <name>read_community_config(Dir) -> Conf</name> + <name since="">read_community_config(Dir) -> Conf</name> <fsummary>Read the agent community config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -427,10 +427,10 @@ word() = 0..65535 </func> <func> - <name>target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId) -> target_addr_entry()</name> - <name>target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId, TMask) -> target_addr_entry()</name> - <name>target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name> - <name>target_addr_entry(Name, Domain, Addr, Timeout, RetryCount, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name> + <name since="">target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId) -> target_addr_entry()</name> + <name since="OTP 17.3">target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId, TMask) -> target_addr_entry()</name> + <name since="">target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name> + <name since="">target_addr_entry(Name, Domain, Addr, Timeout, RetryCount, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name> <fsummary>Create an target_addr entry</fsummary> <type> <v>Name = string()</v> @@ -464,8 +464,8 @@ word() = 0..65535 </func> <func> - <name>write_target_addr_config(Dir, Conf) -> ok</name> - <name>write_target_addr_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_target_addr_config(Dir, Conf) -> ok</name> + <name since="">write_target_addr_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the agent target_addr config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -488,7 +488,7 @@ word() = 0..65535 </func> <func> - <name>append_target_addr_config(Dir, Conf) -> ok</name> + <name since="">append_target_addr_config(Dir, Conf) -> ok</name> <fsummary>Append the agent target_addr config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -508,7 +508,7 @@ word() = 0..65535 </func> <func> - <name>read_target_addr_config(Dir) -> Conf</name> + <name since="">read_target_addr_config(Dir) -> Conf</name> <fsummary>Read the agent target_addr config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -527,9 +527,9 @@ word() = 0..65535 </func> <func> - <name>target_params_entry(Name, Vsn) -> target_params_entry()</name> - <name>target_params_entry(Name, Vsn, SecName, SecLevel) -> target_params_entry()</name> - <name>target_params_entry(Name, MPModel, SecModel, SecName, SecLevel) -> target_params_entry()</name> + <name since="">target_params_entry(Name, Vsn) -> target_params_entry()</name> + <name since="">target_params_entry(Name, Vsn, SecName, SecLevel) -> target_params_entry()</name> + <name since="">target_params_entry(Name, MPModel, SecModel, SecName, SecLevel) -> target_params_entry()</name> <fsummary>Create an target_params entry</fsummary> <type> <v>Name = string()</v> @@ -564,8 +564,8 @@ word() = 0..65535 </func> <func> - <name>write_target_params_config(Dir, Conf) -> ok</name> - <name>write_target_params_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_target_params_config(Dir, Conf) -> ok</name> + <name since="">write_target_params_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the agent target_params config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -588,7 +588,7 @@ word() = 0..65535 </func> <func> - <name>append_target_params_config(Dir, Conf) -> ok</name> + <name since="">append_target_params_config(Dir, Conf) -> ok</name> <fsummary>Append the agent target_params config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -608,7 +608,7 @@ word() = 0..65535 </func> <func> - <name>read_target_params_config(Dir) -> Conf</name> + <name since="">read_target_params_config(Dir) -> Conf</name> <fsummary>Read the agent target_params config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -627,10 +627,10 @@ word() = 0..65535 </func> <func> - <name>vacm_s2g_entry(SecModel, SecName, GroupName) -> vacm_s2g_entry()</name> - <name>vacm_acc_entry(GroupName, Prefix, SecModel, SecLevel, Match, ReadView, WriteView, NotifyView) -> vacm_acc_entry()</name> - <name>vacm_vtf_entry(ViewIndex, ViewSubtree) -> vacm_vtf_entry()</name> - <name>vacm_vtf_entry(ViewIndex, ViewSubtree, ViewStatus, ViewMask) -> vacm_vtf_entry()</name> + <name since="">vacm_s2g_entry(SecModel, SecName, GroupName) -> vacm_s2g_entry()</name> + <name since="">vacm_acc_entry(GroupName, Prefix, SecModel, SecLevel, Match, ReadView, WriteView, NotifyView) -> vacm_acc_entry()</name> + <name since="">vacm_vtf_entry(ViewIndex, ViewSubtree) -> vacm_vtf_entry()</name> + <name since="">vacm_vtf_entry(ViewIndex, ViewSubtree, ViewStatus, ViewMask) -> vacm_vtf_entry()</name> <fsummary>Create an vacm entry</fsummary> <type> <v>SecModel = v1 | v2c | usm</v> @@ -665,8 +665,8 @@ word() = 0..65535 </func> <func> - <name>write_vacm_config(Dir, Conf) -> ok</name> - <name>write_vacm_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_vacm_config(Dir, Conf) -> ok</name> + <name since="">write_vacm_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the agent vacm config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -690,7 +690,7 @@ word() = 0..65535 </func> <func> - <name>append_vacm_config(Dir, Conf) -> ok</name> + <name since="">append_vacm_config(Dir, Conf) -> ok</name> <fsummary>Append the agent vacm config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -710,7 +710,7 @@ word() = 0..65535 </func> <func> - <name>read_vacm_config(Dir) -> Conf</name> + <name since="">read_vacm_config(Dir) -> Conf</name> <fsummary>Read the agent vacm config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -729,8 +729,8 @@ word() = 0..65535 </func> <func> - <name>usm_entry(EngineId) -> usm_entry()</name> - <name>usm_entry(EngineID, UserName, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> usm_entry()</name> + <name since="">usm_entry(EngineId) -> usm_entry()</name> + <name since="">usm_entry(EngineID, UserName, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> usm_entry()</name> <fsummary>Create an usm entry</fsummary> <type> <v>EngineId = string()</v> @@ -762,8 +762,8 @@ word() = 0..65535 </func> <func> - <name>write_usm_config(Dir, Conf) -> ok</name> - <name>write_usm_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_usm_config(Dir, Conf) -> ok</name> + <name since="">write_usm_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the agent usm config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -786,7 +786,7 @@ word() = 0..65535 </func> <func> - <name>append_usm_config(Dir, Conf) -> ok</name> + <name since="">append_usm_config(Dir, Conf) -> ok</name> <fsummary>Append the agent usm config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -805,7 +805,7 @@ word() = 0..65535 </func> <func> - <name>read_usm_config(Dir) -> Conf</name> + <name since="">read_usm_config(Dir) -> Conf</name> <fsummary>Read the agent usm config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -824,7 +824,7 @@ word() = 0..65535 </func> <func> - <name>notify_entry(Name, Tag, Type) -> notify_entry()</name> + <name since="">notify_entry(Name, Tag, Type) -> notify_entry()</name> <fsummary>Create an notify entry</fsummary> <type> <v>Name = string()</v> @@ -845,8 +845,8 @@ word() = 0..65535 </func> <func> - <name>write_notify_config(Dir, Conf) -> ok</name> - <name>write_notify_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_notify_config(Dir, Conf) -> ok</name> + <name since="">write_notify_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the agent notify config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -869,7 +869,7 @@ word() = 0..65535 </func> <func> - <name>append_notify_config(Dir, Conf) -> ok</name> + <name since="">append_notify_config(Dir, Conf) -> ok</name> <fsummary>Append the agent notify config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -889,7 +889,7 @@ word() = 0..65535 </func> <func> - <name>read_notify_config(Dir) -> Conf</name> + <name since="">read_notify_config(Dir) -> Conf</name> <fsummary>Read the agent notify config from the config file</fsummary> <type> <v>Dir = string()</v> diff --git a/lib/snmp/doc/src/snmpa_discovery_handler.xml b/lib/snmp/doc/src/snmpa_discovery_handler.xml index 0ea72a880c..21b8746c11 100644 --- a/lib/snmp/doc/src/snmpa_discovery_handler.xml +++ b/lib/snmp/doc/src/snmpa_discovery_handler.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_discovery_handler.xml</file> </header> - <module>snmpa_discovery_handler</module> + <module since="">snmpa_discovery_handler</module> <modulesummary>Behaviour module for the SNMP agent discovery handler.</modulesummary> <description> <p>This module defines the behaviour of the agent discovery @@ -51,7 +51,7 @@ <funcs> <func> - <name>stage1_finish(TargetName, ManagerEngineID, ExtraInfo) -> ignore | {ok, usm_entry() | [usm_entry()]} | {ok, usm_entry() | [usm_entry()], NewExtraInfo}</name> + <name since="">stage1_finish(TargetName, ManagerEngineID, ExtraInfo) -> ignore | {ok, usm_entry() | [usm_entry()]} | {ok, usm_entry() | [usm_entry()], NewExtraInfo}</name> <fsummary>Discovery stage 1 finish</fsummary> <type> <v>TargetName = string()</v> diff --git a/lib/snmp/doc/src/snmpa_error.xml b/lib/snmp/doc/src/snmpa_error.xml index 7cc4a3513d..6e6761b7a5 100644 --- a/lib/snmp/doc/src/snmpa_error.xml +++ b/lib/snmp/doc/src/snmpa_error.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_error.xml</file> </header> - <module>snmpa_error</module> + <module since="">snmpa_error</module> <modulesummary>Functions for Reporting SNMP Errors</modulesummary> <description> <marker id="desc"></marker> @@ -57,7 +57,7 @@ </description> <funcs> <func> - <name>config_err(Format, Args) -> void()</name> + <name since="">config_err(Format, Args) -> void()</name> <fsummary>Called if a configuration error occurs</fsummary> <type> <v>Format = string()</v> @@ -76,7 +76,7 @@ </func> <func> - <name>user_err(Format, Args) -> void()</name> + <name since="">user_err(Format, Args) -> void()</name> <fsummary>Called if a user related error occurs</fsummary> <type> <v>Format = string()</v> diff --git a/lib/snmp/doc/src/snmpa_error_io.xml b/lib/snmp/doc/src/snmpa_error_io.xml index bcb2688646..d78e09ff13 100644 --- a/lib/snmp/doc/src/snmpa_error_io.xml +++ b/lib/snmp/doc/src/snmpa_error_io.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_error_io.xml</file> </header> - <module>snmpa_error_io</module> + <module since="">snmpa_error_io</module> <modulesummary>Functions for Reporting SNMP Errors on stdio</modulesummary> <description> <p>The module <c>snmpa_error_io</c> implements the @@ -52,7 +52,7 @@ </description> <funcs> <func> - <name>config_err(Format, Args) -> void()</name> + <name since="">config_err(Format, Args) -> void()</name> <fsummary>Called if a configuration error occurs</fsummary> <type> <v>Format = string()</v> @@ -68,7 +68,7 @@ </desc> </func> <func> - <name>user_err(Format, Args) -> void()</name> + <name since="">user_err(Format, Args) -> void()</name> <fsummary>Called if a user related error occurs</fsummary> <type> <v>Format = string()</v> diff --git a/lib/snmp/doc/src/snmpa_error_logger.xml b/lib/snmp/doc/src/snmpa_error_logger.xml index 4feb2e7f32..b0565a6839 100644 --- a/lib/snmp/doc/src/snmpa_error_logger.xml +++ b/lib/snmp/doc/src/snmpa_error_logger.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_error_logger.xml</file> </header> - <module>snmpa_error_logger</module> + <module since="">snmpa_error_logger</module> <modulesummary>Functions for Reporting SNMP Errors through the error_logger</modulesummary> <description> <p>The module <c>snmpa_error_logger</c> implements the @@ -54,7 +54,7 @@ </description> <funcs> <func> - <name>config_err(Format, Args) -> void()</name> + <name since="">config_err(Format, Args) -> void()</name> <fsummary>Called if a configuration error occurs</fsummary> <type> <v>Format = string()</v> @@ -70,7 +70,7 @@ </desc> </func> <func> - <name>user_err(Format, Args) -> void()</name> + <name since="">user_err(Format, Args) -> void()</name> <fsummary>Called if a user related error occurs</fsummary> <type> <v>Format = string()</v> diff --git a/lib/snmp/doc/src/snmpa_error_report.xml b/lib/snmp/doc/src/snmpa_error_report.xml index 282d9b4e59..f08dc1df23 100644 --- a/lib/snmp/doc/src/snmpa_error_report.xml +++ b/lib/snmp/doc/src/snmpa_error_report.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_error_report.xml</file> </header> - <module>snmpa_error_report</module> + <module since="">snmpa_error_report</module> <modulesummary>Behaviour module for reporting SNMP agent errors</modulesummary> <description> <marker id="desc"></marker> @@ -52,7 +52,7 @@ </description> <funcs> <func> - <name>config_err(Format, Args) -> void()</name> + <name since="">config_err(Format, Args) -> void()</name> <fsummary>Called if a configuration error occurs</fsummary> <type> <v>Format = string()</v> @@ -68,7 +68,7 @@ </desc> </func> <func> - <name>user_err(Format, Args) -> void()</name> + <name since="">user_err(Format, Args) -> void()</name> <fsummary>Called if a user related error occurs</fsummary> <type> <v>Format = string()</v> diff --git a/lib/snmp/doc/src/snmpa_local_db.xml b/lib/snmp/doc/src/snmpa_local_db.xml index ac8d466ab3..229f22ab70 100644 --- a/lib/snmp/doc/src/snmpa_local_db.xml +++ b/lib/snmp/doc/src/snmpa_local_db.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_local_db.xml</file> </header> - <module>snmpa_local_db</module> + <module since="">snmpa_local_db</module> <modulesummary>The SNMP built-in database</modulesummary> <description> <p>The module <c>snmpa_local_db</c> contains functions for @@ -86,7 +86,7 @@ </section> <funcs> <func> - <name>dump() -> ok | {error, Reason}</name> + <name since="">dump() -> ok | {error, Reason}</name> <fsummary>Dump the database to disk</fsummary> <type> <v>Reason = term()</v> @@ -97,7 +97,7 @@ </desc> </func> <func> - <name>match(NameDb, Pattern)</name> + <name since="">match(NameDb, Pattern)</name> <fsummary>Perform a match on the table</fsummary> <desc> <p>Performs an ets/dets matching on the table. @@ -106,9 +106,9 @@ </desc> </func> <func> - <name>print()</name> - <name>print(TableName)</name> - <name>print(TableName, Db)</name> + <name since="">print()</name> + <name since="">print(TableName)</name> + <name since="">print(TableName, Db)</name> <fsummary>Print the database to screen</fsummary> <type> <v>TableName = atom()</v> @@ -124,7 +124,7 @@ </desc> </func> <func> - <name>table_create(NameDb) -> bool()</name> + <name since="">table_create(NameDb) -> bool()</name> <fsummary>Create a table</fsummary> <desc> <p>Creates a table. If the table already exist, the old copy @@ -135,7 +135,7 @@ </desc> </func> <func> - <name>table_create_row(NameDb, RowIndex, Row) -> bool()</name> + <name since="">table_create_row(NameDb, RowIndex, Row) -> bool()</name> <fsummary>Create a row in a table</fsummary> <type> <v>Row = {Val1, Val2, ..., ValN}</v> @@ -147,28 +147,28 @@ </desc> </func> <func> - <name>table_delete(NameDb) -> void()</name> + <name since="">table_delete(NameDb) -> void()</name> <fsummary>Delete a table</fsummary> <desc> <p>Deletes a table.</p> </desc> </func> <func> - <name>table_delete_row(NameDb, RowIndex) -> bool()</name> + <name since="">table_delete_row(NameDb, RowIndex) -> bool()</name> <fsummary>Delete the row in the table</fsummary> <desc> <p>Deletes the row in the table.</p> </desc> </func> <func> - <name>table_exists(NameDb) -> bool()</name> + <name since="">table_exists(NameDb) -> bool()</name> <fsummary>Check if a table exists</fsummary> <desc> <p>Checks if a table exists.</p> </desc> </func> <func> - <name>table_get_row(NameDb, RowIndex) -> Row | undefined</name> + <name since="">table_get_row(NameDb, RowIndex) -> Row | undefined</name> <fsummary>Get a row from the table</fsummary> <type> <v>Row = {Val1, Val2, ..., ValN}</v> diff --git a/lib/snmp/doc/src/snmpa_mib_data.xml b/lib/snmp/doc/src/snmpa_mib_data.xml index 1a73c9b634..b849a2826a 100644 --- a/lib/snmp/doc/src/snmpa_mib_data.xml +++ b/lib/snmp/doc/src/snmpa_mib_data.xml @@ -30,7 +30,7 @@ <file>snmpa_mib_data.xml</file> </header> - <module>snmpa_mib_data</module> + <module since="OTP R16B01">snmpa_mib_data</module> <modulesummary>Behaviour module for the SNMP agent mib-server data module.</modulesummary> <description> @@ -108,7 +108,7 @@ <funcs> <func> - <name>Module:new(Storage) -> State</name> + <name since="OTP R16B01">Module:new(Storage) -> State</name> <fsummary>Create new (mib-server) data instance</fsummary> <type> <v>Storage = mib_storage()</v> @@ -122,7 +122,7 @@ </func> <func> - <name>Module:close(State) -> void()</name> + <name since="OTP R16B01">Module:close(State) -> void()</name> <fsummary>Close the mib-server data instance</fsummary> <type> <v>State = term()</v> @@ -135,7 +135,7 @@ </func> <func> - <name>Module:sync(State) -> void()</name> + <name since="OTP R16B01">Module:sync(State) -> void()</name> <fsummary>Synchronize to disc</fsummary> <type> <v>State = term()</v> @@ -151,7 +151,7 @@ </func> <func> - <name>Module:load_mib(State, Filename, MeOverride, TeOverride) -> {ok, NewState} | {error, Reason}</name> + <name since="OTP R16B01">Module:load_mib(State, Filename, MeOverride, TeOverride) -> {ok, NewState} | {error, Reason}</name> <fsummary>Load a mib into the mib-server</fsummary> <type> <v>State = NewState = term()</v> @@ -172,7 +172,7 @@ </func> <func> - <name>Module:unload_mib(State, Filename) -> {ok, NewState} | {error, Reason}</name> + <name since="OTP R16B01">Module:unload_mib(State, Filename) -> {ok, NewState} | {error, Reason}</name> <fsummary>Unload mib from the mib-server</fsummary> <type> <v>State = NewState = term()</v> @@ -188,7 +188,7 @@ </func> <func> - <name>Module:lookup(State, Oid) -> Reply</name> + <name since="OTP R16B01">Module:lookup(State, Oid) -> Reply</name> <fsummary>Find the mib-entry corresponding to the Oid</fsummary> <type> <v>State = term()</v> @@ -210,7 +210,7 @@ </func> <func> - <name>Module:next(State, Oid, MibView) -> Reply</name> + <name since="OTP R16B01">Module:next(State, Oid, MibView) -> Reply</name> <fsummary>Finds the lexicographically next oid</fsummary> <type> <v>State = term()</v> @@ -227,7 +227,7 @@ </func> <func> - <name>Module:register_subagent(State, Oid, Pid) -> Reply</name> + <name since="OTP R16B01">Module:register_subagent(State, Oid, Pid) -> Reply</name> <fsummary>Register the subagent</fsummary> <type> <v>State = NewState = term()</v> @@ -245,7 +245,7 @@ </func> <func> - <name>Module:unregister_subagent(State, PidOrOid) -> Reply</name> + <name since="OTP R16B01">Module:unregister_subagent(State, PidOrOid) -> Reply</name> <fsummary>Unregister the subagent</fsummary> <type> <v>State = NewState = term()</v> @@ -266,7 +266,7 @@ </func> <func> - <name>Module:dump(State, Destination) -> Reply</name> + <name since="OTP R16B01">Module:dump(State, Destination) -> Reply</name> <fsummary>Unregister the subagent</fsummary> <type> <v>State = term()</v> @@ -284,7 +284,7 @@ </func> <func> - <name>Module:which_mib(State, Oid) -> Reply</name> + <name since="OTP R16B01">Module:which_mib(State, Oid) -> Reply</name> <fsummary>Retrieve the mib file for an oid()</fsummary> <type> <v>State = term()</v> @@ -301,7 +301,7 @@ </func> <func> - <name>Module:which_mibs(State) -> Reply</name> + <name since="OTP R16B01">Module:which_mibs(State) -> Reply</name> <fsummary>Retrieve all loaded mib files</fsummary> <type> <v>State = term()</v> @@ -317,7 +317,7 @@ </func> <func> - <name>Module:whereis_mib(State, MibName) -> Reply</name> + <name since="OTP R16B01">Module:whereis_mib(State, MibName) -> Reply</name> <fsummary>Retrieve the mib file for the mib</fsummary> <type> <v>State = term()</v> @@ -334,7 +334,7 @@ </func> <func> - <name>Module:info(State) -> Reply</name> + <name since="OTP R16B01">Module:info(State) -> Reply</name> <fsummary>Retrieve misc info for the mib data</fsummary> <type> <v>State = term()</v> @@ -352,7 +352,7 @@ </func> <func> - <name>Module:backup(State, BackupDir) -> Reply</name> + <name since="OTP R16B01">Module:backup(State, BackupDir) -> Reply</name> <fsummary>Perform a backup of the mib-server data</fsummary> <type> <v>State = term()</v> @@ -370,7 +370,7 @@ </func> <func> - <name>Module:code_change(Destination, Vsn, Extra, State) -> NewState</name> + <name since="OTP R16B01">Module:code_change(Destination, Vsn, Extra, State) -> NewState</name> <fsummary>Perform a code-change</fsummary> <type> <v>Destination = up | down</v> diff --git a/lib/snmp/doc/src/snmpa_mib_storage.xml b/lib/snmp/doc/src/snmpa_mib_storage.xml index 58ce2167ec..ee2b009e77 100644 --- a/lib/snmp/doc/src/snmpa_mib_storage.xml +++ b/lib/snmp/doc/src/snmpa_mib_storage.xml @@ -30,7 +30,7 @@ <file>snmpa_mib_storage.xml</file> </header> - <module>snmpa_mib_storage</module> + <module since="OTP R16B01">snmpa_mib_storage</module> <modulesummary> Behaviour module for the SNMP agent mib storage. </modulesummary> @@ -96,7 +96,7 @@ <funcs> <func> - <name>Module:open(Name, RecordName, Fields, Type, Options) -> {ok, TabId} | {error, Reason}</name> + <name since="OTP R16B01">Module:open(Name, RecordName, Fields, Type, Options) -> {ok, TabId} | {error, Reason}</name> <fsummary>Create new (mib-server) data instance</fsummary> <type> <v>Name = atom()</v> @@ -122,7 +122,7 @@ </func> <func> - <name>Module:close(TabId) -> void()</name> + <name since="OTP R16B01">Module:close(TabId) -> void()</name> <fsummary>Close the mib-storage table</fsummary> <type> <v>State = term()</v> @@ -135,7 +135,7 @@ </func> <func> - <name>Module:read(TabId, Key) -> false | {value, Record}</name> + <name since="OTP R16B01">Module:read(TabId, Key) -> false | {value, Record}</name> <fsummary>Read a record from the mib-storage table</fsummary> <type> <v>TabId = term()</v> @@ -150,7 +150,7 @@ </func> <func> - <name>Module:write(TabId, Record) -> ok | {error, Reason}</name> + <name since="OTP R16B01">Module:write(TabId, Record) -> ok | {error, Reason}</name> <fsummary>Write a record to the mib-storage table</fsummary> <type> <v>TabId = term()</v> @@ -165,7 +165,7 @@ </func> <func> - <name>Module:delete(TabId) -> void()</name> + <name since="OTP R16B01">Module:delete(TabId) -> void()</name> <fsummary>Delete an entire mib-storage table</fsummary> <type> <v>TabId = term()</v> @@ -178,7 +178,7 @@ </func> <func> - <name>Module:delete(TabId, Key) -> ok | {error, Reason}</name> + <name since="OTP R16B01">Module:delete(TabId, Key) -> ok | {error, Reason}</name> <fsummary>Delete a record from the mib-storage table</fsummary> <type> <v>TabId = term()</v> @@ -193,7 +193,7 @@ </func> <func> - <name>Module:match_object(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name> + <name since="OTP R16B01">Module:match_object(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name> <fsummary>Search the mib-storage table for record matching pattern</fsummary> <type> <v>TabId = term()</v> @@ -210,7 +210,7 @@ </func> <func> - <name>Module:match_delete(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name> + <name since="OTP R16B01">Module:match_delete(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name> <fsummary>Delete records in the mib-storage table matching pattern</fsummary> <type> <v>TabId = term()</v> @@ -228,7 +228,7 @@ </func> <func> - <name>Module:tab2list(TabId) -> Recs</name> + <name since="OTP R16B01">Module:tab2list(TabId) -> Recs</name> <fsummary>Return all records of the mib-storage table</fsummary> <type> <v>TabId = term()</v> @@ -243,7 +243,7 @@ </func> <func> - <name>Module:info(TabId) -> {ok, Info} | {error, Reason}</name> + <name since="OTP R16B01">Module:info(TabId) -> {ok, Info} | {error, Reason}</name> <fsummary>Returns information about the mib-storage table. </fsummary> <type> <v>TabId = term()</v> @@ -259,7 +259,7 @@ </func> <func> - <name>Module:sync(TabId) -> void()</name> + <name since="OTP R16B01">Module:sync(TabId) -> void()</name> <fsummary>Synchronize mib-storage table</fsummary> <type> <v>TabId = term()</v> @@ -273,7 +273,7 @@ </func> <func> - <name>Module:backup(TabId, BackupDir) -> ok | {error, Reason}</name> + <name since="OTP R16B01">Module:backup(TabId, BackupDir) -> ok | {error, Reason}</name> <fsummary>Perform a backup of the mib-storage table</fsummary> <type> <v>TabId = term()</v> diff --git a/lib/snmp/doc/src/snmpa_mpd.xml b/lib/snmp/doc/src/snmpa_mpd.xml index a39c087c20..d76a9c4a94 100644 --- a/lib/snmp/doc/src/snmpa_mpd.xml +++ b/lib/snmp/doc/src/snmpa_mpd.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_mpd.xml</file> </header> - <module>snmpa_mpd</module> + <module since="">snmpa_mpd</module> <modulesummary>Message Processing and Dispatch module for the SNMP agent</modulesummary> <description> <p>The module <c>snmpa_mpd</c> implements the version independent @@ -52,7 +52,7 @@ <funcs> <func> - <name>init(Vsns) -> mpd_state()</name> + <name since="">init(Vsns) -> mpd_state()</name> <fsummary>Initialize the MPD module</fsummary> <type> <v>Vsns = [Vsn]</v> @@ -70,8 +70,8 @@ </func> <func> - <name>process_packet(Packet, From, State, NoteStore, Log) -> {ok, Vsn, Pdu, PduMS, ACMData} | {discarded, Reason} | {discovery, DiscoPacket}</name> - <name>process_packet(Packet, From, LocalEngineID, State, NoteStore, Log) -> {ok, Vsn, Pdu, PduMS, ACMData} | {discarded, Reason} | {discovery, DiscoPacket}</name> + <name since="OTP 17.3">process_packet(Packet, From, State, NoteStore, Log) -> {ok, Vsn, Pdu, PduMS, ACMData} | {discarded, Reason} | {discovery, DiscoPacket}</name> + <name since="OTP R14B">process_packet(Packet, From, LocalEngineID, State, NoteStore, Log) -> {ok, Vsn, Pdu, PduMS, ACMData} | {discarded, Reason} | {discovery, DiscoPacket}</name> <fsummary>Process a packet received from the network</fsummary> <type> <v>Packet = binary()</v> @@ -108,8 +108,8 @@ </func> <func> - <name>generate_response_msg(Vsn, RePdu, Type, ACMData, Log) -> {ok, Packet} | {discarded, Reason}</name> - <name>generate_response_msg(Vsn, RePdu, Type, ACMData, LocalEngineID, Log) -> {ok, Packet} | {discarded, Reason}</name> + <name since="OTP R14B">generate_response_msg(Vsn, RePdu, Type, ACMData, Log) -> {ok, Packet} | {discarded, Reason}</name> + <name since="OTP R14B">generate_response_msg(Vsn, RePdu, Type, ACMData, LocalEngineID, Log) -> {ok, Packet} | {discarded, Reason}</name> <fsummary>Generate a response packet to be sent to the network</fsummary> <type> <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v> @@ -136,8 +136,8 @@ </func> <func> - <name>generate_msg(Vsn, NoteStore, Pdu, MsgData, To) -> {ok, PacketsAndAddresses} | {discarded, Reason}</name> - <name>generate_msg(Vsn, NoteStore, Pdu, MsgData, LocalEngineID, To) -> {ok, PacketsAndAddresses} | {discarded, Reason}</name> + <name since="OTP R14B">generate_msg(Vsn, NoteStore, Pdu, MsgData, To) -> {ok, PacketsAndAddresses} | {discarded, Reason}</name> + <name since="OTP R14B">generate_msg(Vsn, NoteStore, Pdu, MsgData, LocalEngineID, To) -> {ok, PacketsAndAddresses} | {discarded, Reason}</name> <fsummary>Generate a request message to be sent to the network</fsummary> <type> <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v> @@ -185,7 +185,7 @@ </func> <func> - <name>process_taddrs(TDests) -> Dests</name> + <name since="OTP 17.3">process_taddrs(TDests) -> Dests</name> <fsummary>Transform addresses from internal MIB format to a less internal </fsummary> <type> @@ -211,7 +211,7 @@ </func> <func> - <name>discarded_pdu(Variable) -> void()</name> + <name since="">discarded_pdu(Variable) -> void()</name> <fsummary>Increment the variable associated with a discarded pdu</fsummary> <type> <v>Variable = atom()</v> diff --git a/lib/snmp/doc/src/snmpa_network_interface.xml b/lib/snmp/doc/src/snmpa_network_interface.xml index d4d4989e90..3e79df11b1 100644 --- a/lib/snmp/doc/src/snmpa_network_interface.xml +++ b/lib/snmp/doc/src/snmpa_network_interface.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_network_interface.xml</file> </header> - <module>snmpa_network_interface</module> + <module since="">snmpa_network_interface</module> <modulesummary>Behaviour module for the SNMP agent network interface.</modulesummary> <description> <p>This module defines the behaviour of the agent network @@ -68,7 +68,7 @@ <funcs> <func> - <name>start_link(Prio, NoteStore, MasterAgent, Opts) -> {ok, Pid} | {error, Reason}</name> + <name since="">start_link(Prio, NoteStore, MasterAgent, Opts) -> {ok, Pid} | {error, Reason}</name> <fsummary>Start-link the network interface process</fsummary> <type> <v>Prio = priority()</v> @@ -93,7 +93,7 @@ </func> <func> - <name>info(Pid) -> [{Key, Value}]</name> + <name since="">info(Pid) -> [{Key, Value}]</name> <fsummary>Return information about the running network interface process</fsummary> <type> <v>Pid = pid()</v> @@ -112,7 +112,7 @@ </func> <func> - <name>verbosity(Pid, Verbosity) -> void()</name> + <name since="">verbosity(Pid, Verbosity) -> void()</name> <fsummary>Change the verbosity of a running network interface process</fsummary> <type> <v>Pid = pid()</v> @@ -126,7 +126,7 @@ </func> <func> - <name>get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name> + <name since="">get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name> <fsummary>Get the Audit Trail Log type</fsummary> <type> <v>Pid = pid()</v> @@ -147,7 +147,7 @@ </func> <func> - <name>set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name> + <name since="">set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name> <fsummary>Change the Audit Trail Log type</fsummary> <type> <v>Pid = pid()</v> diff --git a/lib/snmp/doc/src/snmpa_network_interface_filter.xml b/lib/snmp/doc/src/snmpa_network_interface_filter.xml index 7cd08f8935..02c7d291dd 100644 --- a/lib/snmp/doc/src/snmpa_network_interface_filter.xml +++ b/lib/snmp/doc/src/snmpa_network_interface_filter.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_network_interface_filter.xml</file> </header> - <module>snmpa_network_interface_filter</module> + <module since="">snmpa_network_interface_filter</module> <modulesummary>Behaviour module for the SNMP agent network-interface filter.</modulesummary> <description> <p>This module defines the behaviour of the agent network interface @@ -101,7 +101,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | </section> <funcs> <func> - <name>accept_recv(Domain, Addr) -> boolean()</name> + <name since="">accept_recv(Domain, Addr) -> boolean()</name> <fsummary>Shall the received message be accepted</fsummary> <type> <v>Domain = transportDomain()</v> @@ -116,7 +116,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | </desc> </func> <func> - <name>accept_send(Domain, Addr) -> boolean()</name> + <name since="">accept_send(Domain, Addr) -> boolean()</name> <fsummary>Shall the message be sent</fsummary> <type> <v>Domain = transportDomain()</v> @@ -131,7 +131,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | </desc> </func> <func> - <name>accept_recv_pdu(Domain, Addr, PduType) -> boolean()</name> + <name since="">accept_recv_pdu(Domain, Addr, PduType) -> boolean()</name> <fsummary>Shall the received pdu be accepted</fsummary> <type> <v>Domain = transportDomain()</v> @@ -148,7 +148,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | </desc> </func> <func> - <name>accept_send_pdu(Targets, PduType) -> Reply</name> + <name since="">accept_send_pdu(Targets, PduType) -> Reply</name> <fsummary>Shall the pdu be sent</fsummary> <type> <v>Targets = targets()</v> diff --git a/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml b/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml index cbae158544..5dad372710 100644 --- a/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml +++ b/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml @@ -34,7 +34,7 @@ <rev></rev> <file>snmpa_notification_delivery_info_receiver.xml</file> </header> - <module>snmpa_notification_delivery_info_receiver</module> + <module since="">snmpa_notification_delivery_info_receiver</module> <modulesummary> Behaviour module for the SNMP agent notification delivery information receiver. @@ -76,7 +76,7 @@ <funcs> <func> - <name>delivery_targets(Tag, Targets, Extra) -> void()</name> + <name since="">delivery_targets(Tag, Targets, Extra) -> void()</name> <fsummary>Inform about target addresses</fsummary> <type> <v>Tag = term()</v> @@ -97,7 +97,7 @@ </func> <func> - <name>delivery_info(Tag, Target, DeliveryResult, Extra) -> void()</name> + <name since="">delivery_info(Tag, Target, DeliveryResult, Extra) -> void()</name> <fsummary>Inform about delivery result</fsummary> <type> <v>Tag = term()</v> diff --git a/lib/snmp/doc/src/snmpa_notification_filter.xml b/lib/snmp/doc/src/snmpa_notification_filter.xml index 0f16ba4440..902412ccc5 100644 --- a/lib/snmp/doc/src/snmpa_notification_filter.xml +++ b/lib/snmp/doc/src/snmpa_notification_filter.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_notification_filter.xml</file> </header> - <module>snmpa_notification_filter</module> + <module since="">snmpa_notification_filter</module> <modulesummary>Behaviour module for the SNMP agent notification filters.</modulesummary> <description> <p>This module defines the behaviour of the agent notification @@ -51,7 +51,7 @@ </description> <funcs> <func> - <name>handle_notification(Notif, Data) -> Reply</name> + <name since="">handle_notification(Notif, Data) -> Reply</name> <fsummary>Handle a notification</fsummary> <type> <v>Reply = send | {send, NewNotif} | dont_send</v> diff --git a/lib/snmp/doc/src/snmpa_supervisor.xml b/lib/snmp/doc/src/snmpa_supervisor.xml index 86c6fbc350..e11cde390f 100644 --- a/lib/snmp/doc/src/snmpa_supervisor.xml +++ b/lib/snmp/doc/src/snmpa_supervisor.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpa_supervisor.xml</file> </header> - <module>snmpa_supervisor</module> + <module since="">snmpa_supervisor</module> <modulesummary>A supervisor for the SNMP agent Processes</modulesummary> <description> <p>This is the top supervisor for the agent part of the SNMP @@ -42,7 +42,7 @@ </description> <funcs> <func> - <name>start_sub_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name> + <name since="">start_sub_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name> <fsummary>Start the SNMP supervisor for sub-agents only</fsummary> <type> <v>Opts = [opt()]</v> @@ -60,7 +60,7 @@ </desc> </func> <func> - <name>start_master_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name> + <name since="">start_master_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name> <fsummary>Start the SNMP supervisor for all agents</fsummary> <type> <v>Opts = [opt()]</v> @@ -82,7 +82,7 @@ </desc> </func> <func> - <name>start_sub_agent(ParentAgent,Subtree,Mibs) -> {ok, pid()} | {error, Reason}</name> + <name since="">start_sub_agent(ParentAgent,Subtree,Mibs) -> {ok, pid()} | {error, Reason}</name> <fsummary>Start a sub-agent</fsummary> <type> <v>ParentAgent = pid()</v> @@ -99,7 +99,7 @@ </desc> </func> <func> - <name>stop_sub_agent(SubAgent) -> ok | no_such_child</name> + <name since="">stop_sub_agent(SubAgent) -> ok | no_such_child</name> <fsummary>Stop a sub-agent</fsummary> <type> <v>SubAgent = pid()</v> diff --git a/lib/snmp/doc/src/snmpc.xml b/lib/snmp/doc/src/snmpc.xml index aba51bb500..b22b32a133 100644 --- a/lib/snmp/doc/src/snmpc.xml +++ b/lib/snmp/doc/src/snmpc.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpc.xml</file> </header> - <module>snmpc</module> + <module since="">snmpc</module> <modulesummary>Interface Functions to the SNMP toolkit MIB compiler</modulesummary> <description> <p>The module <c>snmpc</c> contains interface functions to the @@ -43,8 +43,8 @@ <funcs> <func> - <name>compile(File)</name> - <name>compile(File, Options) -> {ok, BinFileName} | {error, Reason}</name> + <name since="">compile(File)</name> + <name since="">compile(File, Options) -> {ok, BinFileName} | {error, Reason}</name> <fsummary>Compile the specified MIB</fsummary> <type> <v>File = string()</v> @@ -236,7 +236,7 @@ </func> <func> - <name>is_consistent(Mibs) -> ok | {error, Reason}</name> + <name since="">is_consistent(Mibs) -> ok | {error, Reason}</name> <fsummary>Check for OID conflicts between MIBs</fsummary> <type> <v>Mibs = [MibName]</v> @@ -252,7 +252,7 @@ </func> <func> - <name>mib_to_hrl(MibName) -> ok | {error, Reason}</name> + <name since="">mib_to_hrl(MibName) -> ok | {error, Reason}</name> <fsummary>Generate constants for the objects in the MIB</fsummary> <type> <v>MibName = string()</v> diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml index be4cd58a1a..c45df98ee0 100644 --- a/lib/snmp/doc/src/snmpm.xml +++ b/lib/snmp/doc/src/snmpm.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpm.xml</file> </header> - <module>snmpm</module> + <module since="">snmpm</module> <modulesummary>Interface functions to the SNMP toolkit manager</modulesummary> <description> <p>The module <c>snmpm</c> contains interface functions to the @@ -77,7 +77,7 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv </section> <funcs> <func> - <name>monitor() -> Ref</name> + <name since="">monitor() -> Ref</name> <fsummary>Monitor the snmp manager</fsummary> <type> <v>Ref = reference()</v> @@ -92,7 +92,7 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>demonitor(Ref) -> void()</name> + <name since="">demonitor(Ref) -> void()</name> <fsummary>Turn off monitoring of the snmp manager</fsummary> <type> <v>Ref = reference()</v> @@ -105,7 +105,7 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>notify_started(Timeout) -> Pid</name> + <name since="">notify_started(Timeout) -> Pid</name> <fsummary>Request to be notified when manager started</fsummary> <type> <v>Timeout = integer()</v> @@ -148,7 +148,7 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>cancel_notify_started(Pid) -> void()</name> + <name since="">cancel_notify_started(Pid) -> void()</name> <fsummary>Cancel request to be notified when manager started</fsummary> <type> <v>Pid = pid()</v> @@ -161,8 +161,8 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>register_user(Id, Module, Data) -> ok | {error, Reason}</name> - <name>register_user(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name> + <name since="">register_user(Id, Module, Data) -> ok | {error, Reason}</name> + <name since="">register_user(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name> <fsummary>Register a user of the manager</fsummary> <type> <v>Id = term()</v> @@ -204,8 +204,8 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>register_user_monitor(Id, Module, Data) -> ok | {error, Reason}</name> - <name>register_user_monitor(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name> + <name since="">register_user_monitor(Id, Module, Data) -> ok | {error, Reason}</name> + <name since="">register_user_monitor(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name> <fsummary>Register a monitored user of the manager</fsummary> <type> <v>Id = term()</v> @@ -252,7 +252,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>unregister_user(Id) -> ok | {error, Reason}</name> + <name since="">unregister_user(Id) -> ok | {error, Reason}</name> <fsummary>Unregister the user</fsummary> <type> <v>Id = term()</v> @@ -265,7 +265,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>which_users() -> Users</name> + <name since="">which_users() -> Users</name> <fsummary>Get a list of all users</fsummary> <type> <v>Users = [UserId]</v> @@ -279,7 +279,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>register_agent(UserId, TargetName, Config) -> ok | {error, Reason}</name> + <name since="">register_agent(UserId, TargetName, Config) -> ok | {error, Reason}</name> <fsummary>Register this agent</fsummary> <type> <v>UserId = term()</v> @@ -325,7 +325,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>unregister_agent(UserId, TargetName) -> ok | {error, Reason}</name> + <name since="">unregister_agent(UserId, TargetName) -> ok | {error, Reason}</name> <fsummary>Unregister the user</fsummary> <type> <v>UserId = term()</v> @@ -339,7 +339,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>agent_info(TargetName, Item) -> {ok, Val} | {error, Reason}</name> + <name since="">agent_info(TargetName, Item) -> {ok, Val} | {error, Reason}</name> <fsummary>Retrieve agent config</fsummary> <type> <v>TargetName = target_name()</v> @@ -354,8 +354,8 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>update_agent_info(UserId, TargetName, Info) -> ok | {error, Reason}</name> - <name>update_agent_info(UserId, TargetName, Item, Val) -> ok | {error, Reason}</name> + <name since="OTP R14B04">update_agent_info(UserId, TargetName, Info) -> ok | {error, Reason}</name> + <name since="">update_agent_info(UserId, TargetName, Item, Val) -> ok | {error, Reason}</name> <fsummary>Update agent config</fsummary> <type> <v>UserId = term()</v> @@ -379,8 +379,8 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>which_agents() -> Agents</name> - <name>which_agents(UserId) -> Agents</name> + <name since="">which_agents() -> Agents</name> + <name since="">which_agents(UserId) -> Agents</name> <fsummary>List the registered agents</fsummary> <type> <v>UserId = term()</v> @@ -396,7 +396,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv </func> <func> - <name>register_usm_user(EngineID, UserName, Conf) -> ok | {error, Reason}</name> + <name since="">register_usm_user(EngineID, UserName, Conf) -> ok | {error, Reason}</name> <fsummary>Register this USM user</fsummary> <type> <v>EngineID = string()</v> @@ -427,7 +427,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>unregister_usm_user(EngineID, UserName) -> ok | {error, Reason}</name> + <name since="">unregister_usm_user(EngineID, UserName) -> ok | {error, Reason}</name> <fsummary>Unregister this USM user</fsummary> <type> <v>EngineID = string()</v> @@ -442,7 +442,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>usm_user_info(EngineID, UserName, Item) -> {ok, Val} | {error, Reason}</name> + <name since="">usm_user_info(EngineID, UserName, Item) -> {ok, Val} | {error, Reason}</name> <fsummary>Retrieve usm user config</fsummary> <type> <v>EngineID = string()</v> @@ -458,7 +458,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>update_usm_user_info(EngineID, UserName, Item, Val) -> ok | {error, Reason}</name> + <name since="">update_usm_user_info(EngineID, UserName, Item, Val) -> ok | {error, Reason}</name> <fsummary>Update agent config</fsummary> <type> <v>EngineID = string()</v> @@ -475,7 +475,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>which_usm_users() -> UsmUsers</name> + <name since="">which_usm_users() -> UsmUsers</name> <fsummary>List all the registered usm users</fsummary> <type> <v>UsmUsers = [{EngineID,UserName}]</v> @@ -490,7 +490,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>which_usm_users(EngineID) -> UsmUsers</name> + <name since="">which_usm_users(EngineID) -> UsmUsers</name> <fsummary>List the registered usm users</fsummary> <type> <v>UsmUsers = [UserName]</v> @@ -505,8 +505,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>sync_get2(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get2(UserId, TargetName, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="OTP R14B03">sync_get2(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="OTP R14B03">sync_get2(UserId, TargetName, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> <fsummary>Synchronous <c>get-request</c></fsummary> <type> <v>UserId = term()</v> @@ -559,11 +559,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>sync_get(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> <fsummary>Synchronous <c>get-request</c></fsummary> <type> <v>UserId = term()</v> @@ -605,8 +605,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>async_get2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get2(UserId, TargetName, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name> + <name since="OTP R14B03">async_get2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name> + <name since="OTP R14B03">async_get2(UserId, TargetName, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name> <fsummary>Asynchronous <c>get-request</c></fsummary> <type> <v>UserId = term()</v> @@ -647,11 +647,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>async_get(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name> <fsummary>Asynchronous <c>get-request</c></fsummary> <type> <v>UserId = term()</v> @@ -683,8 +683,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>sync_get_next2(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_next2(UserId, TargetName, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="OTP R14B03">sync_get_next2(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="OTP R14B03">sync_get_next2(UserId, TargetName, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> <fsummary>Synchronous <c>get-next-request</c></fsummary> <type> <v>UserId = term()</v> @@ -737,11 +737,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>sync_get_next(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_next(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_next(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_next(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_next(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_next(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_next(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_next(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_next(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_next(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> <fsummary>Synchronous <c>get-next-request</c></fsummary> <type> <v>UserId = term()</v> @@ -775,8 +775,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>async_get_next2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_next2(UserId, TargetName, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name> + <name since="OTP R14B03">async_get_next2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name> + <name since="OTP R14B03">async_get_next2(UserId, TargetName, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name> <fsummary>Asynchronous <c>get-next-request</c></fsummary> <type> <v>UserId = term()</v> @@ -814,11 +814,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>async_get_next(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_next(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_next(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_next(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_next(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_next(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_next(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_next(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_next(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_next(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name> <fsummary>Asynchronous <c>get-next-request</c></fsummary> <type> <v>UserId = term()</v> @@ -849,8 +849,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>sync_set2(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_set2(UserId, TargetName, VarsAndVals, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="OTP R14B03">sync_set2(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="OTP R14B03">sync_set2(UserId, TargetName, VarsAndVals, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> <fsummary>Synchronous <c>set-request</c></fsummary> <type> <v>UserId = term()</v> @@ -906,11 +906,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>sync_set(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_set(UserId, TargetName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_set(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_set(UserId, TargetName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> <fsummary>Synchronous <c>set-request</c></fsummary> <type> <v>UserId = term()</v> @@ -946,8 +946,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>async_set2(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name> - <name>async_set2(UserId, TargetName, VarsAndVals, SendOpts) -> {ok, ReqId} | {error, Reason}</name> + <name since="OTP R14B03">async_set2(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name> + <name since="OTP R14B03">async_set2(UserId, TargetName, VarsAndVals, SendOpts) -> {ok, ReqId} | {error, Reason}</name> <fsummary>Asynchronous <c>set-request</c></fsummary> <type> <v>UserId = term()</v> @@ -990,11 +990,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>async_set(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name> - <name>async_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name> - <name>async_set(UserId, TargetName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name> - <name>async_set(UserId, TargetName, ContextName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name> - <name>async_set(UserId, TargetName, ContextName, VarsAndVals, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_set(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_set(UserId, TargetName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_set(UserId, TargetName, ContextName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_set(UserId, TargetName, ContextName, VarsAndVals, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name> <fsummary>Asynchronous <c>set-request</c></fsummary> <type> <v>UserId = term()</v> @@ -1026,8 +1026,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>sync_get_bulk2(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_bulk2(UserId, TragetName, NonRep, MaxRep, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="OTP R14B03">sync_get_bulk2(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="OTP R14B03">sync_get_bulk2(UserId, TragetName, NonRep, MaxRep, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> <fsummary>Synchronous <c>get-bulk-request</c></fsummary> <type> <v>UserId = term()</v> @@ -1082,11 +1082,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> - <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> + <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name> <fsummary>Synchronous <c>get-bulk-request</c></fsummary> <type> <v>UserId = term()</v> @@ -1121,8 +1121,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name> + <name since="OTP R14B03">async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason}</name> + <name since="OTP R14B03">async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name> <fsummary>Asynchronous <c>get-bulk-request</c></fsummary> <type> <v>UserId = term()</v> @@ -1162,11 +1162,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> - <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name> + <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name> <fsummary>Asynchronous <c>get-bulk-request</c></fsummary> <type> <v>UserId = term()</v> @@ -1199,7 +1199,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>cancel_async_request(UserId, ReqId) -> ok | {error, Reason}</name> + <name since="">cancel_async_request(UserId, ReqId) -> ok | {error, Reason}</name> <fsummary>Cancel a asynchronous request</fsummary> <type> <v>UserId = term()</v> @@ -1214,15 +1214,15 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>log_to_txt(LogDir)</name> - <name>log_to_txt(LogDir, Block | Mibs)</name> - <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R16B03">log_to_txt(LogDir)</name> + <name since="">log_to_txt(LogDir, Block | Mibs)</name> + <name since="">log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R16B03">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> @@ -1257,15 +1257,15 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> - <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> + <name since="OTP R16B03">log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name> <fsummary>Convert an Audit Trail Log to text format</fsummary> <type> <v>LogDir = string()</v> @@ -1299,7 +1299,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>change_log_size(NewSize) -> ok | {error, Reason}</name> + <name since="">change_log_size(NewSize) -> ok | {error, Reason}</name> <fsummary>Change the size of the Audit Trail Log</fsummary> <type> <v>NewSize = {MaxBytes, MaxFiles}</v> @@ -1321,7 +1321,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name> + <name since="">set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name> <fsummary>Change the Audit Trail Log type</fsummary> <type> <v>NewType = OldType = atl_type()</v> @@ -1340,7 +1340,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>load_mib(Mib) -> ok | {error, Reason}</name> + <name since="">load_mib(Mib) -> ok | {error, Reason}</name> <fsummary>Load a MIB into the manager</fsummary> <type> <v>Mib = MibName</v> @@ -1361,7 +1361,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>unload_mib(Mib) -> ok | {error, Reason}</name> + <name since="">unload_mib(Mib) -> ok | {error, Reason}</name> <fsummary>Unload a MIB from the manager</fsummary> <type> <v>Mib = MibName</v> @@ -1382,7 +1382,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>which_mibs() -> Mibs</name> + <name since="">which_mibs() -> Mibs</name> <fsummary>Which mibs are loaded into the manager</fsummary> <type> <v>Mibs = [{MibName, MibFile}]</v> @@ -1397,7 +1397,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>name_to_oid(Name) -> {ok, Oids} | {error, Reason}</name> + <name since="">name_to_oid(Name) -> {ok, Oids} | {error, Reason}</name> <fsummary>Get all the possible oid's for an alias-name</fsummary> <type> <v>Name = atom()</v> @@ -1414,7 +1414,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>oid_to_name(Oid) -> {ok, Name} | {error, Reason}</name> + <name since="">oid_to_name(Oid) -> {ok, Name} | {error, Reason}</name> <fsummary>Get the alias-name of the oid </fsummary> <type> <v>Oid = oid()</v> @@ -1429,7 +1429,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>oid_to_type(Oid) -> {ok, Type} | {error, Reason}</name> + <name since="">oid_to_type(Oid) -> {ok, Type} | {error, Reason}</name> <fsummary>Get the type of the the oid</fsummary> <type> <v>Oid = oid()</v> @@ -1444,7 +1444,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>backup(BackupDir) -> ok | {error, Reason}</name> + <name since="">backup(BackupDir) -> ok | {error, Reason}</name> <fsummary>Backup manager data</fsummary> <type> <v>BackupDir = string()</v> @@ -1458,7 +1458,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>info() -> [{Key, Value}]</name> + <name since="">info() -> [{Key, Value}]</name> <fsummary>Return information about the manager</fsummary> <type> <v>Key = atom()</v> @@ -1475,7 +1475,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>verbosity(Ref, Verbosity) -> void()</name> + <name since="">verbosity(Ref, Verbosity) -> void()</name> <fsummary>Assign a new verbosity for the process</fsummary> <type> <v>Ref = server | config | net_if | note_store | all</v> @@ -1492,8 +1492,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 </func> <func> - <name>format_reason(Reason) -> string()</name> - <name>format_reason(Prefix, Reason) -> string()</name> + <name since="">format_reason(Reason) -> string()</name> + <name since="">format_reason(Prefix, Reason) -> string()</name> <fsummary>Assign a new verbosity for the process</fsummary> <type> <v>Reason = term()</v> diff --git a/lib/snmp/doc/src/snmpm_conf.xml b/lib/snmp/doc/src/snmpm_conf.xml index a3097e5f7e..17ecf2df7c 100644 --- a/lib/snmp/doc/src/snmpm_conf.xml +++ b/lib/snmp/doc/src/snmpm_conf.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpm_conf.xml</file> </header> - <module>snmpm_conf</module> + <module since="">snmpm_conf</module> <modulesummary>Utility functions for handling the manager config files.</modulesummary> <description> <p>The module <c>snmpm_conf</c> contains various utility functions to @@ -42,7 +42,7 @@ </description> <funcs> <func> - <name>manager_entry(Tag, Val) -> manager_entry()</name> + <name since="">manager_entry(Tag, Val) -> manager_entry()</name> <fsummary>Create an manager entry</fsummary> <type> <v>Tag = address | port | engine_id | max_message_size</v> @@ -60,8 +60,8 @@ </desc> </func> <func> - <name>write_manager_config(Dir, Conf) -> ok</name> - <name>write_manager_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_manager_config(Dir, Conf) -> ok</name> + <name since="">write_manager_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the manager config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -81,7 +81,7 @@ </desc> </func> <func> - <name>append_manager_config(Dir, Conf) -> ok</name> + <name since="">append_manager_config(Dir, Conf) -> ok</name> <fsummary>Append the manager config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -98,7 +98,7 @@ </desc> </func> <func> - <name>read_manager_config(Dir) -> Conf</name> + <name since="">read_manager_config(Dir) -> Conf</name> <fsummary>Read the manager config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -115,9 +115,9 @@ </desc> </func> <func> - <name>users_entry(UserId) -> users_entry()</name> - <name>users_entry(UserId, UserMod) -> users_entry()</name> - <name>users_entry(UserId, UserMod, UserData) -> users_entry()</name> + <name since="">users_entry(UserId) -> users_entry()</name> + <name since="">users_entry(UserId, UserMod) -> users_entry()</name> + <name since="">users_entry(UserId, UserMod, UserData) -> users_entry()</name> <fsummary>Create an users entry</fsummary> <type> <v>UserId = term()</v> @@ -139,8 +139,8 @@ </desc> </func> <func> - <name>write_users_config(Dir, Conf) -> ok</name> - <name>write_users_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_users_config(Dir, Conf) -> ok</name> + <name since="">write_users_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the manager users config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -161,7 +161,7 @@ </desc> </func> <func> - <name>append_users_config(Dir, Conf) -> ok</name> + <name since="">append_users_config(Dir, Conf) -> ok</name> <fsummary>Append the manager users config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -179,7 +179,7 @@ </desc> </func> <func> - <name>read_users_config(Dir) -> Conf</name> + <name since="">read_users_config(Dir) -> Conf</name> <fsummary>Read the manager users config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -196,7 +196,7 @@ </desc> </func> <func> - <name>agents_entry(UserId, TargetName, Comm, Domain, Addr, EngineID, Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel) -> agents_entry()</name> + <name since="">agents_entry(UserId, TargetName, Comm, Domain, Addr, EngineID, Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel) -> agents_entry()</name> <fsummary>Create an agents entry</fsummary> <type> <v>UserId = term()</v> @@ -223,8 +223,8 @@ </desc> </func> <func> - <name>write_agents_config(Dir, Conf) -> ok</name> - <name>write_agents_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_agents_config(Dir, Conf) -> ok</name> + <name since="">write_agents_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the manager agents to the config file</fsummary> <type> <v>Dir = string()</v> @@ -245,7 +245,7 @@ </desc> </func> <func> - <name>append_agents_config(Dir, Conf) -> ok</name> + <name since="">append_agents_config(Dir, Conf) -> ok</name> <fsummary>Append the manager agents to the config file</fsummary> <type> <v>Dir = string()</v> @@ -263,7 +263,7 @@ </desc> </func> <func> - <name>read_agents_config(Dir) -> Conf</name> + <name since="">read_agents_config(Dir) -> Conf</name> <fsummary>Read the manager agents config from the config file</fsummary> <type> <v>Dir = string()</v> @@ -280,8 +280,8 @@ </desc> </func> <func> - <name>usm_entry(EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name> - <name>usm_entry(EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name> + <name since="">usm_entry(EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name> + <name since="">usm_entry(EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name> <fsummary>Create an usm entry</fsummary> <type> <v>EngineID = string()</v> @@ -303,8 +303,8 @@ </desc> </func> <func> - <name>write_usm_config(Dir, Conf) -> ok</name> - <name>write_usm_config(Dir, Hdr, Conf) -> ok</name> + <name since="">write_usm_config(Dir, Conf) -> ok</name> + <name since="">write_usm_config(Dir, Hdr, Conf) -> ok</name> <fsummary>Write the manager usm config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -325,7 +325,7 @@ </desc> </func> <func> - <name>append_usm_config(Dir, Conf) -> ok</name> + <name since="">append_usm_config(Dir, Conf) -> ok</name> <fsummary>Append the manager usm config to the config file</fsummary> <type> <v>Dir = string()</v> @@ -343,7 +343,7 @@ </desc> </func> <func> - <name>read_usm_config(Dir) -> Conf</name> + <name since="">read_usm_config(Dir) -> Conf</name> <fsummary>Read the manager usm config from the config file</fsummary> <type> <v>Dir = string()</v> diff --git a/lib/snmp/doc/src/snmpm_mpd.xml b/lib/snmp/doc/src/snmpm_mpd.xml index 08276e4b30..b024f8d294 100644 --- a/lib/snmp/doc/src/snmpm_mpd.xml +++ b/lib/snmp/doc/src/snmpm_mpd.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpm_mpd.xml</file> </header> - <module>snmpm_mpd</module> + <module since="">snmpm_mpd</module> <modulesummary>Message Processing and Dispatch module for the SNMP manager</modulesummary> <description> <p>The module <c>snmpm_mpd</c> implements the version independent @@ -48,7 +48,7 @@ <funcs> <func> - <name>init_mpd(Vsns) -> mpd_state()</name> + <name since="">init_mpd(Vsns) -> mpd_state()</name> <fsummary>Initialize the MPD module</fsummary> <type> <v>Vsns = [Vsn]</v> @@ -64,7 +64,7 @@ </desc> </func> <func> - <name>process_msg(Msg, Domain, Addr, State, NoteStore, Logger) -> {ok, Vsn, Pdu, PduMS, MsgData} | {discarded, Reason}</name> + <name since="OTP 17.3">process_msg(Msg, Domain, Addr, State, NoteStore, Logger) -> {ok, Vsn, Pdu, PduMS, MsgData} | {discarded, Reason}</name> <fsummary>Process a message received from the network</fsummary> <type> <v>Msg = binary()</v> @@ -92,7 +92,7 @@ </desc> </func> <func> - <name>generate_msg(Vsn, NoteStore, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name> + <name since="">generate_msg(Vsn, NoteStore, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name> <fsummary>Generate a request message to be sent to the network</fsummary> <type> <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v> @@ -117,7 +117,7 @@ </desc> </func> <func> - <name>generate_response_msg(Vsn, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name> + <name since="">generate_response_msg(Vsn, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name> <fsummary>Generate a response packet to be sent to the network</fsummary> <type> <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v> diff --git a/lib/snmp/doc/src/snmpm_network_interface.xml b/lib/snmp/doc/src/snmpm_network_interface.xml index 73892aa2e8..e4a66ceef2 100644 --- a/lib/snmp/doc/src/snmpm_network_interface.xml +++ b/lib/snmp/doc/src/snmpm_network_interface.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpm_network_interface.xml</file> </header> - <module>snmpm_network_interface</module> + <module since="">snmpm_network_interface</module> <modulesummary>Behaviour module for the SNMP manager network interface.</modulesummary> <description> <p>This module defines the behaviour of the manager network @@ -79,7 +79,7 @@ <funcs> <func> - <name>start_link(Server, NoteStore) -> {ok, Pid} | {error, Reason}</name> + <name since="">start_link(Server, NoteStore) -> {ok, Pid} | {error, Reason}</name> <fsummary>Start-link the network interface process</fsummary> <type> <v>Server = pid()</v> @@ -95,7 +95,7 @@ </func> <func> - <name>stop(Pid) -> void()</name> + <name since="">stop(Pid) -> void()</name> <fsummary>Stop the network interface process</fsummary> <type> <v>Pid = pid()</v> @@ -108,7 +108,7 @@ </func> <func> - <name>send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo) -> void()</name> + <name since="">send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo) -> void()</name> <fsummary>Request the network interface process to send this pdu</fsummary> <type> <v>Pid = pid()</v> @@ -142,7 +142,7 @@ </func> <func> - <name>inform_response(Pid, Ref, Addr, Port) -> void()</name> + <name since="">inform_response(Pid, Ref, Addr, Port) -> void()</name> <fsummary>Send the inform-request ack</fsummary> <type> <v>Pid = pid()</v> @@ -163,7 +163,7 @@ </func> <func> - <name>note_store(Pid, NoteStore) -> void()</name> + <name since="">note_store(Pid, NoteStore) -> void()</name> <fsummary>Change the verbosity of the network interface process</fsummary> <type> <v>Pid = pid()</v> @@ -179,7 +179,7 @@ </func> <func> - <name>info(Pid) -> [{Key, Value}]</name> + <name since="">info(Pid) -> [{Key, Value}]</name> <fsummary>Return information about the running network interface process</fsummary> <type> <v>Pid = pid()</v> @@ -198,7 +198,7 @@ </func> <func> - <name>verbosity(Pid, Verbosity) -> void()</name> + <name since="">verbosity(Pid, Verbosity) -> void()</name> <fsummary>Change the verbosity of the network interface process</fsummary> <type> <v>Pid = pid()</v> @@ -212,7 +212,7 @@ </func> <func> - <name>get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name> + <name since="">get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name> <fsummary>Get the Audit Trail Log type</fsummary> <type> <v>Pid = pid()</v> @@ -233,7 +233,7 @@ </func> <func> - <name>set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name> + <name since="">set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name> <fsummary>Change the Audit Trail Log type</fsummary> <type> <v>Pid = pid()</v> diff --git a/lib/snmp/doc/src/snmpm_network_interface_filter.xml b/lib/snmp/doc/src/snmpm_network_interface_filter.xml index 742cd53fc6..a50572da51 100644 --- a/lib/snmp/doc/src/snmpm_network_interface_filter.xml +++ b/lib/snmp/doc/src/snmpm_network_interface_filter.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpm_network_interface_filter.xml</file> </header> - <module>snmpm_network_interface_filter</module> + <module since="">snmpm_network_interface_filter</module> <modulesummary>Behaviour module for the SNMP manager network-interface filter.</modulesummary> <description> <p>This module defines the behaviour of the manager network interface @@ -100,7 +100,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | <funcs> <func> - <name>accept_recv(Domain, Addr) -> boolean()</name> + <name since="">accept_recv(Domain, Addr) -> boolean()</name> <fsummary>Shall the received message be accepted</fsummary> <type> <v>Domain = transportDomain()</v> @@ -116,7 +116,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | </func> <func> - <name>accept_send(Domain, Addr) -> boolean()</name> + <name since="">accept_send(Domain, Addr) -> boolean()</name> <fsummary>Shall the message be sent</fsummary> <type> <v>Domain = transportDomain()</v> @@ -132,7 +132,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | </func> <func> - <name>accept_recv_pdu(Domain, Addr, PduType) -> boolean()</name> + <name since="">accept_recv_pdu(Domain, Addr, PduType) -> boolean()</name> <fsummary>Shall the received pdu be accepted</fsummary> <type> <v>Domain = transportDomain()</v> @@ -150,7 +150,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | </func> <func> - <name>accept_send_pdu(Domain, Addr, PduType) -> boolean()</name> + <name since="">accept_send_pdu(Domain, Addr, PduType) -> boolean()</name> <fsummary>Shall the pdu be sent</fsummary> <type> <v>Domain = transportDomain()</v> diff --git a/lib/snmp/doc/src/snmpm_user.xml b/lib/snmp/doc/src/snmpm_user.xml index 87ae1d224a..9abf596c83 100644 --- a/lib/snmp/doc/src/snmpm_user.xml +++ b/lib/snmp/doc/src/snmpm_user.xml @@ -32,7 +32,7 @@ <rev></rev> <file>snmpm_user.xml</file> </header> - <module>snmpm_user</module> + <module since="">snmpm_user</module> <modulesummary>Behaviour module for the SNMP manager user.</modulesummary> <description> <p>This module defines the behaviour of the manager user. @@ -93,7 +93,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(), <funcs> <func> - <name>handle_error(ReqId, Reason, UserData) -> void()</name> + <name since="">handle_error(ReqId, Reason, UserData) -> void()</name> <fsummary>Handle error</fsummary> <type> <v>ReqId = integer()</v> @@ -122,7 +122,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(), </func> <func> - <name>handle_agent(Domain, Addr, Type, SnmpInfo, UserData) -> Reply</name> + <name since="">handle_agent(Domain, Addr, Type, SnmpInfo, UserData) -> Reply</name> <fsummary>Handle agent</fsummary> <type> <v>Domain = transportDomainUdpIpv4 | transportDomainUdpIpv6</v> @@ -181,7 +181,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(), </func> <func> - <name>handle_pdu(TargetName, ReqId, SnmpPduInfo, UserData) -> void()</name> + <name since="">handle_pdu(TargetName, ReqId, SnmpPduInfo, UserData) -> void()</name> <fsummary>Handle the reply to an asynchronous request</fsummary> <type> <v>TargetName = target_name()</v> @@ -202,7 +202,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(), </func> <func> - <name>handle_trap(TargetName, SnmpTrapInfo, UserData) -> Reply</name> + <name since="">handle_trap(TargetName, SnmpTrapInfo, UserData) -> Reply</name> <fsummary>Handle a trap/notification message</fsummary> <type> <v>TargetName = TargetName2 = target_name()</v> @@ -225,7 +225,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(), </func> <func> - <name>handle_inform(TargetName, SnmpInformInfo, UserData) -> Reply</name> + <name since="">handle_inform(TargetName, SnmpInformInfo, UserData) -> Reply</name> <fsummary>Handle a inform message</fsummary> <type> <v>TargetName = TargetName2 = target_name()</v> @@ -253,7 +253,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(), </func> <func> - <name>handle_report(TargetName, SnmpReportInfo, UserData) -> Reply</name> + <name since="">handle_report(TargetName, SnmpReportInfo, UserData) -> Reply</name> <fsummary>Handle a report message</fsummary> <type> <v>TargetName = TargetName2 = target_name()</v> @@ -278,7 +278,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(), </func> <func> - <name>handle_invalid_result(IN, OUT) -> void()</name> + <name since="OTP R16B03">handle_invalid_result(IN, OUT) -> void()</name> <fsummary>Handle a report message</fsummary> <type> <v>IN = {Func, Args}</v> diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index 177784384e..2e1b946ebb 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -30,6 +30,21 @@ <file>notes.xml</file> </header> +<section><title>Ssh 4.7.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed port leakage if a ssh:daemon call failed.</p> + <p> + Own Id: OTP-15397 Aux Id: ERL-801 </p> + </item> + </list> + </section> + +</section> + <section><title>Ssh 4.7.2</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -293,6 +308,21 @@ </section> </section> +<section><title>Ssh 4.6.9.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed port leakage if a ssh:daemon call failed.</p> + <p> + Own Id: OTP-15397 Aux Id: ERL-801 </p> + </item> + </list> + </section> + +</section> + <section><title>Ssh 4.6.9.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index 8435fced11..1a53a2ea98 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -28,7 +28,7 @@ <date>2007-10-06</date> <rev></rev> </header> - <module>ssh</module> + <module since="">ssh</module> <modulesummary>Main API of the ssh application</modulesummary> <description> <p>This is the interface module for the <c>SSH</c> application. @@ -1059,17 +1059,17 @@ <!-- CLOSE/1 --> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Closes an SSH connection.</fsummary> <desc><p>Closes an SSH connection.</p></desc> </func> <!-- CONNECT/2 etc --> <func> - <name>connect(Host, Port, Options) -> Result </name> - <name>connect(Host, Port, Options, NegotiationTimeout) -> Result </name> - <name>connect(TcpSocket, Options) -> Result</name> - <name>connect(TcpSocket, Options, NegotiationTimeout) -> Result</name> + <name since="">connect(Host, Port, Options) -> Result </name> + <name since="">connect(Host, Port, Options, NegotiationTimeout) -> Result </name> + <name since="OTP 19.0">connect(TcpSocket, Options) -> Result</name> + <name since="">connect(TcpSocket, Options, NegotiationTimeout) -> Result</name> <fsummary>Connects to an SSH server.</fsummary> <type> <v>Host = <seealso marker="#type-host">host()</seealso></v> @@ -1098,7 +1098,7 @@ <!-- CONNECTION_INFO/1, CONNECTION_INFO/2 --> <func> - <name name="connection_info" arity="2"/> + <name name="connection_info" arity="2" since=""/> <fsummary>Retrieves information about a connection.</fsummary> <desc> <p>Retrieves information about a connection. The list <c>Keys</c> defines which information that @@ -1108,9 +1108,9 @@ <!-- DEAMON/1,2,3 --> <func> - <name>daemon(Port | TcpSocket) -> Result</name> - <name>daemon(Port | TcpSocket, Options) -> Result</name> - <name>daemon(HostAddress, Port, Options) -> Result</name> + <name since="">daemon(Port | TcpSocket) -> Result</name> + <name since="">daemon(Port | TcpSocket, Options) -> Result</name> + <name since="">daemon(HostAddress, Port, Options) -> Result</name> <fsummary>Starts a server listening for SSH connections.</fsummary> <type> <v>Port = integer()</v> @@ -1154,7 +1154,7 @@ <!-- DAEMON_INFO/1 --> <func> - <name name="daemon_info" arity="1"/> + <name name="daemon_info" arity="1" since="OTP 19.0"/> <fsummary>Get info about a daemon</fsummary> <desc> <p>Returns a key-value list with information about the daemon.</p> @@ -1164,7 +1164,7 @@ <!-- DEFAULT_ALGORITHMS/0 --> <func> - <name name="default_algorithms" arity="0"/> + <name name="default_algorithms" arity="0" since="OTP 18.0"/> <fsummary>Get a list declaring the supported algorithms</fsummary> <desc> <p>Returns a key-value list, where the keys are the different types of algorithms and the values are the @@ -1176,9 +1176,9 @@ <!-- SHELL/1,2,3 --> <func> - <name>shell(Host | TcpSocket) -> Result </name> - <name>shell(Host | TcpSocket, Options) -> Result </name> - <name>shell(Host, Port, Options) -> Result </name> + <name since="">shell(Host | TcpSocket) -> Result </name> + <name since="">shell(Host | TcpSocket, Options) -> Result </name> + <name since="">shell(Host, Port, Options) -> Result </name> <fsummary>Starts an interactive shell on a remote SSH server.</fsummary> <type> <v>Host = <seealso marker="#type-host">host()</seealso></v> @@ -1203,8 +1203,8 @@ </func> <func> - <name name="start" arity="0"/> - <name name="start" arity="1"/> + <name name="start" arity="0" since=""/> + <name name="start" arity="1" since=""/> <fsummary>Starts the SSH application.</fsummary> <desc> <p>Utility function that starts the applications <c>crypto</c>, <c>public_key</c>, @@ -1215,7 +1215,7 @@ </func> <func> - <name name="stop" arity="0"/> + <name name="stop" arity="0" since=""/> <fsummary>Stops the <c>ssh</c> application.</fsummary> <desc> <p>Stops the <c>ssh</c> application. @@ -1225,9 +1225,9 @@ </func> <func> - <name name="stop_daemon" arity="1"/> - <name name="stop_daemon" arity="2"/> - <name name="stop_daemon" arity="3"/> + <name name="stop_daemon" arity="1" since=""/> + <name name="stop_daemon" arity="2" since=""/> + <name name="stop_daemon" arity="3" since="OTP 21.0"/> <fsummary>Stops the listener and all connections started by the listener.</fsummary> <desc> <p>Stops the listener and all connections started by the listener.</p> @@ -1235,9 +1235,9 @@ </func> <func> - <name name="stop_listener" arity="1"/> - <name name="stop_listener" arity="2"/> - <name name="stop_listener" arity="3"/> + <name name="stop_listener" arity="1" since=""/> + <name name="stop_listener" arity="2" since=""/> + <name name="stop_listener" arity="3" since="OTP 21.0"/> <fsummary>Stops the listener, but leaves existing connections started by the listener operational.</fsummary> <desc> <p>Stops the listener, but leaves existing connections started by the listener operational.</p> diff --git a/lib/ssh/doc/src/ssh_client_channel.xml b/lib/ssh/doc/src/ssh_client_channel.xml index 9be4007c68..cd28b95fd3 100644 --- a/lib/ssh/doc/src/ssh_client_channel.xml +++ b/lib/ssh/doc/src/ssh_client_channel.xml @@ -29,7 +29,7 @@ <date></date> <rev></rev> </header> - <module>ssh_client_channel</module> + <module since="OTP 21.0">ssh_client_channel</module> <modulesummary>-behaviour(ssh_client_channel). (Replaces ssh_channel) </modulesummary> <description> @@ -68,8 +68,8 @@ <funcs> <func> - <name>call(ChannelRef, Msg) -></name> - <name>call(ChannelRef, Msg, Timeout) -> Reply | {error, Reason}</name> + <name since="OTP 21.0">call(ChannelRef, Msg) -></name> + <name since="OTP 21.0">call(ChannelRef, Msg, Timeout) -> Reply | {error, Reason}</name> <fsummary>Makes a synchronous call to a channel.</fsummary> <type> <v>ChannelRef = pid() </v> @@ -92,7 +92,7 @@ </func> <func> - <name>cast(ChannelRef, Msg) -> ok </name> + <name since="OTP 21.0">cast(ChannelRef, Msg) -> ok </name> <fsummary>Sends an asynchronous message to the channel ChannelRef and returns ok.</fsummary> <type> @@ -111,7 +111,7 @@ </func> <func> - <name>enter_loop(State) -> _ </name> + <name since="OTP 21.0">enter_loop(State) -> _ </name> <fsummary>Makes an existing process an ssh_client_channel (replaces ssh_channel) process.</fsummary> <type> <v>State = term()</v> @@ -131,7 +131,7 @@ </func> <func> - <name>init(Options) -> {ok, State} | {ok, State, Timeout} | {stop, Reason} </name> + <name since="OTP 21.0">init(Options) -> {ok, State} | {ok, State, Timeout} | {stop, Reason} </name> <fsummary>Initiates an <c>ssh_client_channel</c> process.</fsummary> <type> <v>Options = [{Option, Value}]</v> @@ -173,7 +173,7 @@ </func> <func> - <name>reply(Client, Reply) -> _</name> + <name since="OTP 21.0">reply(Client, Reply) -> _</name> <fsummary>Sends a reply to a client.</fsummary> <type> <v>Client = opaque()</v> @@ -193,8 +193,8 @@ </func> <func> - <name>start(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> </name> - <name>start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> + <name since="OTP 21.0">start(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> </name> + <name since="OTP 21.0">start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> {ok, ChannelRef} | {error, Reason}</name> <fsummary>Starts a process that handles an SSH channel.</fsummary> <type> @@ -244,7 +244,7 @@ <funcs> <func> - <name>Module:code_change(OldVsn, State, Extra) -> {ok, + <name since="OTP 21.0">Module:code_change(OldVsn, State, Extra) -> {ok, NewState}</name> <fsummary>Converts process state when code is changed.</fsummary> <type> @@ -287,7 +287,7 @@ </func> <func> - <name>Module:init(Args) -> {ok, State} | {ok, State, timeout()} | + <name since="OTP 21.0">Module:init(Args) -> {ok, State} | {ok, State, timeout()} | {stop, Reason}</name> <fsummary>Makes necessary initializations and returns the initial channel state if the initializations succeed.</fsummary> @@ -307,7 +307,7 @@ </func> <func> - <name>Module:handle_call(Msg, From, State) -> Result</name> + <name since="OTP 21.0">Module:handle_call(Msg, From, State) -> Result</name> <fsummary>Handles messages sent by calling <c>call/[2,3]</c>.</fsummary> <type> @@ -334,7 +334,7 @@ </func> <func> - <name>Module:handle_cast(Msg, State) -> Result</name> + <name since="OTP 21.0">Module:handle_cast(Msg, State) -> Result</name> <fsummary>Handles messages sent by calling <c>cast/2</c>.</fsummary> <type> @@ -355,7 +355,7 @@ </func> <func> - <name>Module:handle_msg(Msg, State) -> {ok, State} | + <name since="OTP 21.0">Module:handle_msg(Msg, State) -> {ok, State} | {stop, ChannelId, State}</name> <fsummary>Handles other messages than SSH connection protocol, @@ -389,7 +389,7 @@ </func> <func> - <name>Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, + <name since="OTP 21.0">Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, ChannelId, State}</name> <fsummary>Handles <c>ssh</c> connection protocol messages.</fsummary> <type> @@ -416,7 +416,7 @@ </func> <func> - <name>Module:terminate(Reason, State) -> _</name> + <name since="OTP 21.0">Module:terminate(Reason, State) -> _</name> <fsummary>Does cleaning up before channel process termination. </fsummary> <type> diff --git a/lib/ssh/doc/src/ssh_client_key_api.xml b/lib/ssh/doc/src/ssh_client_key_api.xml index bc77756147..9f2f3013e5 100644 --- a/lib/ssh/doc/src/ssh_client_key_api.xml +++ b/lib/ssh/doc/src/ssh_client_key_api.xml @@ -29,7 +29,7 @@ <date></date> <rev></rev> </header> - <module>ssh_client_key_api</module> + <module since="OTP R16B">ssh_client_key_api</module> <modulesummary> -behaviour(ssh_client_key_api). </modulesummary> @@ -86,7 +86,7 @@ <funcs> <func> - <name>Module:add_host_key(HostNames, PublicHostKey, ConnectOptions) -> ok | {error, Reason}</name> + <name since="OTP R16B">Module:add_host_key(HostNames, PublicHostKey, ConnectOptions) -> ok | {error, Reason}</name> <fsummary>Adds a host key to the set of trusted host keys.</fsummary> <type> <v>HostNames = string()</v> @@ -103,7 +103,7 @@ </func> <func> - <name>Module:is_host_key(Key, Host, Algorithm, ConnectOptions) -> Result</name> + <name since="OTP R16B">Module:is_host_key(Key, Host, Algorithm, ConnectOptions) -> Result</name> <fsummary>Checks if a host key is trusted.</fsummary> <type> <v>Key = <seealso marker="public_key:public_key#type-public_key">public_key:public_key()</seealso></v> @@ -125,7 +125,7 @@ </func> <func> - <name>Module:user_key(Algorithm, ConnectOptions) -> + <name since="OTP R16B">Module:user_key(Algorithm, ConnectOptions) -> {ok, PrivateKey} | {error, Reason}</name> <fsummary>Fetches the users <em>public key</em> matching the <c>Algorithm</c>.</fsummary> <type> diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml index 8e1cf156a8..2a701929f6 100644 --- a/lib/ssh/doc/src/ssh_connection.xml +++ b/lib/ssh/doc/src/ssh_connection.xml @@ -30,7 +30,7 @@ <date></date> <rev></rev> </header> - <module>ssh_connection</module> + <module since="">ssh_connection</module> <modulesummary> This module provides API functions to send SSH Connection Protocol events to the other side of an SSH channel. @@ -201,7 +201,7 @@ <funcs> <func> - <name>adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok</name> + <name since="">adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok</name> <fsummary>Adjusts the SSH flow control window.</fsummary> <type> <v>ConnectionRef = connection_ref()</v> @@ -221,7 +221,7 @@ </func> <func> - <name>close(ConnectionRef, ChannelId) -> ok</name> + <name since="">close(ConnectionRef, ChannelId) -> ok</name> <fsummary>Sends a close message on the channel <c>ChannelId</c>.</fsummary> <type> <v>ConnectionRef = connection_ref()</v> @@ -240,7 +240,7 @@ </func> <func> - <name>exec(ConnectionRef, ChannelId, Command, TimeOut) -> ssh_request_status() | + <name since="">exec(ConnectionRef, ChannelId, Command, TimeOut) -> ssh_request_status() | {error, reason()}</name> <fsummary>Requests that the server starts the execution of the given command.</fsummary> <type> @@ -284,7 +284,7 @@ </func> <func> - <name>exit_status(ConnectionRef, ChannelId, Status) -> ok</name> + <name since="">exit_status(ConnectionRef, ChannelId, Status) -> ok</name> <fsummary>Sends the exit status of a command to the client.</fsummary> <type> <v>ConnectionRef = connection_ref() </v> @@ -298,8 +298,8 @@ </func> <func> - <name>ptty_alloc(ConnectionRef, ChannelId, Options) -></name> - <name>ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> > ssh_request_status() | + <name since="OTP 17.5">ptty_alloc(ConnectionRef, ChannelId, Options) -></name> + <name since="OTP 17.4">ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> > ssh_request_status() | {error, reason()}</name> <fsummary>Sends an SSH Connection Protocol <c>pty_req</c>, to allocate a pseudo-terminal.</fsummary> @@ -339,7 +339,7 @@ </func> <func> - <name>reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok</name> + <name since="">reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok</name> <fsummary>Sends status replies to requests that want such replies.</fsummary> <type> <v>ConnectionRef = connection_ref()</v> @@ -357,10 +357,10 @@ </func> <func> - <name>send(ConnectionRef, ChannelId, Data) -></name> - <name>send(ConnectionRef, ChannelId, Data, Timeout) -></name> - <name>send(ConnectionRef, ChannelId, Type, Data) -></name> - <name>send(ConnectionRef, ChannelId, Type, Data, TimeOut) -> + <name since="">send(ConnectionRef, ChannelId, Data) -></name> + <name since="">send(ConnectionRef, ChannelId, Data, Timeout) -></name> + <name since="">send(ConnectionRef, ChannelId, Type, Data) -></name> + <name since="">send(ConnectionRef, ChannelId, Type, Data, TimeOut) -> ok | {error, timeout} | {error, closed}</name> <fsummary>Sends channel data.</fsummary> <type> @@ -380,7 +380,7 @@ </func> <func> - <name>send_eof(ConnectionRef, ChannelId) -> ok | {error, closed}</name> + <name since="">send_eof(ConnectionRef, ChannelId) -> ok | {error, closed}</name> <fsummary>Sends EOF on channel <c>ChannelId</c>.</fsummary> <type> <v>ConnectionRef = connection_ref()</v> @@ -392,8 +392,8 @@ </func> <func> - <name>session_channel(ConnectionRef, Timeout) -></name> - <name>session_channel(ConnectionRef, InitialWindowSize, + <name since="">session_channel(ConnectionRef, Timeout) -></name> + <name since="">session_channel(ConnectionRef, InitialWindowSize, MaxPacketSize, Timeout) -> {ok, channel_id()} | {error, reason()}</name> <fsummary>Opens a channel for an SSH session.</fsummary> <type> @@ -410,7 +410,7 @@ </func> <func> - <name>setenv(ConnectionRef, ChannelId, Var, Value, TimeOut) -> ssh_request_status() | + <name since="">setenv(ConnectionRef, ChannelId, Var, Value, TimeOut) -> ssh_request_status() | {error, reason()}</name> <fsummary>Environment variables can be passed to the shell/command to be started later.</fsummary> @@ -428,7 +428,7 @@ </func> <func> - <name>shell(ConnectionRef, ChannelId) -> ok | failure | {error, closed} + <name since="">shell(ConnectionRef, ChannelId) -> ok | failure | {error, closed} </name> <fsummary>Requests that the user default shell (typically defined in /etc/passwd in Unix systems) is to be executed at the server end.</fsummary> @@ -448,7 +448,7 @@ </func> <func> - <name>subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> ssh_request_status() | + <name since="">subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> ssh_request_status() | {error, reason()}</name> <fsummary>Requests to execute a predefined subsystem on the server.</fsummary> <type> diff --git a/lib/ssh/doc/src/ssh_file.xml b/lib/ssh/doc/src/ssh_file.xml index 6681d9c306..f1fef09083 100644 --- a/lib/ssh/doc/src/ssh_file.xml +++ b/lib/ssh/doc/src/ssh_file.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>ssh_file</module> + <module since="OTP 21.2">ssh_file</module> <modulesummary>Default callback module for the client's and server's database operations in the ssh application</modulesummary> <description> <p>This module is the default callback handler for the client's and the server's user and host "database" operations. @@ -169,7 +169,7 @@ <funcs> <func> - <name>host_key(Algorithm, DaemonOptions) -> {ok, Key} | {error, Reason}</name> + <name since="OTP 21.2">host_key(Algorithm, DaemonOptions) -> {ok, Key} | {error, Reason}</name> <fsummary></fsummary> <desc> <p><strong>Types and description</strong></p> @@ -195,7 +195,7 @@ </func> <func> - <name>is_auth_key(PublicUserKey, User, DaemonOptions) -> Result</name> + <name since="OTP 21.2">is_auth_key(PublicUserKey, User, DaemonOptions) -> Result</name> <fsummary></fsummary> <desc> <p><strong>Types and description</strong></p> @@ -216,7 +216,7 @@ </func> <func> - <name>add_host_key(HostNames, PublicHostKey, ConnectOptions) -> ok | {error, Reason}</name> + <name since="OTP 21.2">add_host_key(HostNames, PublicHostKey, ConnectOptions) -> ok | {error, Reason}</name> <fsummary></fsummary> <desc> <p><strong>Types and description</strong></p> @@ -235,7 +235,7 @@ </func> <func> - <name>is_host_key(Key, Host, Algorithm, ConnectOptions) -> Result</name> + <name since="OTP 21.2">is_host_key(Key, Host, Algorithm, ConnectOptions) -> Result</name> <fsummary></fsummary> <desc> <p><strong>Types and description</strong></p> @@ -254,7 +254,7 @@ </func> <func> - <name>user_key(Algorithm, ConnectOptions) -> {ok, PrivateKey} | {error, Reason}</name> + <name since="OTP 21.2">user_key(Algorithm, ConnectOptions) -> {ok, PrivateKey} | {error, Reason}</name> <fsummary></fsummary> <desc> <p><strong>Types and description</strong></p> diff --git a/lib/ssh/doc/src/ssh_server_channel.xml b/lib/ssh/doc/src/ssh_server_channel.xml index 31ba9a3231..a4e18bbfbf 100644 --- a/lib/ssh/doc/src/ssh_server_channel.xml +++ b/lib/ssh/doc/src/ssh_server_channel.xml @@ -29,7 +29,7 @@ <date></date> <rev></rev> </header> - <module>ssh_server_channel</module> + <module since="OTP 21.0">ssh_server_channel</module> <modulesummary>-behaviour(ssh_server_channel). (Replaces ssh_daemon_channel) </modulesummary> <description> @@ -70,7 +70,7 @@ <funcs> <func> - <name>Module:init(Args) -> {ok, State} | {ok, State, timeout()} | + <name since="OTP 21.0">Module:init(Args) -> {ok, State} | {ok, State, timeout()} | {stop, Reason}</name> <fsummary>Makes necessary initializations and returns the initial channel state if the initializations succeed.</fsummary> @@ -93,7 +93,7 @@ </func> <func> - <name>Module:handle_msg(Msg, State) -> {ok, State} | + <name since="OTP 21.0">Module:handle_msg(Msg, State) -> {ok, State} | {stop, ChannelId, State}</name> <fsummary>Handles other messages than SSH connection protocol, @@ -125,7 +125,7 @@ </func> <func> - <name>Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, + <name since="OTP 21.0">Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, ChannelId, State}</name> <fsummary>Handles <c>ssh</c> connection protocol messages.</fsummary> <type> @@ -152,7 +152,7 @@ </func> <func> - <name>Module:terminate(Reason, State) -> _</name> + <name since="OTP 21.0">Module:terminate(Reason, State) -> _</name> <fsummary>Does cleaning up before channel process termination. </fsummary> <type> diff --git a/lib/ssh/doc/src/ssh_server_key_api.xml b/lib/ssh/doc/src/ssh_server_key_api.xml index e2a31bd5f5..013a788a4a 100644 --- a/lib/ssh/doc/src/ssh_server_key_api.xml +++ b/lib/ssh/doc/src/ssh_server_key_api.xml @@ -29,7 +29,7 @@ <date></date> <rev></rev> </header> - <module>ssh_server_key_api</module> + <module since="OTP R16B">ssh_server_key_api</module> <modulesummary> -behaviour(ssh_server_key_api). </modulesummary> @@ -87,7 +87,7 @@ <funcs> <func> - <name>Module:host_key(Algorithm, DaemonOptions) -> + <name since="OTP R16B">Module:host_key(Algorithm, DaemonOptions) -> {ok, Key} | {error, Reason}</name> <fsummary>Fetches the host’s private key.</fsummary> <type> @@ -111,7 +111,7 @@ </func> <func> - <name>Module:is_auth_key(PublicUserKey, User, DaemonOptions) -> Result</name> + <name since="OTP R16B">Module:is_auth_key(PublicUserKey, User, DaemonOptions) -> Result</name> <fsummary>Checks if the user key is authorized.</fsummary> <type> <v>PublicUserKey = <seealso marker="public_key:public_key#type-public_key">public_key:public_key()</seealso></v> diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml index 8c105147d6..c89092798d 100644 --- a/lib/ssh/doc/src/ssh_sftp.xml +++ b/lib/ssh/doc/src/ssh_sftp.xml @@ -29,7 +29,7 @@ <rev></rev> <file>ssh_sftp.sgml</file> </header> - <module>ssh_sftp</module> + <module since="">ssh_sftp</module> <modulesummary>SFTP client.</modulesummary> <description> <p>This module implements an SSH FTP (SFTP) client. SFTP is a @@ -82,7 +82,7 @@ <funcs> <func> - <name>apread(ChannelPid, Handle, Position, Len) -> {async, N} | {error, reason()}</name> + <name since="">apread(ChannelPid, Handle, Position, Len) -> {async, N} | {error, reason()}</name> <fsummary>Reads asynchronously from an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -98,7 +98,7 @@ </func> <func> - <name>apwrite(ChannelPid, Handle, Position, Data) -> {async, N} | {error, reason()}</name> + <name since="">apwrite(ChannelPid, Handle, Position, Data) -> {async, N} | {error, reason()}</name> <fsummary>Writes asynchronously to an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -116,7 +116,7 @@ </func> <func> - <name>aread(ChannelPid, Handle, Len) -> {async, N} | {error, reason()}</name> + <name since="">aread(ChannelPid, Handle, Len) -> {async, N} | {error, reason()}</name> <fsummary>Reads asynchronously from an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -137,7 +137,7 @@ </func> <func> - <name>awrite(ChannelPid, Handle, Data) -> {async, N} | {error, reason()}</name> + <name since="">awrite(ChannelPid, Handle, Data) -> {async, N} | {error, reason()}</name> <fsummary>Writes asynchronously to an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -159,8 +159,8 @@ </func> <func> - <name>close(ChannelPid, Handle) -></name> - <name>close(ChannelPid, Handle, Timeout) -> ok | {error, reason()}</name> + <name since="">close(ChannelPid, Handle) -></name> + <name since="">close(ChannelPid, Handle, Timeout) -> ok | {error, reason()}</name> <fsummary>Closes an open handle.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -173,8 +173,8 @@ </func> <func> - <name>delete(ChannelPid, Name) -></name> - <name>delete(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name> + <name since="">delete(ChannelPid, Name) -></name> + <name since="">delete(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name> <fsummary>Deletes a file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -188,8 +188,8 @@ </func> <func> - <name>del_dir(ChannelPid, Name) -></name> - <name>del_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name> + <name since="">del_dir(ChannelPid, Name) -></name> + <name since="">del_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name> <fsummary>Deletes an empty directory.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -204,8 +204,8 @@ </func> <func> - <name>list_dir(ChannelPid, Path) -></name> - <name>list_dir(ChannelPid, Path, Timeout) -> {ok, Filenames} | {error, reason()}</name> + <name since="">list_dir(ChannelPid, Path) -></name> + <name since="">list_dir(ChannelPid, Path, Timeout) -> {ok, Filenames} | {error, reason()}</name> <fsummary>Lists the directory.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -221,8 +221,8 @@ </func> <func> - <name>make_dir(ChannelPid, Name) -></name> - <name>make_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name> + <name since="">make_dir(ChannelPid, Name) -></name> + <name since="">make_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name> <fsummary>Creates a directory.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -237,8 +237,8 @@ </func> <func> - <name>make_symlink(ChannelPid, Name, Target) -></name> - <name>make_symlink(ChannelPid, Name, Target, Timeout) -> ok | {error, reason()}</name> + <name since="">make_symlink(ChannelPid, Name, Target) -></name> + <name since="">make_symlink(ChannelPid, Name, Target, Timeout) -> ok | {error, reason()}</name> <fsummary>Creates a symbolic link.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -253,8 +253,8 @@ </func> <func> - <name>open(ChannelPid, File, Mode) -></name> - <name>open(ChannelPid, File, Mode, Timeout) -> {ok, Handle} | {error, reason()}</name> + <name since="">open(ChannelPid, File, Mode) -></name> + <name since="">open(ChannelPid, File, Mode, Timeout) -> {ok, Handle} | {error, reason()}</name> <fsummary>Opens a file and returns a handle.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -270,8 +270,8 @@ </desc> </func> <func> - <name>opendir(ChannelPid, Path) -></name> - <name>opendir(ChannelPid, Path, Timeout) -> {ok, Handle} | {error, reason()}</name> + <name since="">opendir(ChannelPid, Path) -></name> + <name since="">opendir(ChannelPid, Path, Timeout) -> {ok, Handle} | {error, reason()}</name> <fsummary>Opens a directory and returns a handle.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -285,8 +285,8 @@ </func> <func> - <name>open_tar(ChannelPid, Path, Mode) -></name> - <name>open_tar(ChannelPid, Path, Mode, Timeout) -> {ok, Handle} | {error, reason()}</name> + <name since="OTP 17.4">open_tar(ChannelPid, Path, Mode) -></name> + <name since="OTP 17.4">open_tar(ChannelPid, Path, Mode, Timeout) -> {ok, Handle} | {error, reason()}</name> <fsummary>Opens a tar file on the server to which <c>ChannelPid</c> is connected and returns a handle.</fsummary> <type> @@ -339,8 +339,8 @@ </func> <func> - <name>position(ChannelPid, Handle, Location) -></name> - <name>position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition | {error, reason()}</name> + <name since="">position(ChannelPid, Handle, Location) -></name> + <name since="">position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition | {error, reason()}</name> <fsummary>Sets the file position of a file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -384,8 +384,8 @@ </func> <func> - <name>pread(ChannelPid, Handle, Position, Len) -></name> - <name>pread(ChannelPid, Handle, Position, Len, Timeout) -> {ok, Data} | eof | {error, reason()}</name> + <name since="">pread(ChannelPid, Handle, Position, Len) -></name> + <name since="">pread(ChannelPid, Handle, Position, Len, Timeout) -> {ok, Data} | eof | {error, reason()}</name> <fsummary>Reads from an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -402,8 +402,8 @@ </func> <func> - <name>pwrite(ChannelPid, Handle, Position, Data) -> ok</name> - <name>pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, reason()}</name> + <name since="">pwrite(ChannelPid, Handle, Position, Data) -> ok</name> + <name since="">pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, reason()}</name> <fsummary>Writes to an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -419,8 +419,8 @@ </func> <func> - <name>read(ChannelPid, Handle, Len) -></name> - <name>read(ChannelPid, Handle, Len, Timeout) -> {ok, Data} | eof | {error, reason()}</name> + <name since="">read(ChannelPid, Handle, Len) -></name> + <name since="">read(ChannelPid, Handle, Len, Timeout) -> {ok, Data} | eof | {error, reason()}</name> <fsummary>Reads from an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -441,8 +441,8 @@ </func> <func> - <name>read_file(ChannelPid, File) -></name> - <name>read_file(ChannelPid, File, Timeout) -> {ok, Data} | {error, reason()}</name> + <name since="">read_file(ChannelPid, File) -></name> + <name since="">read_file(ChannelPid, File, Timeout) -> {ok, Data} | {error, reason()}</name> <fsummary>Reads a file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -456,8 +456,8 @@ </func> <func> - <name>read_file_info(ChannelPid, Name) -></name> - <name>read_file_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()}</name> + <name since="">read_file_info(ChannelPid, Name) -></name> + <name since="">read_file_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()}</name> <fsummary>Gets information about a file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -481,8 +481,8 @@ </func> <func> - <name>read_link(ChannelPid, Name) -></name> - <name>read_link(ChannelPid, Name, Timeout) -> {ok, Target} | {error, reason()}</name> + <name since="">read_link(ChannelPid, Name) -></name> + <name since="">read_link(ChannelPid, Name, Timeout) -> {ok, Target} | {error, reason()}</name> <fsummary>Reads symbolic link.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -496,8 +496,8 @@ </func> <func> - <name>read_link_info(ChannelPid, Name) -> {ok, FileInfo} | {error, reason()}</name> - <name>read_link_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()}</name> + <name since="">read_link_info(ChannelPid, Name) -> {ok, FileInfo} | {error, reason()}</name> + <name since="">read_link_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()}</name> <fsummary>Gets information about a symbolic link.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -517,8 +517,8 @@ </func> <func> - <name>rename(ChannelPid, OldName, NewName) -> </name> - <name>rename(ChannelPid, OldName, NewName, Timeout) -> ok | {error, reason()}</name> + <name since="">rename(ChannelPid, OldName, NewName) -> </name> + <name since="">rename(ChannelPid, OldName, NewName, Timeout) -> ok | {error, reason()}</name> <fsummary>Renames a file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -534,16 +534,16 @@ </func> <func> - <name>start_channel(ConnectionRef) -></name> - <name>start_channel(ConnectionRef, Options) -> + <name since="">start_channel(ConnectionRef) -></name> + <name since="">start_channel(ConnectionRef, Options) -> {ok, Pid} | {error, reason()|term()}</name> - <name>start_channel(Host, Options) -></name> - <name>start_channel(Host, Port, Options) -> + <name since="">start_channel(Host, Options) -></name> + <name since="">start_channel(Host, Port, Options) -> {ok, Pid, ConnectionRef} | {error, reason()|term()}</name> - <name>start_channel(TcpSocket) -></name> - <name>start_channel(TcpSocket, Options) -> + <name since="">start_channel(TcpSocket) -></name> + <name since="">start_channel(TcpSocket, Options) -> {ok, Pid, ConnectionRef} | {error, reason()|term()}</name> <fsummary>Starts an SFTP client.</fsummary> @@ -594,7 +594,7 @@ </func> <func> - <name>stop_channel(ChannelPid) -> ok</name> + <name since="">stop_channel(ChannelPid) -> ok</name> <fsummary>Stops the SFTP client channel.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -606,8 +606,8 @@ </func> <func> - <name>write(ChannelPid, Handle, Data) -></name> - <name>write(ChannelPid, Handle, Data, Timeout) -> ok | {error, reason()}</name> + <name since="">write(ChannelPid, Handle, Data) -></name> + <name since="">write(ChannelPid, Handle, Data, Timeout) -> ok | {error, reason()}</name> <fsummary>Writes to an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -625,8 +625,8 @@ </func> <func> - <name>write_file(ChannelPid, File, Iolist) -></name> - <name>write_file(ChannelPid, File, Iolist, Timeout) -> ok | {error, reason()}</name> + <name since="">write_file(ChannelPid, File, Iolist) -></name> + <name since="">write_file(ChannelPid, File, Iolist, Timeout) -> ok | {error, reason()}</name> <fsummary>Writes a file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -641,8 +641,8 @@ </func> <func> - <name>write_file_info(ChannelPid, Name, Info) -></name> - <name>write_file_info(ChannelPid, Name, Info, Timeout) -> ok | {error, reason()}</name> + <name since="">write_file_info(ChannelPid, Name, Info) -></name> + <name since="">write_file_info(ChannelPid, Name, Info, Timeout) -> ok | {error, reason()}</name> <fsummary>Writes information for a file.</fsummary> <type> <v>ChannelPid = pid()</v> diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml index 3b34150e98..ee72784add 100644 --- a/lib/ssh/doc/src/ssh_sftpd.xml +++ b/lib/ssh/doc/src/ssh_sftpd.xml @@ -29,7 +29,7 @@ <rev></rev> <file>ssh_sftpd.sgml</file> </header> - <module>ssh_sftpd</module> + <module since="">ssh_sftpd</module> <modulesummary>Specifies the channel process to handle an SFTP subsystem.</modulesummary> <description> <p>Specifies a channel process to handle an SFTP subsystem.</p> @@ -51,7 +51,7 @@ </section> <funcs> <func> - <name>subsystem_spec(Options) -> subsystem_spec()</name> + <name since="">subsystem_spec(Options) -> subsystem_spec()</name> <fsummary>Returns the subsystem specification that allows an SSH daemon to handle the subsystem "sftp".</fsummary> <type> <v>Options = [{Option, Value}]</v> diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 086fa6e5f8..9281bf84a7 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -270,25 +270,38 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535, try {Host1, UserOptions} = handle_daemon_args(Host0, UserOptions0), #{} = Options0 = ssh_options:handle_options(server, UserOptions), - - {{Host,Port}, ListenSocket} = - open_listen_socket(Host1, Port0, Options0), - - %% Now Host,Port is what to use for the supervisor to register its name, - %% and ListenSocket is for listening on connections. But it is still owned - %% by self()... - - finalize_start(Host, Port, ?GET_OPT(profile, Options0), - ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options0), - fun(Opts, Result) -> - {_, Callback, _} = ?GET_OPT(transport, Opts), - receive - {request_control, ListenSocket, ReqPid} -> - ok = Callback:controlling_process(ListenSocket, ReqPid), - ReqPid ! {its_yours,ListenSocket}, - Result - end - end) + {open_listen_socket(Host1, Port0, Options0), Options0} + of + {{{Host,Port}, ListenSocket}, Options1} -> + try + %% Now Host,Port is what to use for the supervisor to register its name, + %% and ListenSocket is for listening on connections. But it is still owned + %% by self()... + finalize_start(Host, Port, ?GET_OPT(profile, Options1), + ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options1), + fun(Opts, Result) -> + {_, Callback, _} = ?GET_OPT(transport, Opts), + receive + {request_control, ListenSocket, ReqPid} -> + ok = Callback:controlling_process(ListenSocket, ReqPid), + ReqPid ! {its_yours,ListenSocket}, + Result + end + end) + of + {error,Err} -> + close_listen_socket(ListenSocket, Options1), + {error,Err}; + OK -> + OK + catch + error:Error -> + close_listen_socket(ListenSocket, Options1), + error(Error); + exit:Exit -> + close_listen_socket(ListenSocket, Options1), + exit(Exit) + end catch throw:bad_fd -> {error,bad_fd}; @@ -524,6 +537,15 @@ open_listen_socket(_Host0, Port0, Options0) -> {{LHost,LPort}, LSock}. %%%---------------------------------------------------------------- +close_listen_socket(ListenSocket, Options) -> + try + {_, Callback, _} = ?GET_OPT(transport, Options), + Callback:close(ListenSocket) + catch + _C:_E -> ok + end. + +%%%---------------------------------------------------------------- finalize_start(Host, Port, Profile, Options0, F) -> try %% throws error:Error if no usable hostkey is found diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl index 278f6a9780..aa9ba0f9bb 100644 --- a/lib/ssh/src/ssh_sftpd.erl +++ b/lib/ssh/src/ssh_sftpd.erl @@ -508,11 +508,8 @@ close_our_file({_,Fd}, FileMod, FS0) -> FS1. %%% stat: do the stat -stat(Vsn, ReqId, Data, State, F) when Vsn =< 3-> - <<?UINT32(BLen), BPath:BLen/binary>> = Data, - stat(ReqId, unicode:characters_to_list(BPath), State, F); -stat(Vsn, ReqId, Data, State, F) when Vsn >= 4-> - <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(_Flags)>> = Data, +stat(Vsn, ReqId, Data, State, F) -> + <<?UINT32(BLen), BPath:BLen/binary, _/binary>> = Data, stat(ReqId, unicode:characters_to_list(BPath), State, F). fstat(Vsn, ReqId, Data, State) when Vsn =< 3-> diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index da94b5722f..5de6d52092 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -43,7 +43,9 @@ suite() -> {timetrap,{seconds,40}}]. all() -> - [{group, all_tests}]. + [{group, all_tests}, + daemon_already_started + ]. groups() -> [{all_tests, [parallel], [{group, ssh_renegotiate_SUITE}, @@ -801,6 +803,24 @@ daemon_already_started(Config) when is_list(Config) -> ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- +%%% Test that a failed daemon start does not leave the port open +daemon_error_closes_port(Config) -> + GoodSystemDir = proplists:get_value(data_dir, Config), + Port = ssh_test_lib:inet_port(), + {error,_} = ssh_test_lib:daemon(Port, []), % No system dir + case ssh_test_lib:daemon(Port, [{system_dir, GoodSystemDir}]) of + {error,eaddrinuse} -> + {fail, "Port leakage"}; + {error,Error} -> + ct:log("Strange error: ~p",[Error]), + {fail, "Strange error"}; + {Pid, _Host, Port} -> + %% Ok + ssh:stop_daemon(Pid) + end. + + +%%-------------------------------------------------------------------- %%% check that known_hosts is updated correctly known_hosts(Config) when is_list(Config) -> SystemDir = proplists:get_value(data_dir, Config), diff --git a/lib/ssh/test/ssh_bench_SUITE.erl b/lib/ssh/test/ssh_bench_SUITE.erl index 764c52b624..2ac4e5636a 100644 --- a/lib/ssh/test/ssh_bench_SUITE.erl +++ b/lib/ssh/test/ssh_bench_SUITE.erl @@ -109,11 +109,10 @@ connect(Config) -> lists:foreach( fun(KexAlg) -> PrefAlgs = preferred_algorithms(KexAlg), - report([{value, measure_connect(Config, - [{preferred_algorithms,PrefAlgs}])}, - {suite, ?MODULE}, - {name, mk_name(["Connect erlc erld ",KexAlg," [µs]"])} - ]) + TimeMicroSec = measure_connect(Config, + [{preferred_algorithms,PrefAlgs}]), + report(["Connect erlc erld ",KexAlg," [connects per sec]"], + 1000000 / TimeMicroSec) end, KexAlgs). @@ -130,7 +129,7 @@ measure_connect(Config, Opts) -> [begin {Time, {ok,Pid}} = timer:tc(ssh,connect,["localhost", Port, ConnectOptions]), ssh:close(Pid), - Time + Time % in µs end || _ <- lists:seq(1,?Nruns)]). %%%---------------------------------------------------------------- @@ -178,10 +177,6 @@ gen_data(DataSz) -> <<Data0/binary, Data1/binary>>. -%% connect_measure(Port, Cipher, Mac, Data, Options) -> -%% report([{value, 1}, -%% {suite, ?MODULE}, -%% {name, mk_name(["Transfer 1M bytes ",Cipher,"/",Mac," [µs]"])}]); connect_measure(Port, Cipher, Mac, Data, Options) -> AES_GCM = {cipher, []}, @@ -220,10 +215,8 @@ connect_measure(Port, Cipher, Mac, Data, Options) -> ssh:close(C), Time end || _ <- lists:seq(1,?Nruns)], - - report([{value, median(Times)}, - {suite, ?MODULE}, - {name, mk_name(["Transfer 1M bytes ",Cipher,"/",Mac," [µs]"])}]). + report(["Transfer ",Cipher,"/",Mac," [Mbyte per sec]"], + 1000000 / median(Times)). send_wait_acc(C, Ch, Data) -> ssh_connection:send(C, Ch, Data), @@ -238,12 +231,6 @@ send_wait_acc(C, Ch, Data) -> %%% %%%---------------------------------------------------------------- -mk_name(Name) -> [char(C) || C <- lists:concat(Name)]. - -char($-) -> $_; -char(C) -> C. - -%%%---------------------------------------------------------------- preferred_algorithms(KexAlg) -> [{kex, [KexAlg]}, {public_key, ['ssh-rsa']}, @@ -265,11 +252,22 @@ median(Data) when is_list(Data) -> 1 -> lists:nth(N div 2 + 1, SortedData) end, - ct:log("median(~p) = ~p",[SortedData,Median]), + ct:pal("median(~p) = ~p",[SortedData,Median]), Median. +%%%---------------------------------------------------------------- +report(LabelList, Value) -> + Label = report_chars(lists:concat(LabelList)), + ct:pal("ct_event:notify ~p: ~p", [Label, Value]), + ct_event:notify( + #event{name = benchmark_data, + data = [{suite, ?MODULE}, + {name, Label}, + {value, Value}]}). + +report_chars(Cs) -> + [case C of + $- -> $_; + _ -> C + end || C <- Cs]. -report(Data) -> - ct:log("EventData = ~p",[Data]), - ct_event:notify(#event{name = benchmark_data, - data = Data}). diff --git a/lib/ssh/test/ssh_compat_SUITE.erl b/lib/ssh/test/ssh_compat_SUITE.erl index f4eef2dc77..8e82527c6e 100644 --- a/lib/ssh/test/ssh_compat_SUITE.erl +++ b/lib/ssh/test/ssh_compat_SUITE.erl @@ -1126,7 +1126,24 @@ prepare_local_directory(ServerRootDir) -> "chmod 222 unreadable_file", "exit"]. + check_local_directory(ServerRootDir) -> + TimesToTry = 3, % sleep 0.5, 1, 2 and then 4 secs (7.5s in total) + check_local_directory(ServerRootDir, 500, TimesToTry-1). + +check_local_directory(ServerRootDir, SleepTime, N) -> + case do_check_local_directory(ServerRootDir) of + {error,Error} when N>0 -> + %% Could be that the erlang side is faster and the docker's operations + %% are not yet finalized. + %% Sleep for a while and retry a few times: + timer:sleep(SleepTime), + check_local_directory(ServerRootDir, 2*SleepTime, N-1); + Other -> + Other + end. + +do_check_local_directory(ServerRootDir) -> case lists:sort(ok(file:list_dir(ServerRootDir)) -- [".",".."]) of ["ex_tst1","mydir","tst2"] -> {ok,Expect} = file:read_file(filename:join(ServerRootDir,"ex_tst1")), @@ -1161,6 +1178,7 @@ check_local_directory(ServerRootDir) -> {error,{bad_dir_contents,"/"}} end. + call_sftp_in_docker(Config, ServerIP, ServerPort, Cmnds, UserDir) -> {DockerIP,DockerPort} = ip_port(Config), {ok,C} = ssh:connect(DockerIP, DockerPort, diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 3ba1e177be..2890d7fe5b 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,4 +1,4 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 4.7.2 +SSH_VSN = 4.7.3 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/doc/specs/.gitignore b/lib/ssl/doc/specs/.gitignore new file mode 100644 index 0000000000..322eebcb06 --- /dev/null +++ b/lib/ssl/doc/specs/.gitignore @@ -0,0 +1 @@ +specs_*.xml diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile index c72b6d6cc4..7cf251d8f9 100644 --- a/lib/ssl/doc/src/Makefile +++ b/lib/ssl/doc/src/Makefile @@ -80,11 +80,16 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf +SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml) + +TOP_SPECS_FILE = specs.xml + # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- XML_FLAGS += DVIPS_FLAGS += +SPECS_FLAGS = -I../../../public_key/include -I../../../public_key/src -I../../.. # ---------------------------------------------------- # Targets @@ -92,7 +97,7 @@ DVIPS_FLAGS += $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -docs: pdf html man +docs: html pdf man $(TOP_PDF_FILE): $(XML_FILES) @@ -105,6 +110,7 @@ clean clean_docs: rm -rf $(XMLDIR) rm -f $(MAN3DIR)/* rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f $(SPECS_FILES) rm -f errs core *~ man: $(MAN3_FILES) $(MAN6_FILES) diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index 48372babf8..674e38b054 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -27,6 +27,58 @@ </header> <p>This document describes the changes made to the SSL application.</p> +<section><title>SSL 9.1.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix encoding of the SRP extension length field in ssl. + The old encoding of the SRP extension length could cause + interoperability problems with third party SSL + implementations when SRP was used.</p> + <p> + Own Id: OTP-15477 Aux Id: ERL-790 </p> + </item> + <item> + <p> + Guarantee active once data delivery, handling TCP stream + properly.</p> + <p> + Own Id: OTP-15504 Aux Id: ERL-371 </p> + </item> + <item> + <p> + Correct gen_statem returns for some error cases</p> + <p> + Own Id: OTP-15505</p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 9.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed renegotiation bug. Client did not handle server + initiated renegotiation correctly after rewrite to two + connection processes, due to ERL-622 commit + d87ac1c55188f5ba5cdf72384125d94d42118c18. This could + manifest it self as a " bad_record_mac" alert.</p> + <p> + Also included are some optimizations</p> + <p> + Own Id: OTP-15489 Aux Id: ERL-308 </p> + </item> + </list> + </section> + +</section> + <section><title>SSL 9.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/ssl/doc/src/specs.xml b/lib/ssl/doc/src/specs.xml new file mode 100644 index 0000000000..50e9428fec --- /dev/null +++ b/lib/ssl/doc/src/specs.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" ?> +<specs xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:include href="../specs/specs_ssl_crl_cache_api.xml"/> + <xi:include href="../specs/specs_ssl_crl_cache.xml"/> + <xi:include href="../specs/specs_ssl_session_cache_api.xml"/> + <xi:include href="../specs/specs_ssl.xml"/> +</specs> + + diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 3029977745..21ea1be4b4 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -28,7 +28,7 @@ <rev></rev> <file>ssl.xml</file> </header> - <module>ssl</module> + <module since="">ssl</module> <modulesummary>Interface Functions for Secure Socket Layer</modulesummary> <description> <p> @@ -37,273 +37,333 @@ <seealso marker="ssl_app">ssl(6)</seealso>. </p> </description> - - <section> - <title>DATA TYPES</title> - <p>The following data types are used in the functions for SSL/TLS/DTLS:</p> - - <taglist> - - <tag><c>boolean() =</c></tag> - <item><p><c>true | false</c></p></item> - - <tag><c>option() =</c></tag> - <item><p><c>socketoption() | ssl_option() | transport_option()</c></p> - </item> - - <tag><c>socketoption() =</c></tag> - <item><p><c>proplists:property()</c></p> - <p>The default socket options are - <c>[{mode,list},{packet, 0},{header, 0},{active, true}]</c>.</p> - <p>For valid options, see the - <seealso marker="kernel:inet">inet(3)</seealso>, - <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso> and - <seealso marker="kernel:gen_tcp">gen_udp(3)</seealso> - manual pages - in Kernel. Note that stream oriented options such as packet are only relevant for SSL/TLS and not DTLS</p></item> - - <tag><marker id="type-ssloption"/><c>ssl_option() =</c></tag> - <item> - <p><c>{verify, verify_type()}</c></p> - <p><c>| {verify_fun, {fun(), term()}}</c></p> - <p><c>| {fail_if_no_peer_cert, boolean()}</c></p> - <p><c>| {depth, integer()}</c></p> - <p><c>| {cert, public_key:der_encoded()}</c></p> - <p><c>| {certfile, path()}</c></p> - <p><c>| {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' - | 'PrivateKeyInfo', public_key:der_encoded()} | - #{algorithm := rsa | dss | ecdsa, - engine := crypto:engine_ref(), key_id := crypto:key_id(), password => crypto:password()}</c></p> - <p><c>| {keyfile, path()}</c></p> - <p><c>| {password, string()}</c></p> - <p><c>| {cacerts, [public_key:der_encoded()]}</c></p> - <p><c>| {cacertfile, path()}</c></p> - <p><c>| {dh, public_key:der_encoded()}</c></p> - <p><c>| {dhfile, path()}</c></p> - <p><c>| {ciphers, ciphers()}</c></p> - <p><c>| {user_lookup_fun, {fun(), term()}}, {psk_identity, string()}, - {srp_identity, {string(), string()}}</c></p> - <p><c>| {reuse_sessions, boolean()}</c></p> - <p><c>| {reuse_session, fun()} {next_protocols_advertised, [binary()]}</c></p> - <p><c>| {client_preferred_next_protocols, {client | server, - [binary()]} | {client | server, [binary()], binary()}}</c></p> - <p><c>| {log_alert, boolean()}</c></p> - <p><c>| {server_name_indication, hostname() | disable}</c></p> - <p><c>| {customize_hostname_check, list()}</c></p> - <p><c>| {sni_hosts, [{hostname(), [ssl_option()]}]}</c></p> - <p><c>| {sni_fun, SNIfun::fun()}</c></p> - </item> - - <tag><c>transport_option() =</c></tag> - <item><p><c>{cb_info, {CallbackModule::atom(), DataTag::atom(), - - ClosedTag::atom(), ErrTag:atom()}}</c></p> - <p>Defaults to <c>{gen_tcp, tcp, tcp_closed, tcp_error}</c> for TLS - and <c>{gen_udp, udp, udp_closed, udp_error}</c> for DTLS. Can be used - to customize the transport layer. For TLS the callback module must implement a - reliable transport protocol, behave as <c>gen_tcp</c>, and have functions - corresponding to <c>inet:setopts/2</c>, <c>inet:getopts/2</c>, - <c>inet:peername/1</c>, <c>inet:sockname/1</c>, and <c>inet:port/1</c>. - The callback <c>gen_tcp</c> is treated specially and calls <c>inet</c> - directly. For DTLS this feature must be considered exprimental.</p> - <taglist> - <tag><c>CallbackModule =</c></tag> - <item><p><c>atom()</c></p></item> - <tag><c>DataTag =</c></tag> - <item><p><c>atom()</c></p> - <p>Used in socket data message.</p></item> - <tag><c>ClosedTag =</c></tag> - <item><p><c>atom()</c></p> - <p>Used in socket close message.</p></item> - </taglist> - </item> - - <tag><c>verify_type() =</c></tag> - <item><p><c>verify_none | verify_peer</c></p></item> - - <tag><c>path() =</c></tag> - <item><p><c>string()</c></p> - <p>Represents a file path.</p></item> - <tag><c>public_key:der_encoded() =</c></tag> - <item><p><c>binary()</c></p> - <p>ASN.1 DER-encoded entity as an Erlang binary.</p></item> + <!-- + ================================================================ + = Data types = + ================================================================ + --> - <tag><c>host() =</c></tag> - <item><p><c>hostname() | ipaddress()</c></p></item> + <datatypes> + <datatype_title>Types used in SSL/TLS/DTLS</datatype_title> - <tag><c>hostname() =</c></tag> - <item><p><c>string() - DNS hostname</c></p></item> + + <datatype> + <name name="socket"/> + </datatype> + + <datatype> + <name name="sslsocket"/> + <desc> + <p>An opaque reference to the TLS/DTLS connection.</p> + </desc> + </datatype> + + <datatype> + <name name="tls_option"/> + </datatype> + + <datatype> + <name name="tls_client_option"/> + </datatype> + + <datatype> + <name name="tls_server_option"/> + </datatype> + + + <datatype> + <name name="socket_option"/> + <desc> + <p>The default socket options are + <c>[{mode,list},{packet, 0},{header, 0},{active, true}]</c>.</p> + <p>For valid options, see the + <seealso marker="kernel:inet">inet(3)</seealso>, + <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso> and + <seealso marker="kernel:gen_tcp">gen_udp(3)</seealso> + manual pages in Kernel. Note that stream oriented options such as packet + are only relevant for SSL/TLS and not DTLS</p> + </desc> + </datatype> - <tag><c>ip_address() =</c></tag> - <item><p><c>{N1,N2,N3,N4} % IPv4 | {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6 - </c></p></item> + <datatype> + <name name="socket_connect_option"/> + </datatype> + + <datatype> + <name name="socket_listen_option"/> + </datatype> - <tag><c>sslsocket() =</c></tag> - <item><p>opaque()</p></item> - - <tag><marker id="type-protocol"/><c> protocol_version() =</c></tag> - <item><p><c> ssl_tls_protocol() | dtls_protocol() </c></p></item> - - <item><p><c>sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'</c></p></item> - - <tag><marker id="type-protocol"/><c> dtls_protocol() =</c></tag> - <item><p><c>'dtlsv1' | 'dtlsv1.2'</c></p></item> - - <tag><c>ciphers() =</c></tag> - <item><p><c>= [ciphersuite()]</c></p> - <p>Tuples and string formats accepted by versions - before ssl-8.2.4 will be converted for backwards compatibility</p></item> - - <tag><c>ciphersuite() =</c></tag> - <item><p><c> - #{key_exchange := key_exchange(), - cipher := cipher(), - mac := MAC::hash() | aead, - prf := PRF::hash() | default_prf} </c></p></item> - - <tag><c>key_exchange()=</c></tag> - <item><p><c>rsa | dhe_dss | dhe_rsa | dh_anon | psk | dhe_psk - | rsa_psk | srp_anon | srp_dss | srp_rsa | ecdh_anon | ecdh_ecdsa - | ecdhe_ecdsa | ecdh_rsa | ecdhe_rsa</c></p></item> - - <tag><c>cipher() =</c></tag> - <item><p><c>rc4_128 | des_cbc | '3des_ede_cbc' - | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305</c></p></item> - - <tag><c>hash() =</c></tag> - <item><p><c>md5 | sha | sha224 | sha256 | sha348 | sha512</c></p></item> - - <tag><c>prf_random() =</c></tag> - <item><p><c>client_random | server_random</c></p></item> - - <tag><c>cipher_filters() =</c></tag> - <item><p><c> [{key_exchange | cipher | mac | prf, algo_filter()}])</c></p></item> - - <tag><c>algo_filter() =</c></tag> - <item><p>fun(key_exchange() | cipher() | hash() | aead | default_prf) -> true | false </p></item> - - <tag><c>srp_param_type() =</c></tag> - <item><p><c>srp_1024 | srp_1536 | srp_2048 | srp_3072 - | srp_4096 | srp_6144 | srp_8192</c></p></item> - - <tag><c>SNIfun::fun()</c></tag> - <item><p><c>= fun(ServerName :: string()) -> [ssl_option()]</c></p></item> - - <tag><c>named_curve() =</c></tag> - <item><p><c>sect571r1 | sect571k1 | secp521r1 | brainpoolP512r1 - | sect409k1 | sect409r1 | brainpoolP384r1 | secp384r1 - | sect283k1 | sect283r1 | brainpoolP256r1 | secp256k1 | secp256r1 - | sect239k1 | sect233k1 | sect233r1 | secp224k1 | secp224r1 - | sect193r1 | sect193r2 | secp192k1 | secp192r1 | sect163k1 - | sect163r1 | sect163r2 | secp160k1 | secp160r1 | secp160r2</c></p></item> - - <tag><c>hello_extensions() =</c></tag> - <item><p><c>#{renegotiation_info => binary() | undefined, - signature_algs => [{hash(), ecsda| rsa| dsa}] | undefined - alpn => binary() | undefined, - next_protocol_negotiation => binary() | undefined, - srp => string() | undefined, - ec_point_formats => list() | undefined, - elliptic_curves => [oid] | undefined, - sni => string() | undefined} - }</c></p></item> + <datatype> + <name name="active_msgs"/> + <desc> + <p>When an TLS/DTLS socket is in active mode (the default), data from the + socket is delivered to the owner of the socket in the form of + messages as described above.</p> + </desc> + </datatype> + <datatype> + <name name="transport_option"/> + <desc> + <p>Defaults to <c>{gen_tcp, tcp, tcp_closed, tcp_error}</c> + for TLS and <c>{gen_udp, udp, udp_closed, udp_error}</c> for + DTLS. Can be used to customize the transport layer. The tag + values should be the values used by the underlying transport + in its active mode messages. For TLS the callback module must implement a + reliable transport protocol, behave as <c>gen_tcp</c>, and have functions + corresponding to <c>inet:setopts/2</c>, <c>inet:getopts/2</c>, + <c>inet:peername/1</c>, <c>inet:sockname/1</c>, and <c>inet:port/1</c>. + The callback <c>gen_tcp</c> is treated specially and calls <c>inet</c> + directly. For DTLS this feature must be considered exprimental. + </p> + </desc> + </datatype> + + <datatype> + <name name="path"/> + </datatype> + + <datatype> + <name name="host"/> + </datatype> + + <datatype> + <name name="hostname"/> + </datatype> + + <datatype> + <name name="ip_address"/> + </datatype> + + <datatype> + <name name="protocol_version"/> + </datatype> + + <datatype> + <name name="tls_version"/> + </datatype> + + <datatype> + <name name="dtls_version"/> + </datatype> + + + <datatype> + <name name="legacy_version"/> + </datatype> + + + <datatype> + <name name="verify_type"/> + </datatype> + + <datatype> + <name name="ciphers"/> + </datatype> + + <datatype> + <name name="erl_cipher_suite"/> + </datatype> + + <datatype> + <name name="cipher"/> + </datatype> + + <datatype> + <name name="legacy_cipher"/> + </datatype> + + <datatype> + <name name="cipher_filters"/> + </datatype> + + <datatype> + <name name="hash"/> + </datatype> - </taglist> - </section> + <datatype> + <name name="sha2"/> + </datatype> - <section> - <title>TLS/DTLS OPTION DESCRIPTIONS - COMMON for SERVER and CLIENT</title> + <datatype> + <name name="legacy_hash"/> + </datatype> - <p>The following options have the same meaning in the client and - the server:</p> + + <datatype> + <name name="signature_algs"/> + </datatype> + + <datatype> + <name name="sign_algo"/> + </datatype> + + <datatype> + <name name="key_algo"/> + </datatype> + + <datatype> + <name name="algo_filter"/> + </datatype> + + <datatype> + <name name="eccs"/> + </datatype> + + <datatype> + <name name="named_curve"/> + </datatype> + + <datatype> + <name name="psk_identity"/> + </datatype> + + <datatype> + <name name="srp_identity"/> + </datatype> + + <datatype> + <name name="srp_param_type"/> + </datatype> + + <datatype> + <name name="app_level_protocol"/> + </datatype> + + <datatype> + <name name="error_alert"/> + </datatype> + + <datatype> + <name name="tls_alert"/> + </datatype> + + <datatype_title>TLS/DTLS OPTION DESCRIPTIONS - COMMON for SERVER and CLIENT</datatype_title> - <taglist> - - <tag><c>{protocol, tls | dtls}</c></tag> - <item><p>Choose TLS or DTLS protocol for the transport layer security. - Defaults to <c>tls</c> Introduced in OTP 20, DTLS support is considered - experimental in this release. Other transports than UDP are not yet supported.</p></item> - - <tag><c>{handshake, hello | full}</c></tag> - <item><p> Defaults to <c>full</c>. If hello is specified the handshake will - pause after the hello message and give the user a possibility make decisions - based on hello extensions before continuing or aborting the handshake by calling - <seealso marker="#handshake_continue-3"> handshake_continue/3</seealso> or - <seealso marker="#handshake_cancel-1"> handshake_cancel/1</seealso> - </p></item> - - <tag><c>{cert, public_key:der_encoded()}</c></tag> - <item><p>The DER-encoded users certificate. If this option - is supplied, it overrides option <c>certfile</c>.</p></item> - - <tag><c>{certfile, path()}</c></tag> - <item><p>Path to a file containing the user certificate.</p></item> - - <tag> - <marker id="key_option_def"/> - <c>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' - |'PrivateKeyInfo', public_key:der_encoded()} | #{algorithm := rsa | dss | ecdsa, - engine := crypto:engine_ref(), key_id := crypto:key_id(), password => crypto:password()}</c></tag> - <item><p>The DER-encoded user's private key or a map refering to a crypto - engine and its key reference that optionally can be password protected, - seealso <seealso marker="crypto:crypto#engine_load-4"> crypto:engine_load/4 - </seealso> and <seealso marker="crypto:engine_load"> Crypto's Users Guide</seealso>. If this option - is supplied, it overrides option <c>keyfile</c>.</p></item> - - <tag><c>{keyfile, path()}</c></tag> - <item><p>Path to the file containing the user's - private PEM-encoded key. As PEM-files can contain several - entries, this option defaults to the same file as given by - option <c>certfile</c>.</p></item> - - <tag><c>{password, string()}</c></tag> - <item><p>String containing the user's password. Only used if the - private keyfile is password-protected.</p></item> - - <tag><c>{ciphers, ciphers()}</c></tag> - <item><p>Supported cipher suites. The function - <c>cipher_suites/0</c> can be used to find all ciphers that are - supported by default. <c>cipher_suites(all)</c> can be called - to find all available cipher suites. Pre-Shared Key - (<url href="http://www.ietf.org/rfc/rfc4279.txt">RFC 4279</url> and - <url href="http://www.ietf.org/rfc/rfc5487.txt">RFC 5487</url>), - Secure Remote Password - (<url href="http://www.ietf.org/rfc/rfc5054.txt">RFC 5054</url>), RC4 cipher suites, - and anonymous cipher suites only work if explicitly enabled by - this option; they are supported/enabled by the peer also. - Anonymous cipher suites are supported for testing purposes - only and are not be used when security matters.</p></item> - - <tag><c>{eccs, [named_curve()]}</c></tag> - <item><p> Allows to specify the order of preference for named curves - and to restrict their usage when using a cipher suite supporting them. - </p></item> - - <tag><c>{secure_renegotiate, boolean()}</c></tag> - <item><p>Specifies if to reject renegotiation attempt that does - not live up to - <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>. - By default <c>secure_renegotiate</c> is set to <c>true</c>, - that is, secure renegotiation is enforced. If set to <c>false</c> secure renegotiation - will still be used if possible, - but it falls back to insecure renegotiation if the peer - does not support - <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>.</p> - </item> - - <tag><c>{depth, integer()}</c></tag> - <item><p>Maximum number of non-self-issued + <datatype> + <name name="common_option"/> + </datatype> + + <datatype> + <name since="OTP 20" name="protocol"/> + <desc> + <p>Choose TLS or DTLS protocol for the transport layer security. + Defaults to <c>tls</c>. For DTLS other transports than UDP are not yet supported.</p> + </desc> + </datatype> + + <datatype> + <name name="handshake_completion"/> + <desc> + <p>Defaults to <c>full</c>. If hello is specified the handshake will + pause after the hello message and give the user a possibility make decisions + based on hello extensions before continuing or aborting the handshake by calling + <seealso marker="#handshake_continue-3"> handshake_continue/3</seealso> or + <seealso marker="#handshake_cancel-1"> handshake_cancel/1</seealso></p> + </desc> + </datatype> + + <datatype> + <name name="cert"/> + <desc> + <p>The DER-encoded users certificate. If this option + is supplied, it overrides option <c>certfile</c>.</p> + </desc> + </datatype> + + <datatype> + <name name="cert_pem"/> + <desc> + <p>Path to a file containing the user certificate on PEM format.</p> + </desc> + </datatype> + + <datatype> + <name name="key"/> + <desc> + <p>The DER-encoded user's private key or a map refering to a crypto + engine and its key reference that optionally can be password protected, + seealso <seealso marker="crypto:crypto#engine_load-4"> crypto:engine_load/4 + </seealso> and <seealso marker="crypto:engine_load"> Crypto's Users Guide</seealso>. If this option + is supplied, it overrides option <c>keyfile</c>.</p> + </desc> + </datatype> + + <datatype> + <name name="key_pem"/> + <desc> + <p>Path to the file containing the user's + private PEM-encoded key. As PEM-files can contain several + entries, this option defaults to the same file as given by + option <c>certfile</c>.</p> + </desc> + </datatype> + + <datatype> + <name name="key_password"/> + <desc> + <p>String containing the user's password. Only used if the + private keyfile is password-protected.</p> + </desc> + </datatype> + + <datatype> + <name name="cipher_suites"/> + <desc> + <p>Supported cipher suites. The function + <c>cipher_suites/2</c> can be used to find all ciphers that + are supported by default. <c>cipher_suites(all, 'tlsv1.2')</c> can be + called to find all available cipher suites. Pre-Shared Key + (<url href="http://www.ietf.org/rfc/rfc4279.txt">RFC + 4279</url> and <url + href="http://www.ietf.org/rfc/rfc5487.txt">RFC 5487</url>), + Secure Remote Password (<url + href="http://www.ietf.org/rfc/rfc5054.txt">RFC 5054</url>), + RC4, 3DES, DES cipher suites, and anonymous cipher suites only work if + explicitly enabled by this option; they are supported/enabled + by the peer also. Anonymous cipher suites are supported for + testing purposes only and are not be used when security + matters.</p> + </desc> + </datatype> + + <datatype> + <name name="eccs"/> + <desc><p> Allows to specify the order of preference for named curves + and to restrict their usage when using a cipher suite supporting them.</p> + </desc> + </datatype> + + <datatype> + <name name="secure_renegotiation"/> + <desc><p>Specifies if to reject renegotiation attempt that does + not live up to <url + href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>. By + default <c>secure_renegotiate</c> is set to <c>true</c>, that + is, secure renegotiation is enforced. If set to <c>false</c> + secure renegotiation will still be used if possible, but it + falls back to insecure renegotiation if the peer does not + support <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC + 5746</url>.</p> + </desc> + </datatype> + + <datatype> + <name name="allowed_cert_chain_length"/> + <desc><p>Maximum number of non-self-issued intermediate certificates that can follow the peer certificate in a valid certification path. So, if depth is 0 the PEER must be signed by the trusted ROOT-CA directly; if 1 the path can be PEER, CA, ROOT-CA; if 2 the path can be PEER, CA, CA, - ROOT-CA, and so on. The default value is 1.</p></item> - - <tag><marker id="verify_fun"/><c>{verify_fun, {Verifyfun :: fun(), InitialUserState :: - term()}}</c></tag> - <item><p>The verification fun is to be defined as follows:</p> + ROOT-CA, and so on. The default value is 1.</p> + </desc> + </datatype> + + <datatype> + <name name="custom_verify"/> + <desc> + <p>The verification fun is to be defined as follows:</p> <code> fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() | {revoked, @@ -315,20 +375,21 @@ atom()}} | <p>The verification fun is called during the X509-path validation when an error or an extension unknown to the SSL - application is encountered. It is also called - when a certificate is considered valid by the path validation - to allow access to each certificate in the path to the user - application. It differentiates between the peer - certificate and the CA certificates by using <c>valid_peer</c> or - <c>valid</c> as second argument to the verification fun. See the - <seealso marker="public_key:public_key_records">public_key User's - Guide</seealso> for definition of <c>#'OTPCertificate'{}</c> and - <c>#'Extension'{}</c>.</p> + application is encountered. It is also called when a + certificate is considered valid by the path validation to + allow access to each certificate in the path to the user + application. It differentiates between the peer certificate + and the CA certificates by using <c>valid_peer</c> or + <c>valid</c> as second argument to the verification fun. See + the <seealso marker="public_key:public_key_records">public_key + User's Guide</seealso> for definition of + <c>#'OTPCertificate'{}</c> and <c>#'Extension'{}</c>.</p> <list type="bulleted"> - <item><p>If the verify callback fun returns <c>{fail, Reason}</c>, - the verification process is immediately stopped, an alert is - sent to the peer, and the TLS/DTLS handshake terminates.</p></item> + <item><p>If the verify callback fun returns <c>{fail, + Reason}</c>, the verification process is immediately + stopped, an alert is sent to the peer, and the TLS/DTLS + handshake terminates.</p></item> <item><p>If the verify callback fun returns <c>{valid, UserState}</c>, the verification process continues.</p></item> <item><p>If the verify callback fun always returns @@ -378,10 +439,12 @@ atom()}} | <taglist> <tag><c>unknown_ca</c></tag> - <item><p>No trusted CA was found in the trusted store. The trusted CA is - normally a so called ROOT CA, which is a self-signed certificate. Trust can - be claimed for an intermediate CA (trusted anchor does not have to be - self-signed according to X-509) by using option <c>partial_chain</c>.</p> + <item><p>No trusted CA was found in the trusted store. The + trusted CA is normally a so called ROOT CA, which is a + self-signed certificate. Trust can be claimed for an + intermediate CA (trusted anchor does not have to be + self-signed according to X-509) by using option + <c>partial_chain</c>.</p> </item> <tag><c>selfsigned_peer</c></tag> @@ -392,15 +455,17 @@ atom()}} | marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso> </p></item> </taglist> - </item> - - <tag><c>{crl_check, boolean() | peer | best_effort }</c></tag> - <item> + </desc> + </datatype> + + <datatype> + <name name="crl_check"/> + <desc> <p>Perform CRL (Certificate Revocation List) verification <seealso marker="public_key:public_key#pkix_crls_validate-3"> - (public_key:pkix_crls_validate/3)</seealso> on all the certificates during the path validation - <seealso - marker="public_key:public_key#pkix_path_validation-3">(public_key:pkix_path_validation/3) + (public_key:pkix_crls_validate/3)</seealso> on all the + certificates during the path validation <seealso + marker="public_key:public_key#pkix_path_validation-3">(public_key:pkix_path_validation/3) </seealso> of the certificate chain. Defaults to <c>false</c>.</p> @@ -412,106 +477,104 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid <item>if certificate revocation status can not be determined it will be accepted as valid.</item> </taglist> - + <p>The CA certificates specified for the connection will be used to construct the certificate chain validating the CRLs.</p> <p>The CRLs will be fetched from a local or external cache. See <seealso marker="ssl:ssl_crl_cache_api">ssl_crl_cache_api(3)</seealso>.</p> - </item> - - <tag><c>{crl_cache, {Module :: atom(), {DbHandle :: internal | term(), Args :: list()}}}</c></tag> - <item> - <p>Specify how to perform lookup and caching of certificate revocation lists. - <c>Module</c> defaults to <seealso marker="ssl:ssl_crl_cache">ssl_crl_cache</seealso> - with <c> DbHandle </c> being <c>internal</c> and an - empty argument list.</p> - - <p>There are two implementations available:</p> - - <taglist> - <tag><c>ssl_crl_cache</c></tag> - <item> - <p>This module maintains a cache of CRLs. CRLs can be - added to the cache using the function <seealso - marker="ssl:ssl_crl_cache#insert-1">ssl_crl_cache:insert/1</seealso>, - and optionally automatically fetched through HTTP if the - following argument is specified:</p> - - <taglist> - <tag><c>{http, timeout()}</c></tag> - <item><p> - Enables fetching of CRLs specified as http URIs in<seealso - marker="public_key:public_key_records">X509 certificate extensions</seealso>. - Requires the OTP inets application.</p> - </item> - </taglist> - </item> - - <tag><c>ssl_crl_hash_dir</c></tag> - <item> - <p>This module makes use of a directory where CRLs are - stored in files named by the hash of the issuer name.</p> - - <p>The file names consist of eight hexadecimal digits - followed by <c>.rN</c>, where <c>N</c> is an integer, - e.g. <c>1a2b3c4d.r0</c>. For the first version of the - CRL, <c>N</c> starts at zero, and for each new version, - <c>N</c> is incremented by one. The OpenSSL utility - <c>c_rehash</c> creates symlinks according to this - pattern.</p> - - <p>For a given hash value, this module finds all - consecutive <c>.r*</c> files starting from zero, and those - files taken together make up the revocation list. CRL - files whose <c>nextUpdate</c> fields are in the past, or - that are issued by a different CA that happens to have the - same name hash, are excluded.</p> - - <p>The following argument is required:</p> - - <taglist> - <tag><c>{dir, string()}</c></tag> - <item><p>Specifies the directory in which the CRLs can be found.</p></item> - </taglist> - - </item> - - <tag><c>max_handshake_size</c></tag> - <item> - <p>Integer (24 bits unsigned). Used to limit the size of - valid TLS handshake packets to avoid DoS attacks. - Defaults to 256*1024.</p> - </item> - - </taglist> - - </item> + </desc> + </datatype> - <tag><c>{partial_chain, fun(Chain::[DerCert]) -> {trusted_ca, DerCert} | - unknown_ca }</c></tag> - <item><p>Claim an intermediate CA in the chain as trusted. TLS then - performs <seealso - marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso> - with the selected CA as trusted anchor and the rest of the chain.</p></item> + <datatype> + <name name="crl_cache_opts"/> + <desc> + <p>Specify how to perform lookup and caching of certificate revocation lists. + <c>Module</c> defaults to <seealso marker="ssl:ssl_crl_cache">ssl_crl_cache</seealso> + with <c> DbHandle </c> being <c>internal</c> and an + empty argument list.</p> + + <p>There are two implementations available:</p> + + <taglist> + <tag><c>ssl_crl_cache</c></tag> + <item> + <p>This module maintains a cache of CRLs. CRLs can be + added to the cache using the function <seealso + marker="ssl:ssl_crl_cache#insert-1">ssl_crl_cache:insert/1</seealso>, + and optionally automatically fetched through HTTP if the + following argument is specified:</p> + + <taglist> + <tag><c>{http, timeout()}</c></tag> + <item><p> + Enables fetching of CRLs specified as http URIs in<seealso + marker="public_key:public_key_records">X509 certificate extensions</seealso>. + Requires the OTP inets application.</p> + </item> + </taglist> + </item> + + <tag><c>ssl_crl_hash_dir</c></tag> + <item> + <p>This module makes use of a directory where CRLs are + stored in files named by the hash of the issuer name.</p> + + <p>The file names consist of eight hexadecimal digits + followed by <c>.rN</c>, where <c>N</c> is an integer, + e.g. <c>1a2b3c4d.r0</c>. For the first version of the + CRL, <c>N</c> starts at zero, and for each new version, + <c>N</c> is incremented by one. The OpenSSL utility + <c>c_rehash</c> creates symlinks according to this + pattern.</p> + + <p>For a given hash value, this module finds all + consecutive <c>.r*</c> files starting from zero, and those + files taken together make up the revocation list. CRL + files whose <c>nextUpdate</c> fields are in the past, or + that are issued by a different CA that happens to have the + same name hash, are excluded.</p> + + <p>The following argument is required:</p> + + <taglist> + <tag><c>{dir, string()}</c></tag> + <item><p>Specifies the directory in which the CRLs can be found.</p></item> + </taglist> + </item> + </taglist> + </desc> + </datatype> + + <datatype> + <name name="root_fun"/> + <desc> + <code> +fun(Chain::[public_key:der_encoded()]) -> + {trusted_ca, DerCert::public_key:der_encoded()} | unknown_ca} + </code> + <p>Claim an intermediate CA in the chain as trusted. TLS then + performs <seealso + marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso> + with the selected CA as trusted anchor and the rest of the chain.</p> + </desc> + </datatype> - <tag><c>{versions, [protocol_version()]}</c></tag> - <item><p>TLS protocol versions supported by started clients and servers. + <datatype> + <name name="protocol_versions"/> + <desc><p>TLS protocol versions supported by started clients and servers. This option overrides the application environment option <c>protocol_version</c> and <c>dtls_protocol_version</c>. If the environment option is not set, it defaults to all versions, except SSL-3.0, supported by the SSL application. - See also <seealso marker="ssl:ssl_app">ssl(6).</seealso></p></item> + See also <seealso marker="ssl:ssl_app">ssl(6).</seealso></p> + </desc> + </datatype> - <tag><c>{hibernate_after, integer()|undefined}</c></tag> - <item><p>When an integer-value is specified, <c>TLS/DTLS-connection</c> - goes into hibernation after the specified number of milliseconds - of inactivity, thus reducing its memory footprint. When - <c>undefined</c> is specified (this is the default), the process - never goes into hibernation.</p></item> - <tag><c>{user_lookup_fun, {Lookupfun :: fun(), UserState :: term()}}</c></tag> - <item><p>The lookup fun is to defined as follows:</p> + <datatype> + <name name="custom_user_lookup"/> + <desc><p>The lookup fun is to defined as follows:</p> <code> fun(psk, PSKIdentity ::string(), UserState :: term()) -> @@ -533,20 +596,54 @@ fun(srp, Username :: string(), UserState :: term()) -> <url href="http://tools.ietf.org/html/rfc5054#section-2.4"> RFC 5054</url>: <c>crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])])</c> </p> - </item> + </desc> + </datatype> - <tag><c>{padding_check, boolean()}</c></tag> - <item><p>Affects TLS-1.0 connections only. + <datatype> + <name name="session_id"/> + <desc> + <p>Identifies a TLS session.</p> + </desc> + </datatype> + + <datatype> + <name name="log_alert"/> + <desc><p>If set to <c>false</c>, error reports are not displayed.</p> + </desc> + </datatype> + + <datatype> + <name name="hibernate_after"/> + <desc><p>When an integer-value is specified, <c>TLS/DTLS-connection</c> + goes into hibernation after the specified number of milliseconds + of inactivity, thus reducing its memory footprint. When + <c>undefined</c> is specified (this is the default), the process + never goes into hibernation.</p> + </desc> + </datatype> + + <datatype> + <name name="handshake_size"/> + <desc> + <p>Integer (24 bits unsigned). Used to limit the size of + valid TLS handshake packets to avoid DoS attacks. + Defaults to 256*1024.</p> + </desc> + </datatype> + + <datatype> + <name name="padding_check"/> + <desc><p>Affects TLS-1.0 connections only. If set to <c>false</c>, it disables the block cipher padding check to be able to interoperate with legacy software.</p> <warning><p>Using <c>{padding_check, boolean()}</c> makes TLS vulnerable to the Poodle attack.</p></warning> - </item> - - + </desc> + </datatype> - <tag><c>{beast_mitigation, one_n_minus_one | zero_n | disabled}</c></tag> - <item><p>Affects SSL-3.0 and TLS-1.0 connections only. Used to change the BEAST + <datatype> + <name name="beast_mitigation"/> + <desc><p>Affects SSL-3.0 and TLS-1.0 connections only. Used to change the BEAST mitigation strategy to interoperate with legacy software. Defaults to <c>one_n_minus_one</c>.</p> @@ -556,127 +653,166 @@ fun(srp, Username :: string(), UserState :: term()) -> <p><c>disabled</c> - Disable BEAST mitigation.</p> - <warning><p>Using <c>{beast_mitigation, disabled}</c> makes SSL or TLS + <warning><p>Using <c>{beast_mitigation, disabled}</c> makes SSL-3.0 or TLS-1.0 vulnerable to the BEAST attack.</p></warning> - </item> - </taglist> - - </section> - - <section> - <title>TLS/DTLS OPTION DESCRIPTIONS - CLIENT SIDE</title> - - <p>The following options are client-specific or have a slightly different - meaning in the client than in the server:</p> + </desc> + </datatype> + - <taglist> + <datatype_title>TLS/DTLS OPTION DESCRIPTIONS - CLIENT</datatype_title> + + <datatype> + <name name="client_option"/> + </datatype> + + <datatype> + <name name="client_verify_type"/> + <desc><p>In mode <c>verify_none</c> the default behavior is to allow + all x509-path validation errors. See also option <seealso marker="#type-custom_verify">verify_fun</seealso>.</p> + </desc> + </datatype> - <tag><c>{verify, verify_type()}</c></tag> - <item><p>In mode <c>verify_none</c> the default behavior is to allow - all x509-path validation errors. See also option <c>verify_fun</c>.</p> - </item> + <datatype> + <name name="client_reuse_session"/> + <desc> + <p>Reuses a specific session earlier saved with the option + <c>{reuse_sessions, save} since OTP-21.3 </c> + </p> + </desc> + </datatype> - <tag><c>{reuse_sessions, boolean()}</c></tag> - <item><p>Specifies if the client is to try to reuse sessions - when possible.</p></item> + <datatype> + <name name="client_reuse_sessions"/> + <desc> + <p>When <c>save</c> is specified a new connection will be negotiated + and saved for later reuse. The session ID can be fetched with + <seealso marker="#connection_information-2">connection_information/2</seealso> + and used with the client option <seealso marker="#type-client_reuse_session">reuse_session</seealso> + The boolean value true specifies that if possible, automatized session reuse will + be performed. If a new session is created, and is unique in regard + to previous stored sessions, it will be saved for possible later reuse. Since OTP-21.3</p> + </desc> + </datatype> - <tag><c>{cacerts, [public_key:der_encoded()]}</c></tag> - <item><p>The DER-encoded trusted certificates. If this option - is supplied it overrides option <c>cacertfile</c>.</p></item> - - <tag><c>{cacertfile, path()}</c></tag> - <item><p>Path to a file containing PEM-encoded CA certificates. The CA + <datatype> + <name name="client_cacerts"/> + <desc> + <p>The DER-encoded trusted certificates. If this option + is supplied it overrides option <c>cacertfile</c>.</p> + </desc> + </datatype> + + <datatype> + <name name="client_cafile"/> + <desc> + <p>Path to a file containing PEM-encoded CA certificates. The CA certificates are used during server authentication and when building the client certificate chain.</p> - </item> - - <tag><c>{alpn_advertised_protocols, [binary()]}</c></tag> - <item> - <p>The list of protocols supported by the client to be sent to the - server to be used for an Application-Layer Protocol Negotiation (ALPN). - If the server supports ALPN then it will choose a protocol from this - list; otherwise it will fail the connection with a "no_application_protocol" - alert. A server that does not support ALPN will ignore this value.</p> - - <p>The list of protocols must not contain an empty binary.</p> - - <p>The negotiated protocol can be retrieved using the <c>negotiated_protocol/1</c> function.</p> - </item> - - <tag><c>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()]}}</c><br/> - <c>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()], Default :: binary()}}</c></tag> - <item> - <p>Indicates that the client is to try to perform Next Protocol - Negotiation.</p> - - <p>If precedence is server, the negotiated protocol is the - first protocol to be shown on the server advertised list, which is - also on the client preference list.</p> - - <p>If precedence is client, the negotiated protocol is the - first protocol to be shown on the client preference list, which is - also on the server advertised list.</p> - - <p>If the client does not support any of the server advertised - protocols or the server does not advertise any protocols, the - client falls back to the first protocol in its list or to the - default protocol (if a default is supplied). If the - server does not support Next Protocol Negotiation, the - connection terminates if no default protocol is supplied.</p> - </item> - - <tag><c>{psk_identity, string()}</c></tag> - <item><p>Specifies the identity the client presents to the server. - The matching secret is found by calling <c>user_lookup_fun</c>.</p> - </item> - - <tag><c>{srp_identity, {Username :: string(), Password :: string()} - </c></tag> - <item><p>Specifies the username and password to use to authenticate - to the server.</p></item> - - <tag><c>{server_name_indication, HostName :: hostname()}</c></tag> - <item><p>Specify the hostname to be used in TLS Server Name Indication extension. - If not specified it will default to the <c>Host</c> argument of <seealso marker="#connect-3">connect/[3,4]</seealso> - unless it is of type inet:ipaddress().</p> - <p> - The <c>HostName</c> will also be used in the hostname verification of the peer certificate using - <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso>. - </p> - </item> - <tag><c>{server_name_indication, disable}</c></tag> - <item> - <p> Prevents the Server Name Indication extension from being sent and - disables the hostname verification check - <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> </p> - </item> - - <tag><c>{customize_hostname_check, Options::list()}</c></tag> - <item> - <p> Customizes the hostname verification of the peer certificate, as different protocols that use + </desc> + </datatype> + + <datatype> + <name name="client_alpn"/> + <desc> + <p>The list of protocols supported by the client to be sent to the + server to be used for an Application-Layer Protocol Negotiation (ALPN). + If the server supports ALPN then it will choose a protocol from this + list; otherwise it will fail the connection with a "no_application_protocol" + alert. A server that does not support ALPN will ignore this value.</p> + + <p>The list of protocols must not contain an empty binary.</p> + + <p>The negotiated protocol can be retrieved using the <c>negotiated_protocol/1</c> function.</p> + </desc> + </datatype> + + <datatype> + <name name="client_preferred_next_protocols"/> + <desc> + <p>Indicates that the client is to try to perform Next Protocol + Negotiation.</p> + + <p>If precedence is server, the negotiated protocol is the + first protocol to be shown on the server advertised list, which is + also on the client preference list.</p> + + <p>If precedence is client, the negotiated protocol is the + first protocol to be shown on the client preference list, which is + also on the server advertised list.</p> + + <p>If the client does not support any of the server advertised + protocols or the server does not advertise any protocols, the + client falls back to the first protocol in its list or to the + default protocol (if a default is supplied). If the + server does not support Next Protocol Negotiation, the + connection terminates if no default protocol is supplied.</p> + </desc> + </datatype> + + <datatype> + <name name="client_psk_identity"/> + <desc> + <p>Specifies the identity the client presents to the server. + The matching secret is found by calling <c>user_lookup_fun</c></p> + </desc> + </datatype> + + <datatype> + <name name="client_srp_identity"/> + <desc> + <p>Specifies the username and password to use to authenticate + to the server.</p> + </desc> + </datatype> + + <datatype> + <name name="sni"/> + <desc> + <p>Specify the hostname to be used in TLS Server Name Indication extension. + If not specified it will default to the <c>Host</c> argument of <seealso marker="#connect-3">connect/[3,4]</seealso> + unless it is of type inet:ipaddress().</p> + <p> + The <c>HostName</c> will also be used in the hostname verification of the peer certificate using + <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso>. + </p> + <p> The special value <c>disable</c> prevents the Server Name Indication extension from being sent and + disables the hostname verification check + <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> </p> + </desc> + </datatype> + + <datatype> + <name name="customize_hostname_check"/> + <desc> + <p> Customizes the hostname verification of the peer certificate, as different protocols that use TLS such as HTTP or LDAP may want to do it differently, for possible options see <seealso marker="public_key:public_key#pkix_verify_hostname-3">public_key:pkix_verify_hostname/3</seealso> </p> - </item> - - <tag><c>{fallback, boolean()}</c></tag> - <item> - <p> Send special cipher suite TLS_FALLBACK_SCSV to avoid undesired TLS version downgrade. - Defaults to false</p> - <warning><p>Note this option is not needed in normal TLS usage and should not be used - to implement new clients. But legacy clients that retries connections in the following manner</p> - - <p><c> ssl:connect(Host, Port, [...{versions, ['tlsv2', 'tlsv1.1', 'tlsv1', 'sslv3']}])</c></p> - <p><c> ssl:connect(Host, Port, [...{versions, [tlsv1.1', 'tlsv1', 'sslv3']}, {fallback, true}])</c></p> - <p><c> ssl:connect(Host, Port, [...{versions, ['tlsv1', 'sslv3']}, {fallback, true}]) </c></p> - <p><c> ssl:connect(Host, Port, [...{versions, ['sslv3']}, {fallback, true}]) </c></p> - - <p>may use it to avoid undesired TLS version downgrade. Note that TLS_FALLBACK_SCSV must also - be supported by the server for the prevention to work. - </p></warning> - </item> - <tag><marker id="client_signature_algs"/><c>{signature_algs, [{hash(), ecdsa | rsa | dsa}]}</c></tag> - <item> - <p>In addition to the algorithms negotiated by the cipher + </desc> + </datatype> + + <datatype> + <name name="fallback"/> + <desc> + <p> Send special cipher suite TLS_FALLBACK_SCSV to avoid undesired TLS version downgrade. + Defaults to false</p> + <warning><p>Note this option is not needed in normal TLS usage and should not be used + to implement new clients. But legacy clients that retries connections in the following manner</p> + + <p><c> ssl:connect(Host, Port, [...{versions, ['tlsv2', 'tlsv1.1', 'tlsv1', 'sslv3']}])</c></p> + <p><c> ssl:connect(Host, Port, [...{versions, [tlsv1.1', 'tlsv1', 'sslv3']}, {fallback, true}])</c></p> + <p><c> ssl:connect(Host, Port, [...{versions, ['tlsv1', 'sslv3']}, {fallback, true}]) </c></p> + <p><c> ssl:connect(Host, Port, [...{versions, ['sslv3']}, {fallback, true}]) </c></p> + + <p>may use it to avoid undesired TLS version downgrade. Note that TLS_FALLBACK_SCSV must also + be supported by the server for the prevention to work. + </p></warning> + </desc> + </datatype> + + <datatype> + <name name="client_signature_algs"/> + <desc> + <p>In addition to the algorithms negotiated by the cipher suite used for key exchange, payload encryption, message authentication and pseudo random calculation, the TLS signature algorithm extension <url @@ -707,177 +843,230 @@ fun(srp, Username :: string(), UserState :: term()) -> Selected signature algorithm can restrict which hash functions that may be selected. Default support for {md5, rsa} removed in ssl-8.0 </p> - </item> - </taglist> - </section> - - <section> - <title>TLS/DTLS OPTION DESCRIPTIONS - SERVER SIDE</title> + </desc> + </datatype> + - <p>The following options are server-specific or have a slightly different - meaning in the server than in the client:</p> + <datatype_title>TLS/DTLS OPTION DESCRIPTIONS - SERVER </datatype_title> - <taglist> - <tag><c>{cacerts, [public_key:der_encoded()]}</c></tag> - <item><p>The DER-encoded trusted certificates. If this option - is supplied it overrides option <c>cacertfile</c>.</p></item> + <datatype> + <name name="server_option"/> + </datatype> + + <datatype> + <name name="server_cacerts"/> + <desc><p>The DER-encoded trusted certificates. If this option + is supplied it overrides option <c>cacertfile</c>.</p> + </desc> + </datatype> - <tag><c>{cacertfile, path()}</c></tag> - <item><p>Path to a file containing PEM-encoded CA - certificates. The CA certificates are used to build the server - certificate chain and for client authentication. The CAs are - also used in the list of acceptable client CAs passed to the - client when a certificate is requested. Can be omitted if there - is no need to verify the client and if there are no - intermediate CAs for the server certificate.</p></item> - - <tag><c>{dh, public_key:der_encoded()}</c></tag> - <item><p>The DER-encoded Diffie-Hellman parameters. If specified, - it overrides option <c>dhfile</c>.</p></item> - - <tag><c>{dhfile, path()}</c></tag> - <item><p>Path to a file containing PEM-encoded Diffie Hellman parameters - to be used by the server if a cipher suite using Diffie Hellman key - exchange is negotiated. If not specified, default parameters are used. - </p></item> - - <tag><c>{verify, verify_type()}</c></tag> - <item><p>A server only does x509-path validation in mode <c>verify_peer</c>, - as it then sends a certificate request to the client - (this message is not sent if the verify option is <c>verify_none</c>). - You can then also want to specify option <c>fail_if_no_peer_cert</c>. - </p></item> - - <tag><c>{fail_if_no_peer_cert, boolean()}</c></tag> - <item><p>Used together with <c>{verify, verify_peer}</c> by an TLS/DTLS server. - If set to <c>true</c>, the server fails if the client does not have - a certificate to send, that is, sends an empty certificate. If set to - <c>false</c>, it fails only if the client sends an invalid - certificate (an empty certificate is considered valid). Defaults to false.</p> - </item> - - <tag><c>{reuse_sessions, boolean()}</c></tag> - <item><p>Specifies if the server is to agree to reuse sessions - when requested by the clients. See also option <c>reuse_session</c>. - </p></item> - - <tag><c>{reuse_session, fun(SuggestedSessionId, - PeerCert, Compression, CipherSuite) -> boolean()}</c></tag> - <item><p>Enables the TLS/DTLS server to have a local policy - for deciding if a session is to be reused or not. - Meaningful only if <c>reuse_sessions</c> is set to <c>true</c>. - <c>SuggestedSessionId</c> is a <c>binary()</c>, <c>PeerCert</c> is - a DER-encoded certificate, <c>Compression</c> is an enumeration integer, - and <c>CipherSuite</c> is of type <c>ciphersuite()</c>.</p></item> - - <tag><c>{alpn_preferred_protocols, [binary()]}</c></tag> - <item> - <p>Indicates the server will try to perform Application-Layer - Protocol Negotiation (ALPN).</p> - - <p>The list of protocols is in order of preference. The protocol - negotiated will be the first in the list that matches one of the - protocols advertised by the client. If no protocol matches, the - server will fail the connection with a "no_application_protocol" alert.</p> - - <p>The negotiated protocol can be retrieved using the <c>negotiated_protocol/1</c> function.</p> - </item> - - <tag><c>{next_protocols_advertised, Protocols :: [binary()]}</c></tag> - <item><p>List of protocols to send to the client if the client indicates that - it supports the Next Protocol extension. The client can select a protocol - that is not on this list. The list of protocols must not contain an empty - binary. If the server negotiates a Next Protocol, it can be accessed - using the <c>negotiated_next_protocol/1</c> method.</p></item> - - <tag><c>{psk_identity, string()}</c></tag> - <item><p>Specifies the server identity hint, which the server presents to - the client.</p></item> - - <tag><c>{log_alert, boolean()}</c></tag> - <item><p>If set to <c>false</c>, error reports are not displayed.</p></item> - - <tag><c>{honor_cipher_order, boolean()}</c></tag> - <item><p>If set to <c>true</c>, use the server preference for cipher - selection. If set to <c>false</c> (the default), use the client - preference.</p></item> - - <tag><c>{sni_hosts, [{hostname(), [ssl_option()]}]}</c></tag> - <item><p>If the server receives a SNI (Server Name Indication) from the client - matching a host listed in the <c>sni_hosts</c> option, the specific options for - that host will override previously specified options. - - The option <c>sni_fun</c>, and <c>sni_hosts</c> are mutually exclusive.</p></item> - - <tag><c>{sni_fun, SNIfun::fun()}</c></tag> - <item><p>If the server receives a SNI (Server Name Indication) from the client, - the given function will be called to retrieve <c>[ssl_option()]</c> for the indicated server. - These options will be merged into predefined <c>[ssl_option()]</c>. - - The function should be defined as: - <c>fun(ServerName :: string()) -> [ssl_option()]</c> - and can be specified as a fun or as named <c>fun module:function/1</c> - - The option <c>sni_fun</c>, and <c>sni_hosts</c> are mutually exclusive.</p></item> - - <tag><c>{client_renegotiation, boolean()}</c></tag> - <item>In protocols that support client-initiated renegotiation, the cost - of resources of such an operation is higher for the server than the - client. This can act as a vector for denial of service attacks. The SSL - application already takes measures to counter-act such attempts, - but client-initiated renegotiation can be strictly disabled by setting - this option to <c>false</c>. The default value is <c>true</c>. - Note that disabling renegotiation can result in long-lived connections - becoming unusable due to limits on the number of messages the underlying - cipher suite can encipher. - </item> - - <tag><c>{honor_cipher_order, boolean()}</c></tag> - <item>If true, use the server's preference for cipher selection. If false - (the default), use the client's preference. - </item> - <tag><c>{honor_ecc_order, boolean()}</c></tag> - <item>If true, use the server's preference for ECC curve selection. If false - (the default), use the client's preference. - </item> - - <tag><c>{signature_algs, [{hash(), ecdsa | rsa | dsa}]}</c></tag> - <item><p> The algorithms specified by - this option will be the ones accepted by the server in a signature algorithm - negotiation, introduced in TLS-1.2. The algorithms will also be offered to the client if a - client certificate is requested. For more details see the <seealso marker="#client_signature_algs">corresponding client option</seealso>. - </p> </item> - - </taglist> - </section> - - <section> - <title>General</title> + <datatype> + <name name="server_cafile"/> + <desc><p>Path to a file containing PEM-encoded CA + certificates. The CA certificates are used to build the server + certificate chain and for client authentication. The CAs are + also used in the list of acceptable client CAs passed to the + client when a certificate is requested. Can be omitted if + there is no need to verify the client and if there are no + intermediate CAs for the server certificate.</p> + </desc> + </datatype> + + <datatype> + <name name="dh_der"/> + <desc><p>The DER-encoded Diffie-Hellman parameters. If + specified, it overrides option <c>dhfile</c>.</p> + </desc> + </datatype> + + <datatype> + <name name="dh_file"/> + <desc><p>Path to a file containing PEM-encoded Diffie Hellman + parameters to be used by the server if a cipher suite using + Diffie Hellman key exchange is negotiated. If not specified, + default parameters are used.</p> + </desc> + </datatype> - <p>When an TLS/DTLS socket is in active mode (the default), data from the - socket is delivered to the owner of the socket in the form of - messages:</p> - <list type="bulleted"> - <item><p><c>{ssl, Socket, Data}</c></p></item> - <item><p><c>{ssl_closed, Socket}</c></p></item> - <item><p><c>{ssl_error, Socket, Reason}</c></p></item> - </list> + <datatype> + <name name="server_verify_type"/> + <desc><p>A server only does x509-path validation in mode + <c>verify_peer</c>, as it then sends a certificate request to + the client (this message is not sent if the verify option is + <c>verify_none</c>). You can then also want to specify option + <c>fail_if_no_peer_cert</c>. </p> + </desc> + </datatype> + + <datatype> + <name name="fail_if_no_peer_cert"/> + <desc><p>Used together with <c>{verify, verify_peer}</c> by an + TLS/DTLS server. If set to <c>true</c>, the server fails if + the client does not have a certificate to send, that is, sends + an empty certificate. If set to <c>false</c>, it fails only if + the client sends an invalid certificate (an empty certificate + is considered valid). Defaults to false.</p> + </desc> + </datatype> + + <datatype> + <name name="server_reuse_sessions"/> + <desc><p>The boolean value true specifies that the server will + agree to reuse sessions. Setting it to false will result in an empty + session table, that is no sessions will be reused. + See also option <seealso marker="#type-server_reuse_session">reuse_session</seealso> + </p> + </desc> + </datatype> + + <datatype> + <name name="server_reuse_session"/> + <desc><p>Enables the TLS/DTLS server to have a local policy + for deciding if a session is to be reused or not. Meaningful + only if <c>reuse_sessions</c> is set to <c>true</c>. + <c>SuggestedSessionId</c> is a <c>binary()</c>, + <c>PeerCert</c> is a DER-encoded certificate, + <c>Compression</c> is an enumeration integer, and + <c>CipherSuite</c> is of type <c>ciphersuite()</c>.</p> + </desc> + </datatype> + + <datatype> + <name name="server_alpn"/> + <desc> + <p>Indicates the server will try to perform + Application-Layer Protocol Negotiation (ALPN).</p> + + <p>The list of protocols is in order of preference. The + protocol negotiated will be the first in the list that + matches one of the protocols advertised by the client. If no + protocol matches, the server will fail the connection with a + "no_application_protocol" alert.</p> + + <p>The negotiated protocol can be retrieved using the + <c>negotiated_protocol/1</c> function.</p> + </desc> + </datatype> + + <datatype> + <name name="server_next_protocol"/> + <desc><p>List of protocols to send to the client if the client + indicates that it supports the Next Protocol extension. The + client can select a protocol that is not on this list. The + list of protocols must not contain an empty binary. If the + server negotiates a Next Protocol, it can be accessed using + the <c>negotiated_next_protocol/1</c> method.</p> + </desc> + </datatype> + + <datatype> + <name name="server_psk_identity"/> + <desc> + <p>Specifies the server identity hint, which the server presents to + the client.</p> + </desc> + </datatype> + + <datatype> + <name name="honor_cipher_order"/> + <desc> + <p>If set to <c>true</c>, use the server preference for cipher + selection. If set to <c>false</c> (the default), use the client + preference.</p> + </desc> + </datatype> + + <datatype> + <name name="sni_hosts"/> + <desc><p>If the server receives a SNI (Server Name Indication) from the client + matching a host listed in the <c>sni_hosts</c> option, the specific options for + that host will override previously specified options. + + The option <c>sni_fun</c>, and <c>sni_hosts</c> are mutually exclusive.</p> + </desc> + </datatype> + + <datatype> + <name name="sni_fun"/> + <desc> + <p>If the server receives a SNI (Server Name Indication) + from the client, the given function will be called to + retrieve <seealso marker="#type-server_option">[server_option()] </seealso> for the indicated server. + These options will be merged into predefined + <seealso marker="#type-server_option">[server_option()] </seealso> list. + + The function should be defined as: + fun(ServerName :: string()) -> <seealso marker="#type-server_option">[server_option()] </seealso> + and can be specified as a fun or as named <c>fun module:function/1</c> + + The option <c>sni_fun</c>, and <c>sni_hosts</c> are mutually exclusive.</p> + </desc> + </datatype> + + <datatype> + <name name="client_renegotiation"/> + <desc><p>In protocols that support client-initiated + renegotiation, the cost of resources of such an operation is + higher for the server than the client. This can act as a + vector for denial of service attacks. The SSL application + already takes measures to counter-act such attempts, but + client-initiated renegotiation can be strictly disabled by + setting this option to <c>false</c>. The default value is + <c>true</c>. Note that disabling renegotiation can result in + long-lived connections becoming unusable due to limits on the + number of messages the underlying cipher suite can + encipher.</p> + </desc> + </datatype> + + <datatype> + <name name="honor_cipher_order"/> + <desc><p>If true, use the server's preference for cipher + selection. If false (the default), use the client's + preference.</p> + </desc> + </datatype> + + <datatype> + <name name="honor_ecc_order"/> + <desc><p>If true, use the server's preference for ECC curve + selection. If false (the default), use the client's + preference.</p> + </desc> + </datatype> + + <datatype> + <name name="server_signature_algs"/> + <desc><p> The algorithms specified by this option will be the + ones accepted by the server in a signature algorithm + negotiation, introduced in TLS-1.2. The algorithms will also + be offered to the client if a client certificate is + requested. For more details see the <seealso + marker="#type-client_signature_algs">corresponding client + option</seealso>. + </p> + </desc> + </datatype> + </datatypes> + +<!-- + ================================================================ + = Function definitions = + ================================================================ +--> - <p>A <c>Timeout</c> argument specifies a time-out in milliseconds. The - default value for argument <c>Timeout</c> is <c>infinity</c>.</p> - </section> - <funcs> <func> - <name>append_cipher_suites(Deferred, Suites) -> ciphers() </name> + <name since="OTP 20.3">append_cipher_suites(Deferred, Suites) -> ciphers() </name> <fsummary></fsummary> <type> - <v>Deferred = ciphers() | cipher_filters() </v> - <v>Suites = ciphers() </v> + <v>Deferred = <seealso marker="#type-ciphers">ciphers()</seealso> | + <seealso marker="#type-cipher_filters">cipher_filters()</seealso></v> + <v>Suites = <seealso marker="#type-ciphers">ciphers()</seealso></v> </type> <desc><p>Make <c>Deferred</c> suites become the least preferred suites, that is put them at the end of the cipher suite list @@ -889,8 +1078,8 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>cipher_suites() -></name> - <name>cipher_suites(Type) -> old_ciphers()</name> + <name since="OTP R14B">cipher_suites() -></name> + <name since="OTP R14B">cipher_suites(Type) -> old_ciphers()</name> <fsummary>Returns a list of supported cipher suites.</fsummary> <type> <v>Type = erlang | openssl | all</v> @@ -901,12 +1090,12 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>cipher_suites(Supported, Version) -> ciphers()</name> + <name since="OTP 20.3">cipher_suites(Supported, Version) -> ciphers()</name> <fsummary>Returns a list of all default or all supported cipher suites.</fsummary> <type> <v> Supported = default | all | anonymous </v> - <v> Version = protocol_version() </v> + <v> Version = <seealso marker="#type-protocol_version">protocol_version() </seealso></v> </type> <desc><p>Returns all default or all supported (except anonymous), or all anonymous cipher suites for a @@ -915,10 +1104,16 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>eccs() -></name> - <name>eccs(protocol_version()) -> [named_curve()]</name> + <name since="OTP 19.2">eccs() -></name> + <name since="OTP 19.2">eccs(Version) -> NamedCurves</name> <fsummary>Returns a list of supported ECCs.</fsummary> + <type> + <v> Version = <seealso marker="#type-protocol_version">protocol_version() </seealso></v> + <v> NamedCurves = <seealso marker="#type-named_curve">[named_curve()] </seealso></v> + + </type> + <desc><p>Returns a list of supported ECCs. <c>eccs()</c> is equivalent to calling <c>eccs(Protocol)</c> with all supported protocols and then deduplicating the output.</p> @@ -926,7 +1121,7 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>clear_pem_cache() -> ok </name> + <name since="OTP 17.5">clear_pem_cache() -> ok </name> <fsummary> Clears the pem cache</fsummary> <desc><p>PEM files, used by ssl API-functions, are cached. The @@ -938,61 +1133,68 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>connect(Socket, SslOptions) -> </name> - <name>connect(Socket, SslOptions, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext} + <name since="OTP R14B">connect(Socket, Options) -> </name> + <name since="">connect(Socket, Options, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason}</name> <fsummary>Upgrades a <c>gen_tcp</c>, or equivalent, connected socket to an TLS socket.</fsummary> <type> - <v>Socket = socket()</v> - <v>SslOptions = [{handshake, hello| full} | ssl_option()]</v> - <v>Timeout = integer() | infinity</v> - <v>SslSocket = sslsocket()</v> + <v>Socket = <seealso marker="#type-socket"> socket() </seealso></v> + <v>Options = <seealso marker="#type-client_option"> [client_option()] </seealso></v> + <v>Timeout = timeout()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Ext = hello_extensions()</v> - <v>Reason = term()</v> + <v>Reason = closed | timeout | <seealso marker="#type-error_alert"> error_alert() </seealso></v> </type> <desc><p>Upgrades a <c>gen_tcp</c>, or equivalent, connected socket to an TLS socket, that is, performs the client-side TLS handshake.</p> - <note><p>If the option <c>verify</c> is set to <c>verify_peer</c> - the option <c>server_name_indication</c> shall also be specified, - if it is not no Server Name Indication extension will be sent, - and <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> - will be called with the IP-address of the connection as <c>ReferenceID</c>, which is proably not what you want.</p> + <note><p>If the option <c>verify</c> is set to + <c>verify_peer</c> the option <c>server_name_indication</c> + shall also be specified, if it is not no Server Name + Indication extension will be sent, and <seealso + marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> + will be called with the IP-address of the connection as + <c>ReferenceID</c>, which is proably not what you want.</p> </note> <p> If the option <c>{handshake, hello}</c> is used the handshake is paused after receiving the server hello message and the success response is <c>{ok, SslSocket, Ext}</c> - instead of <c>{ok, SslSocket}</c>. Thereafter the handshake is continued or - canceled by calling <seealso marker="#handshake_continue-3"> + instead of <c>{ok, SslSocket}</c>. Thereafter the handshake + is continued or canceled by calling <seealso + marker="#handshake_continue-3"> <c>handshake_continue/3</c></seealso> or <seealso - marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>. + marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>. </p> + <p> If the option <c>active</c> is set to <c>once</c> or <c>true</c> the + process owning the sslsocket will receive messages of type + <seealso marker="#type-active_msgs"> active_msgs() </seealso> + </p> </desc> </func> <func> - <name>connect(Host, Port, Options) -></name> - <name>connect(Host, Port, Options, Timeout) -> + <name since="">connect(Host, Port, Options) -></name> + <name since="">connect(Host, Port, Options, Timeout) -> {ok, SslSocket}| {ok, SslSocket, Ext} | {error, Reason}</name> <fsummary>Opens an TLS/DTLS connection to <c>Host</c>, <c>Port</c>.</fsummary> <type> - <v>Host = host()</v> - <v>Port = integer()</v> - <v>Options = [option()]</v> - <v>Timeout = integer() | infinity</v> - <v>SslSocket = sslsocket()</v> - <v>Reason = term()</v> + <v>Host =<seealso marker="#type-host"> host() </seealso> </v> + <v>Port = <seealso marker="kernel:inet#type-port_number">inet:port_number()</seealso></v> + <v>Options = <seealso marker="#type-client_option"> [client_option()]</seealso></v> + <v>Timeout = timeout()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> + <v>Reason = closed | timeout | <seealso marker="#type-error_alert"> error_alert() </seealso></v> </type> <desc><p>Opens an TLS/DTLS connection to <c>Host</c>, <c>Port</c>.</p> <p> When the option <c>verify</c> is set to <c>verify_peer</c> the check <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> will be performed in addition to the usual x509-path validation checks. If the check fails the error {bad_cert, hostname_check_failed} will - be propagated to the path validation fun <seealso marker="#verify_fun">verify_fun</seealso>, where it is possible to do customized + be propagated to the path validation fun <seealso marker="#type-custom_verify">verify_fun</seealso>, where it is possible to do customized checks by using the full possibilities of the <seealso marker="public_key:public_key#pkix_verify_hostname-3">public_key:pkix_verify_hostname/3</seealso> API. When the option <c>server_name_indication</c> is provided, its value (the DNS name) will be used as <c>ReferenceID</c> @@ -1014,14 +1216,19 @@ fun(srp, Username :: string(), UserState :: term()) -> <c>handshake_continue/3</c></seealso> or <seealso marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>. </p> + + <p> If the option <c>active</c> is set to <c>once</c> or <c>true</c> the + process owning the sslsocket will receive messages of type + <seealso marker="#type-active_msgs"> active_msgs() </seealso> + </p> </desc> </func> <func> - <name>close(SslSocket) -> ok | {error, Reason}</name> + <name since="">close(SslSocket) -> ok | {error, Reason}</name> <fsummary>Closes an TLS/DTLS connection.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Reason = term()</v> </type> <desc><p>Closes an TLS/DTLS connection.</p> @@ -1029,10 +1236,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>close(SslSocket, How) -> ok | {ok, port()} | {error, Reason}</name> + <name since="OTP 18.1">close(SslSocket, How) -> ok | {ok, port()} | {error, Reason}</name> <fsummary>Closes an TLS connection.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>How = timeout() | {NewController::pid(), timeout()} </v> <v>Reason = term()</v> </type> @@ -1044,12 +1251,12 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>controlling_process(SslSocket, NewOwner) -> + <name since="">controlling_process(SslSocket, NewOwner) -> ok | {error, Reason}</name> <fsummary>Assigns a new controlling process to the TLS/DTLS socket.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>NewOwner = pid()</v> <v>Reason = term()</v> </type> @@ -1060,12 +1267,12 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>connection_information(SslSocket) -> + <name since="OTP 18.0">connection_information(SslSocket) -> {ok, Result} | {error, Reason} </name> <fsummary>Returns all the connection information. </fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Item = protocol | selected_cipher_suite | sni_hostname | ecc | session_id | atom()</v> <d>Meaningful atoms, not specified above, are the ssl option names.</d> <v>Result = [{Item::atom(), Value::term()}]</v> @@ -1081,12 +1288,12 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>connection_information(SslSocket, Items) -> + <name since="OTP 18.0">connection_information(SslSocket, Items) -> {ok, Result} | {error, Reason} </name> <fsummary>Returns the requested connection information. </fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Items = [Item]</v> <v>Item = protocol | cipher_suite | sni_hostname | ecc | session_id | client_random | server_random | master_secret | atom()</v> @@ -1103,11 +1310,11 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>filter_cipher_suites(Suites, Filters) -> ciphers()</name> + <name since="OTP 20.3">filter_cipher_suites(Suites, Filters) -> ciphers()</name> <fsummary></fsummary> <type> - <v> Suites = ciphers()</v> - <v> Filters = cipher_filters()</v> + <v> Suites = <seealso marker="#type-ciphers"> ciphers() </seealso></v> + <v> Filters = <seealso marker="#type-cipher_filters"> cipher_filters() </seealso></v> </type> <desc><p>Removes cipher suites if any of the filter functions returns false for any part of the cipher suite. This function @@ -1118,7 +1325,7 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>format_error(Reason) -> string()</name> + <name since="">format_error(Reason) -> string()</name> <fsummary>Returns an error string.</fsummary> <type> <v>Reason = term()</v> @@ -1129,11 +1336,11 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>getopts(SslSocket, OptionNames) -> + <name since="">getopts(SslSocket, OptionNames) -> {ok, [socketoption()]} | {error, Reason}</name> <fsummary>Gets the values of the specified options.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>Socket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>OptionNames = [atom()]</v> </type> <desc> @@ -1143,13 +1350,13 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>getstat(SslSocket) -> + <name since="OTP 19.0">getstat(SslSocket) -> {ok, OptionValues} | {error, inet:posix()}</name> - <name>getstat(SslSocket, OptionNames) -> + <name since="OTP 19.0">getstat(SslSocket, OptionNames) -> {ok, OptionValues} | {error, inet:posix()}</name> <fsummary>Get one or more statistic options for a socket</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>OptionNames = [atom()]</v> <v>OptionValues = [{inet:stat_option(), integer()}]</v> </type> @@ -1160,31 +1367,36 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>handshake(HsSocket) -> </name> - <name>handshake(HsSocket, Timeout) -> {ok, SslSocket} | {error, Reason}</name> + <name since="OTP 21.0">handshake(HsSocket) -> </name> + <name since="OTP 21.0">handshake(HsSocket, Timeout) -> {ok, SslSocket} | {error, Reason}</name> <fsummary>Performs server-side SSL/TLS handshake.</fsummary> <type> - <v>HsSocket = SslSocket = sslsocket()</v> - <v>Timeout = integer()</v> - <v>Reason = term()</v> + <v>HsSocket = SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> + <v>Timeout = timeout()</v> + <v>Reason = closed | timeout | <seealso marker="#type-error_alert"> error_alert() </seealso></v> </type> <desc> <p>Performs the SSL/TLS/DTLS server-side handshake.</p> <p>Returns a new TLS/DTLS socket if the handshake is successful.</p> + + <p> If the option <c>active</c> is set to <c>once</c> or <c>true</c> the + process owning the sslsocket will receive messages of type + <seealso marker="#type-active_msgs"> active_msgs() </seealso> + </p> </desc> </func> <func> - <name>handshake(Socket, SslOptions) -> </name> - <name>handshake(Socket, SslOptions, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason}</name> + <name since="OTP 21.0">handshake(Socket, Options) -> </name> + <name since="OTP 21.0">handshake(Socket, Options, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason}</name> <fsummary>Performs server-side SSL/TLS/DTLS handshake.</fsummary> <type> - <v>Socket = socket() | sslsocket() </v> - <v>SslSocket = sslsocket() </v> + <v>Socket = socket() | <seealso marker="#type-sslsocket"> socket() </seealso> </v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso> </v> <v>Ext = hello_extensions()</v> - <v>SslOptions = [{handshake, hello| full} | ssl_option()]</v> - <v>Timeout = integer()</v> - <v>Reason = term()</v> + <v>Options = <seealso marker="#type-server_option"> [server_option()] </seealso> </v> + <v>Timeout = timeout()</v> + <v>Reason = closed | timeout | <seealso marker="#type-error_alert"> error_alert() </seealso></v> </type> <desc> <p>If <c>Socket</c> is a ordinary <c>socket()</c>: upgrades a <c>gen_tcp</c>, @@ -1196,7 +1408,8 @@ fun(srp, Username :: string(), UserState :: term()) -> is undefined. </p></warning> - <p>If <c>Socket</c> is an <c>sslsocket()</c>: provides extra SSL/TLS/DTLS + <p>If <c>Socket</c> is an + <seealso marker="#type-sslsocket"> sslsocket() </seealso>: provides extra SSL/TLS/DTLS options to those specified in <seealso marker="#listen-2">listen/2 </seealso> and then performs the SSL/TLS/DTLS handshake. Returns a new TLS/DTLS socket if the handshake is successful.</p> @@ -1210,14 +1423,20 @@ fun(srp, Username :: string(), UserState :: term()) -> <c>handshake_continue/3</c></seealso> or <seealso marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>. </p> + + <p> If the option <c>active</c> is set to <c>once</c> or <c>true</c> the + process owning the sslsocket will receive messages of type + <seealso marker="#type-active_msgs"> active_msgs() </seealso> + </p> + </desc> </func> <func> - <name>handshake_cancel(SslSocket) -> ok </name> + <name since="OTP 21.0">handshake_cancel(SslSocket) -> ok </name> <fsummary>Cancel handshake with a fatal alert</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> </type> <desc> <p>Cancel the handshake with a fatal <c>USER_CANCELED</c> alert.</p> @@ -1225,14 +1444,14 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>handshake_continue(HsSocket, SSLOptions) -> {ok, SslSocket} | {error, Reason}</name> - <name>handshake_continue(HsSocket, SSLOptions, Timeout) -> {ok, SslSocket} | {error, Reason}</name> + <name since="OTP 21.0">handshake_continue(HsSocket, Options) -> {ok, SslSocket} | {error, Reason}</name> + <name since="OTP 21.0">handshake_continue(HsSocket, Options, Timeout) -> {ok, SslSocket} | {error, Reason}</name> <fsummary>Continue the SSL/TLS handshake.</fsummary> <type> - <v>HsSocket = SslSocket = sslsocket()</v> - <v>SslOptions = [ssl_option()]</v> - <v>Timeout = integer()</v> - <v>Reason = term()</v> + <v>HsSocket = SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> + <v>Options = <seealso marker="#type-tls_option"> tls_option() </seealso> </v> + <v>Timeout = timeout()</v> + <v>Reason = closed | timeout | <seealso marker="#type-error_alert"> error_alert() </seealso></v> </type> <desc> <p>Continue the SSL/TLS handshake possiby with new, additional or changed options.</p> @@ -1240,13 +1459,13 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>listen(Port, Options) -> + <name since="">listen(Port, Options) -> {ok, ListenSocket} | {error, Reason}</name> <fsummary>Creates an SSL listen socket.</fsummary> <type> - <v>Port = integer()</v> - <v>Options = options()</v> - <v>ListenSocket = sslsocket()</v> + <v>Port = <seealso marker="kernel:inet#type-port_number">inet:port_number()</seealso></v> + <v>Options = <seealso marker="#type-server_option"> [server_option()] </seealso></v> + <v>ListenSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> </type> <desc> <p>Creates an SSL listen socket.</p> @@ -1254,10 +1473,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>negotiated_protocol(SslSocket) -> {ok, Protocol} | {error, protocol_not_negotiated}</name> + <name since="OTP 18.0">negotiated_protocol(SslSocket) -> {ok, Protocol} | {error, protocol_not_negotiated}</name> <fsummary>Returns the protocol negotiated through ALPN or NPN extensions.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Protocol = binary()</v> </type> <desc> @@ -1268,10 +1487,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>peercert(SslSocket) -> {ok, Cert} | {error, Reason}</name> + <name since="">peercert(SslSocket) -> {ok, Cert} | {error, Reason}</name> <fsummary>Returns the peer certificate.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Cert = binary()</v> </type> <desc> @@ -1283,13 +1502,13 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>peername(SslSocket) -> {ok, {Address, Port}} | + <name since="">peername(SslSocket) -> {ok, {Address, Port}} | {error, Reason}</name> <fsummary>Returns the peer address and port.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Address = ipaddress()</v> - <v>Port = integer()</v> + <v>Port = <seealso marker="kernel:inet#type-port_number">inet:port_number()</seealso></v> </type> <desc> <p>Returns the address and port number of the peer.</p> @@ -1297,11 +1516,12 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>prepend_cipher_suites(Preferred, Suites) -> ciphers()</name> + <name since="OTP 20.3">prepend_cipher_suites(Preferred, Suites) -> ciphers()</name> <fsummary></fsummary> <type> - <v>Preferred = ciphers() | cipher_filters() </v> - <v>Suites = ciphers() </v> + <v>Preferred = <seealso marker="#type-ciphers">ciphers()</seealso> | + <seealso marker="#type-cipher_filters">cipher_filters()</seealso></v> + <v>Suites = <seealso marker="#type-ciphers">ciphers()</seealso></v> </type> <desc><p>Make <c>Preferred</c> suites become the most preferred suites that is put them at the head of the cipher suite list @@ -1313,10 +1533,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>prf(Socket, Secret, Label, Seed, WantedLength) -> {ok, binary()} | {error, reason()}</name> + <name since="OTP R15B01">prf(Socket, Secret, Label, Seed, WantedLength) -> {ok, binary()} | {error, reason()}</name> <fsummary>Uses a session Pseudo-Random Function to generate key material.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>Socket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Secret = binary() | master_secret</v> <v>Label = binary()</v> <v>Seed = [binary() | prf_random()]</v> @@ -1333,14 +1553,14 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>recv(SslSocket, Length) -> </name> - <name>recv(SslSocket, Length, Timeout) -> {ok, Data} | {error, + <name since="">recv(SslSocket, Length) -> </name> + <name since="">recv(SslSocket, Length, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Receives data on a socket.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Length = integer()</v> - <v>Timeout = integer()</v> + <v>Timeout = timeout()</v> <v>Data = [char()] | binary()</v> </type> <desc> @@ -1360,10 +1580,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>renegotiate(SslSocket) -> ok | {error, Reason}</name> + <name since="OTP R14B">renegotiate(SslSocket) -> ok | {error, Reason}</name> <fsummary>Initiates a new handshake.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> </type> <desc><p>Initiates a new handshake. A notable return value is <c>{error, renegotiation_rejected}</c> indicating that the peer @@ -1373,10 +1593,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>send(SslSocket, Data) -> ok | {error, Reason}</name> + <name since="">send(SslSocket, Data) -> ok | {error, Reason}</name> <fsummary>Writes data to a socket.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>Data = iodata()</v> </type> <desc> @@ -1387,11 +1607,11 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>setopts(SslSocket, Options) -> ok | {error, Reason}</name> + <name since="">setopts(SslSocket, Options) -> ok | {error, Reason}</name> <fsummary>Sets socket options.</fsummary> <type> - <v>SslSocket = sslsocket()</v> - <v>Options = [socketoption]()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> + <v>Options = <seealso marker="#type-socket_option"> [socket_option()] </seealso></v> </type> <desc> <p>Sets options according to <c>Options</c> for socket @@ -1400,10 +1620,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>shutdown(SslSocket, How) -> ok | {error, Reason}</name> + <name since="OTP R14B">shutdown(SslSocket, How) -> ok | {error, Reason}</name> <fsummary>Immediately closes a socket.</fsummary> <type> - <v>SslSocket = sslsocket()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> <v>How = read | write | read_write</v> <v>Reason = reason()</v> </type> @@ -1418,13 +1638,13 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>ssl_accept(SslSocket) -> </name> - <name>ssl_accept(SslSocket, Timeout) -> ok | {error, Reason}</name> + <name since="">ssl_accept(SslSocket) -> </name> + <name since="">ssl_accept(SslSocket, Timeout) -> ok | {error, Reason}</name> <fsummary>Performs server-side SSL/TLS handshake.</fsummary> <type> - <v>SslSocket = sslsocket()</v> - <v>Timeout = integer()</v> - <v>Reason = term()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> + <v>Timeout = timeout()</v> + <v>Reason = closed | timeout | <seealso marker="#type-error_alert"> error_alert() </seealso></v> </type> <desc> <p>Deprecated in OTP 21, use <seealso marker="#handshake-1">handshake/[1,2]</seealso> instead.</p> @@ -1433,14 +1653,14 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>ssl_accept(Socket, SslOptions) -> </name> - <name>ssl_accept(Socket, SslOptions, Timeout) -> {ok, Socket} | ok | {error, Reason}</name> + <name since="">ssl_accept(Socket, Options) -> </name> + <name since="OTP R14B">ssl_accept(Socket, Options, Timeout) -> {ok, Socket} | ok | {error, Reason}</name> <fsummary>Performs server-side SSL/TLS/DTLS handshake.</fsummary> <type> - <v>Socket = socket() | sslsocket() </v> - <v>SslOptions = [ssl_option()]</v> - <v>Timeout = integer()</v> - <v>Reason = term()</v> + <v>Socket = socket() | <seealso marker="#type-sslsocket"> sslsocket() </seealso> </v> + <v>Options = <seealso marker="#type-server_option"> [server_option()] </seealso> </v> + <v>Timeout = timeout()</v> + <v>Reason = closed | timeout | <seealso marker="#type-error_alert"> error_alert() </seealso></v> </type> <desc> <p>Deprecated in OTP 21, use <seealso marker="#handshake-3">handshake/[2,3]</seealso> instead.</p> @@ -1449,13 +1669,13 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>sockname(SslSocket) -> {ok, {Address, Port}} | + <name since="">sockname(SslSocket) -> {ok, {Address, Port}} | {error, Reason}</name> <fsummary>Returns the local address and port.</fsummary> <type> - <v>SslSocket = sslsocket()</v> - <v>Address = ipaddress()</v> - <v>Port = integer()</v> + <v>SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> + <v>Address = <seealso marker="#type-ip_address">ip_address()</seealso></v> + <v>Port = <seealso marker="kernel:inet#type-port_number">inet:port_number()</seealso></v> </type> <desc> <p>Returns the local address and port number of socket @@ -1464,8 +1684,8 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>start() -> </name> - <name>start(Type) -> ok | {error, Reason}</name> + <name since="OTP R14B">start() -> </name> + <name since="OTP R14B">start(Type) -> ok | {error, Reason}</name> <fsummary>Starts the SSL application.</fsummary> <type> <v>Type = permanent | transient | temporary</v> @@ -1477,7 +1697,7 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>stop() -> ok </name> + <name since="OTP R14B">stop() -> ok </name> <fsummary>Stops the SSL application.</fsummary> <desc> <p>Stops the SSL application.</p> @@ -1485,10 +1705,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>suite_to_str(CipherSuite) -> String</name> + <name since="OTP 21.0">suite_to_str(CipherSuite) -> String</name> <fsummary>Returns the string representation of a cipher suite.</fsummary> <type> - <v>CipherSuite = erl_cipher_suite()</v> + <v>CipherSuite = <seealso marker="#type-erl_cipher_suite"> erl_cipher_suite() </seealso></v> <v>String = string()</v> </type> <desc> @@ -1497,14 +1717,14 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>transport_accept(ListenSocket) -></name> - <name>transport_accept(ListenSocket, Timeout) -> + <name since="">transport_accept(ListenSocket) -></name> + <name since="">transport_accept(ListenSocket, Timeout) -> {ok, SslSocket} | {error, Reason}</name> <fsummary>Accepts an incoming connection and prepares for <c>ssl_accept</c>.</fsummary> <type> - <v>ListenSocket = SslSocket = sslsocket()</v> - <v>Timeout = integer()</v> + <v>ListenSocket = SslSocket = <seealso marker="#type-sslsocket"> sslsocket() </seealso></v> + <v>Timeout = timeout()</v> <v>Reason = reason()</v> </type> <desc> @@ -1532,7 +1752,7 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>versions() -> [versions_info()]</name> + <name since="OTP R14B">versions() -> [versions_info()]</name> <fsummary>Returns version information relevant for the SSL application.</fsummary> <type> diff --git a/lib/ssl/doc/src/ssl_crl_cache.xml b/lib/ssl/doc/src/ssl_crl_cache.xml index 71c6d5e49e..a33aec62a7 100644 --- a/lib/ssl/doc/src/ssl_crl_cache.xml +++ b/lib/ssl/doc/src/ssl_crl_cache.xml @@ -24,7 +24,7 @@ <file>ssl_crl_cache.xml</file> </header> - <module>ssl_crl_cache</module> + <module since="OTP 18.0">ssl_crl_cache</module> <modulesummary>CRL cache </modulesummary> <description> <p> @@ -34,32 +34,43 @@ the following functions are available. </p> </description> + + <datatypes> + <datatype_title>DATA TYPES</datatype_title> + + <datatype> + <name name="crl_src"/> + </datatype> + + <datatype> + <name name="uri"/> + </datatype> + + </datatypes> <funcs> <func> - <name>delete(Entries) -> ok | {error, Reason} </name> + <name since="OTP 18.0">delete(Entries) -> ok | {error, Reason} </name> <fsummary> </fsummary> <type> - <v> Entries = <seealso marker="stdlib:uri_string">uri_string:uri_string()</seealso> | {file, string()} | {der, [<seealso - marker="public_key:public_key"> public_key:der_encoded() </seealso>]}</v> - <v> Reason = term()</v> + <v> Entries = <seealso marker="#type-crl_src">crl_src()</seealso>]}</v> + <v> Reason = crl_reason()</v> </type> <desc> <p>Delete CRLs from the ssl applications local cache. </p> </desc> </func> <func> - <name>insert(CRLSrc) -> ok | {error, Reason}</name> - <name>insert(URI, CRLSrc) -> ok | {error, Reason}</name> + <name since="OTP 18.0">insert(CRLSrc) -> ok | {error, Reason}</name> + <name since="OTP 18.0">insert(URI, CRLSrc) -> ok | {error, Reason}</name> <fsummary> </fsummary> <type> - <v> CRLSrc = {file, string()} | {der, [ <seealso - marker="public_key:public_key"> public_key:der_encoded() </seealso> ]}</v> - <v> URI = <seealso marker="stdlib:uri_string">uri_string:uri_string() </seealso> </v> + <v> CRLSrc = <seealso marker="#type-crl_src">crl_src()</seealso>]}</v> + <v> URI = <seealso marker="#type-uri">uri()</seealso> </v> <v> Reason = term()</v> </type> <desc> - <p>Insert CRLs into the ssl applications local cache. </p> + <p>Insert CRLs, available to fetch on DER format from <c>URI</c>, into the ssl applications local cache. </p> </desc> </func> </funcs> diff --git a/lib/ssl/doc/src/ssl_crl_cache_api.xml b/lib/ssl/doc/src/ssl_crl_cache_api.xml index c6774b4df6..4cba4e1de1 100644 --- a/lib/ssl/doc/src/ssl_crl_cache_api.xml +++ b/lib/ssl/doc/src/ssl_crl_cache_api.xml @@ -24,7 +24,7 @@ <file>ssl_crl_cache_api.xml</file> </header> - <module>ssl_crl_cache_api</module> + <module since="OTP 18.0">ssl_crl_cache_api</module> <modulesummary>API for a SSL/TLS CRL (Certificate Revocation List) cache.</modulesummary> <description> <p> @@ -39,35 +39,44 @@ a CRL cache. </p> </description> - - <section> - <title>DATA TYPES</title> - - <p>The following data types are used in the functions below: - </p> - - <taglist> - - <tag><c>cache_ref() =</c></tag> - <item>opaque()</item> - <tag><c>dist_point() =</c></tag> - <item><p>#'DistributionPoint'{} see <seealso - marker="public_key:public_key_records"> X509 certificates records</seealso></p></item> - - </taglist> + + + <!-- + ================================================================ + = Data types = + ================================================================ + --> + + <datatypes> - </section> + <datatype> + <name name="crl_cache_ref"/> + <desc> + <p>Reference to the CRL cache.</p> + </desc> + </datatype> + + + <datatype> + <name name="dist_point"/> + <desc> + <p>For description see <seealso + marker="public_key:public_key_records"> X509 certificates records</seealso></p> + </desc> + </datatype> + </datatypes> + <funcs> <func> - <name>fresh_crl(DistributionPoint, CRL) -> FreshCRL</name> + <name since="OTP 18.0">fresh_crl(DistributionPoint, CRL) -> FreshCRL</name> <fsummary> <c>fun fresh_crl/2 </c> will be used as input option <c>update_crl</c> to public_key:pkix_crls_validate/3 </fsummary> <type> - <v> DistributionPoint = dist_point() </v> + <v> DistributionPoint = <seealso marker="#type-dist_point"> dist_point() </seealso> </v> <v> CRL = [<seealso - marker="public_key:public_key">public_key:der_encoded()</seealso>] </v> + marker="public_key:public_key#type-der_encoded">public_key:der_encoded()</seealso>] </v> <v> FreshCRL = [<seealso - marker="public_key:public_key">public_key:der_encoded()</seealso>] </v> + marker="public_key:public_key#type-der_encoded">public_key:der_encoded()</seealso>] </v> </type> <desc> <p> <c>fun fresh_crl/2 </c> will be used as input option <c>update_crl</c> to @@ -76,16 +85,16 @@ </func> <func> - <name>lookup(DistributionPoint, Issuer, DbHandle) -> not_available | CRLs </name> - <name>lookup(DistributionPoint, DbHandle) -> not_available | CRLs </name> + <name since="OTP 19.0">lookup(DistributionPoint, Issuer, DbHandle) -> not_available | CRLs </name> + <name since="OTP 18.0">lookup(DistributionPoint, DbHandle) -> not_available | CRLs </name> <fsummary> </fsummary> <type> - <v> DistributionPoint = dist_point() </v> + <v> DistributionPoint = <seealso marker="#type-dist_point"> dist_point() </seealso> </v> <v> Issuer = <seealso - marker="public_key:public_key">public_key:issuer_name()</seealso> </v> - <v> DbHandle = cache_ref() </v> + marker="public_key:public_key#type-issuer_name">public_key:issuer_name()</seealso> </v> + <v> DbHandle = <seealso marker="#type-crl_cache_ref"> crl_cache_ref() </seealso></v> <v> CRLs = [<seealso - marker="public_key:public_key">public_key:der_encoded()</seealso>] </v> + marker="public_key:public_key#type-der_encoded">public_key:der_encoded()</seealso>] </v> </type> <desc> <p>Lookup the CRLs belonging to the distribution point <c> Distributionpoint</c>. This function may choose to only look in the cache or to follow distribution point @@ -106,12 +115,12 @@ </func> <func> - <name>select(Issuer, DbHandle) -> CRLs </name> + <name since="OTP 18.0">select(Issuer, DbHandle) -> CRLs </name> <fsummary>Select the CRLs in the cache that are issued by <c>Issuer</c></fsummary> <type> <v> Issuer = <seealso - marker="public_key:public_key">public_key:issuer_name()</seealso></v> - <v> DbHandle = cache_ref() </v> + marker="public_key:public_key#type-issuer_name">public_key:issuer_name()</seealso></v> + <v> DbHandle = <seealso marker="#type-crl_cache_ref"> cache_ref() </seealso></v> </type> <desc> <p>Select the CRLs in the cache that are issued by <c>Issuer</c> </p> diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml index a84a3dfce9..e841729e57 100644 --- a/lib/ssl/doc/src/ssl_session_cache_api.xml +++ b/lib/ssl/doc/src/ssl_session_cache_api.xml @@ -28,7 +28,7 @@ <rev></rev> <file>ssl_session_cache_api.xml</file> </header> - <module>ssl_session_cache_api</module> + <module since="OTP R14B">ssl_session_cache_api</module> <modulesummary>TLS session cache API</modulesummary> <description> @@ -38,39 +38,50 @@ defining a new callback module implementing this API. </p> </description> - <section> - <title>DATA TYPES</title> - <p>The following data types are used in the functions for - <c>ssl_session_cache_api</c>:</p> - - <taglist> - <tag><c>cache_ref() =</c></tag> - <item><p><c>opaque()</c></p></item> - - <tag><c>key() =</c></tag> - <item><p><c>{partialkey(), session_id()}</c></p></item> - - <tag><c>partialkey() =</c></tag> - <item><p><c>opaque()</c></p></item> - - <tag><c>session_id() =</c></tag> - <item><p><c>binary()</c></p></item> - - <tag><c>session()</c> =</tag> - <item><p><c>opaque()</c></p></item> - </taglist> - - </section> + <!-- + ================================================================ + = Data types = + ================================================================ + --> + + <datatypes> + + <datatype> + <name name="session_cache_ref"/> + </datatype> + + <datatype> + <name name="session_cache_key"/> + <desc> + <p>A key to an entry in the session cache.</p> + </desc> + </datatype> + + <datatype> + <name name="partial_key"/> + <desc> + <p>The opaque part of the key. Does not need to be handled + by the callback.</p> + </desc> + </datatype> + + <datatype> + <name name="session"/> + <desc> + <p>The session data that is stored for each session.</p> + </desc> + </datatype> + </datatypes> <funcs> <func> - <name>delete(Cache, Key) -> _</name> + <name since="OTP R14B">delete(Cache, Key) -> _</name> <fsummary>Deletes a cache entry.</fsummary> <type> - <v>Cache = cache_ref()</v> - <v>Key = key()</v> + <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v> + <v>Key = <seealso marker="#type-session_cache_key">session_cache_key() </seealso> </v> </type> <desc> <p>Deletes a cache entry. Is only called from the cache @@ -80,10 +91,12 @@ </func> <func> - <name>foldl(Fun, Acc0, Cache) -> Acc</name> + <name since="OTP R14B">foldl(Fun, Acc0, Cache) -> Acc</name> <fsummary></fsummary> <type> - <v></v> + <v>Fun = fun()</v> + <v>Acc0 = Acc = term()</v> + <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v> </type> <desc> <p>Calls <c>Fun(Elem, AccIn)</c> on successive elements of the @@ -96,10 +109,11 @@ </func> <func> - <name>init(Args) -> opaque() </name> + <name since="OTP 18.0">init(Args) -> Cache </name> <fsummary>Returns cache reference.</fsummary> <type> - <v>Args = proplists:proplist()</v> + <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v> + <v>Args = <seealso marker="stdlib:proplists#type-proplist">proplists:proplist()</seealso></v> </type> <desc> <p>Includes property <c>{role, client | server}</c>. @@ -121,12 +135,12 @@ </func> <func> - <name>lookup(Cache, Key) -> Entry</name> + <name since="OTP R14B">lookup(Cache, Key) -> Entry</name> <fsummary>Looks up a cache entry.</fsummary> <type> - <v>Cache = cache_ref()</v> - <v>Key = key()</v> - <v>Entry = session() | undefined</v> + <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v> + <v>Key = <seealso marker="#type-session_cache_key">session_cache_key()</seealso> </v> + <v>Session = <seealso marker="#type-session">session()</seealso> | undefined</v> </type> <desc> <p>Looks up a cache entry. Is to be callable from any @@ -136,12 +150,12 @@ </func> <func> - <name>select_session(Cache, PartialKey) -> [session()]</name> + <name since="OTP R14B">select_session(Cache, PartialKey) -> [Session]</name> <fsummary>Selects sessions that can be reused.</fsummary> <type> - <v>Cache = cache_ref()</v> - <v>PartialKey = partialkey()</v> - <v>Session = session()</v> + <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v> + <v>PartialKey = <seealso marker="#type-partial_key"> partial_key() </seealso></v> + <v>Session = <seealso marker="#type-session">session()</seealso></v> </type> <desc> <p>Selects sessions that can be reused. Is to be callable @@ -151,10 +165,10 @@ </func> <func> - <name>size(Cache) -> integer()</name> + <name since="OTP 19.3">size(Cache) -> integer()</name> <fsummary>Returns the number of sessions in the cache.</fsummary> <type> - <v>Cache = cache_ref()</v> + <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v> </type> <desc> <p>Returns the number of sessions in the cache. If size @@ -166,11 +180,12 @@ </func> <func> - <name>terminate(Cache) -> _</name> + <name since="OTP R14B">terminate(Cache) -> _</name> <fsummary>Called by the process that handles the cache when it is about to terminate.</fsummary> <type> - <v>Cache = term() - as returned by init/0</v> + <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v> + <d>As returned by init/0</d> </type> <desc> <p>Takes care of possible cleanup that is needed when the @@ -180,12 +195,12 @@ </func> <func> - <name>update(Cache, Key, Session) -> _</name> + <name since="OTP R14B">update(Cache, Key, Session) -> _</name> <fsummary>Caches a new session or updates an already cached one.</fsummary> <type> - <v>Cache = cache_ref()</v> - <v>Key = key()</v> - <v>Session = session()</v> + <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v> + <v>Key = <seealso marker="#type-session_cache_key">session_cache_key()</seealso> </v> + <v>Session = <seealso marker="#type-session">session()</seealso></v> </type> <desc> <p>Caches a new session or updates an already cached one. Is diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 37719ad439..70dae4c677 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -39,7 +39,7 @@ -export([start_fsm/8, start_link/7, init/1, pids/1]). %% State transition handling --export([next_event/3, next_event/4, handle_common_event/4]). +-export([next_event/3, next_event/4, handle_protocol_record/3]). %% Handshake handling -export([renegotiate/2, send_handshake/2, @@ -80,7 +80,7 @@ start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_, Tracker} end. %%-------------------------------------------------------------------- --spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) -> +-spec start_link(atom(), ssl:host(), inet:port_number(), port(), list(), pid(), tuple()) -> {ok, pid()} | ignore | {error, reason()}. %% %% Description: Creates a gen_statem process which calls Module:init/1 to @@ -107,9 +107,11 @@ pids(_) -> %%==================================================================== %% State transition handling %%==================================================================== -next_record(#state{unprocessed_handshake_events = N} = State) when N > 0 -> - {no_record, State#state{unprocessed_handshake_events = N-1}}; - +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{dtls_cipher_texts = [#ssl_tls{epoch = Epoch} = CT | Rest]} = Buffers, @@ -141,14 +143,14 @@ next_record(#state{protocol_buffers = next_record(State#state{protocol_buffers = Buffers#protocol_buffers{dtls_cipher_texts = Rest}, connection_states = ConnectionStates}); -next_record(#state{role = server, - socket = {Listener, {Client, _}}} = State) -> +next_record(#state{static_env = #static_env{role = server, + socket = {Listener, {Client, _}}}} = State) -> dtls_packet_demux:active_once(Listener, Client, self()), {no_record, State}; -next_record(#state{role = client, - socket = {_Server, Socket} = DTLSSocket, - close_tag = CloseTag, - transport_cb = Transport} = State) -> +next_record(#state{static_env = #static_env{role = client, + socket = {_Server, Socket} = DTLSSocket, + close_tag = CloseTag, + transport_cb = Transport}} = State) -> case dtls_socket:setopts(Transport, Socket, [{active,once}]) of ok -> {no_record, State}; @@ -234,36 +236,43 @@ next_event(StateName, Record, {next_state, StateName, State0, [{next_event, internal, Alert} | Actions]} end. -handle_common_event(internal, #alert{} = Alert, StateName, - #state{negotiated_version = Version} = State) -> - handle_own_alert(Alert, Version, StateName, State); +%%% DTLS record protocol level application data messages + +handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName0, State0) -> + case ssl_connection:read_application_data(Data, State0) of + {stop, _, _} = Stop-> + Stop; + {Record, State1} -> + {next_state, StateName, State, Actions} = next_event(StateName0, Record, State1), + ssl_connection:hibernate_after(StateName, State, Actions) + end; %%% DTLS record protocol level handshake messages -handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE, +handle_protocol_record(#ssl_tls{type = ?HANDSHAKE, fragment = Data}, StateName, #state{protocol_buffers = Buffers0, - negotiated_version = Version} = State0) -> + negotiated_version = Version} = State) -> try case dtls_handshake:get_dtls_handshake(Version, Data, Buffers0) of {[], Buffers} -> - next_event(StateName, no_record, State0#state{protocol_buffers = Buffers}); + next_event(StateName, no_record, State#state{protocol_buffers = Buffers}); {Packets, Buffers} -> - State = State0#state{protocol_buffers = Buffers}, + HsEnv = State#state.handshake_env, Events = dtls_handshake_events(Packets), {next_state, StateName, - State#state{unprocessed_handshake_events = unprocessed_events(Events)}, Events} + State#state{protocol_buffers = Buffers, + handshake_env = + HsEnv#handshake_env{unprocessed_handshake_events + = unprocessed_events(Events)}}, Events} end catch throw:#alert{} = Alert -> - handle_own_alert(Alert, Version, StateName, State0) + handle_own_alert(Alert, Version, StateName, State) end; -%%% DTLS record protocol level application data messages -handle_common_event(internal, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State) -> - {next_state, StateName, State, [{next_event, internal, {application_data, Data}}]}; %%% DTLS record protocol level change cipher messages -handle_common_event(internal, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) -> +handle_protocol_record(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) -> {next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]}; %%% DTLS record protocol level Alert messages -handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName, +handle_protocol_record(#ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName, #state{negotiated_version = Version} = State) -> case decode_alerts(EncAlerts) of Alerts = [_|_] -> @@ -272,18 +281,20 @@ handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, Sta handle_own_alert(Alert, Version, StateName, State) end; %% Ignore unknown TLS record level protocol messages -handle_common_event(internal, #ssl_tls{type = _Unknown}, StateName, State) -> - {next_state, StateName, State}. +handle_protocol_record(#ssl_tls{type = _Unknown}, StateName, State) -> + {next_state, StateName, State, []}. %%==================================================================== %% Handshake handling %%==================================================================== -renegotiate(#state{role = client} = State, Actions) -> +renegotiate(#state{static_env = #static_env{role = client}} = State, Actions) -> %% Handle same way as if server requested %% the renegotiation - next_event(connection, no_record, State, [{next_event, internal, #hello_request{}} | Actions]); -renegotiate(#state{role = server} = State0, Actions) -> + {next_state, connection, State, + [{next_event, internal, #hello_request{}} | Actions]}; + +renegotiate(#state{static_env = #static_env{role = server}} = State0, Actions) -> HelloRequest = ssl_handshake:hello_request(), State1 = prepare_flight(State0), {State, MoreActions} = send_handshake(HelloRequest, State1), @@ -293,7 +304,7 @@ send_handshake(Handshake, #state{connection_states = ConnectionStates} = State) #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write), send_handshake_flight(queue_handshake(Handshake, State), Epoch). -queue_handshake(Handshake0, #state{tls_handshake_history = Hist0, +queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv, negotiated_version = Version, flight_buffer = #{handshakes := HsBuffer0, change_cipher_spec := undefined, @@ -302,9 +313,9 @@ queue_handshake(Handshake0, #state{tls_handshake_history = Hist0, Hist = update_handshake_history(Handshake0, Handshake, Hist0), State#state{flight_buffer = Flight0#{handshakes => [Handshake | HsBuffer0], next_sequence => Seq +1}, - tls_handshake_history = Hist}; + handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}; -queue_handshake(Handshake0, #state{tls_handshake_history = Hist0, +queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv, negotiated_version = Version, flight_buffer = #{handshakes_after_change_cipher_spec := Buffer0, next_sequence := Seq} = Flight0} = State) -> @@ -312,7 +323,7 @@ queue_handshake(Handshake0, #state{tls_handshake_history = Hist0, Hist = update_handshake_history(Handshake0, Handshake, Hist0), State#state{flight_buffer = Flight0#{handshakes_after_change_cipher_spec => [Handshake | Buffer0], next_sequence => Seq +1}, - tls_handshake_history = Hist}. + handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}. queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight, connection_states = ConnectionStates0} = State) -> @@ -324,10 +335,11 @@ queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight, reinit(State) -> %% To be API compatible with TLS NOOP here reinit_handshake_data(State). -reinit_handshake_data(#state{protocol_buffers = Buffers} = State) -> +reinit_handshake_data(#state{protocol_buffers = Buffers, + handshake_env = HsEnv} = State) -> State#state{premaster_secret = undefined, public_key_info = undefined, - tls_handshake_history = ssl_handshake:init_handshake_history(), + handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history()}, flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}, flight_buffer = new_flight(), protocol_buffers = @@ -353,8 +365,8 @@ encode_alert(#alert{} = Alert, Version, ConnectionStates) -> dtls_record:encode_alert_record(Alert, Version, ConnectionStates). send_alert(Alert, #state{negotiated_version = Version, - socket = Socket, - transport_cb = Transport, + static_env = #static_env{socket = Socket, + transport_cb = Transport}, connection_states = ConnectionStates0} = State0) -> {BinMsg, ConnectionStates} = encode_alert(Alert, Version, ConnectionStates0), @@ -406,13 +418,15 @@ getopts(Transport, Socket, Tag) -> init(enter, _, State) -> {keep_state, State}; init({call, From}, {start, Timeout}, - #state{host = Host, port = Port, role = client, + #state{static_env = #static_env{host = Host, + port = Port, + role = client, + session_cache = Cache, + session_cache_cb = CacheCb}, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, ssl_options = SslOpts, session = #session{own_certificate = Cert} = Session0, - connection_states = ConnectionStates0, - renegotiation = {Renegotiation, _}, - session_cache = Cache, - session_cache_cb = CacheCb + connection_states = ConnectionStates0 } = State0) -> Timer = ssl_connection:start_or_recv_cancel_timer(Timeout, From), Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, @@ -422,15 +436,17 @@ init({call, From}, {start, Timeout}, HelloVersion = dtls_record:hello_version(Version, SslOpts#ssl_options.versions), State1 = prepare_flight(State0#state{negotiated_version = Version}), {State2, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}), - State = State2#state{negotiated_version = Version, %% Requested version - session = - Session0#session{session_id = Hello#client_hello.session_id}, - start_or_recv_from = From, - timer = Timer, - flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT} - }, - next_event(hello, no_record, State, Actions); -init({call, _} = Type, Event, #state{role = server, data_tag = udp} = State) -> + State3 = State2#state{negotiated_version = Version, %% Requested version + session = + Session0#session{session_id = Hello#client_hello.session_id}, + start_or_recv_from = From, + timer = Timer, + flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT} + }, + {Record, State} = next_record(State3), + next_event(hello, Record, State, Actions); +init({call, _} = Type, Event, #state{static_env = #static_env{role = server, + data_tag = udp}} = State) -> Result = gen_handshake(?FUNCTION_NAME, Type, Event, State#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}, protocol_specific = #{current_cookie_secret => dtls_v1:cookie_secret(), @@ -439,7 +455,7 @@ init({call, _} = Type, Event, #state{role = server, data_tag = udp} = State) -> max_ignored_alerts => 10}}), erlang:send_after(dtls_v1:cookie_timeout(), self(), new_cookie_secret), Result; -init({call, _} = Type, Event, #state{role = server} = State) -> +init({call, _} = Type, Event, #state{static_env = #static_env{role = server}} = State) -> %% I.E. DTLS over sctp gen_handshake(?FUNCTION_NAME, Type, Event, State#state{flight_state = reliable}); init(Type, Event, State) -> @@ -454,8 +470,8 @@ error(enter, _, State) -> {keep_state, State}; error({call, From}, {start, _Timeout}, #state{protocol_specific = #{error := Error}} = State) -> - ssl_connection:stop_and_reply( - normal, {reply, From, {error, Error}}, State); + {stop_and_reply, {shutdown, normal}, + [{reply, From, {error, Error}}], State}; error({call, _} = Call, Msg, State) -> gen_handshake(?FUNCTION_NAME, Call, Msg, State); error(_, _, _) -> @@ -467,16 +483,17 @@ error(_, _, _) -> #state{}) -> gen_statem:state_function_result(). %%-------------------------------------------------------------------- -hello(enter, _, #state{role = server} = State) -> +hello(enter, _, #state{static_env = #static_env{role = server}} = State) -> {keep_state, State}; -hello(enter, _, #state{role = client} = State0) -> +hello(enter, _, #state{static_env = #static_env{role = client}} = State0) -> {State, Actions} = handle_flight_timer(State0), {keep_state, State, Actions}; hello(internal, #client_hello{cookie = <<>>, client_version = Version} = Hello, - #state{role = server, - transport_cb = Transport, - socket = Socket, + #state{static_env = #static_env{role = server, + transport_cb = Transport, + socket = Socket}, + handshake_env = HsEnv, protocol_specific = #{current_cookie_secret := Secret}} = State0) -> {ok, {IP, Port}} = dtls_socket:peername(Transport, Socket), Cookie = dtls_handshake:cookie(Secret, IP, Port, Hello), @@ -488,25 +505,32 @@ hello(internal, #client_hello{cookie = <<>>, %% negotiated. VerifyRequest = dtls_handshake:hello_verify_request(Cookie, ?HELLO_VERIFY_REQUEST_VERSION), State1 = prepare_flight(State0#state{negotiated_version = Version}), - {State, Actions} = send_handshake(VerifyRequest, State1), - next_event(?FUNCTION_NAME, no_record, - State#state{tls_handshake_history = ssl_handshake:init_handshake_history()}, Actions); -hello(internal, #hello_verify_request{cookie = Cookie}, #state{role = client, - host = Host, port = Port, + {State2, Actions} = send_handshake(VerifyRequest, State1), + {Record, State} = next_record(State2), + next_event(?FUNCTION_NAME, Record, + State#state{handshake_env = HsEnv#handshake_env{ + tls_handshake_history = + ssl_handshake:init_handshake_history()}}, + Actions); +hello(internal, #hello_verify_request{cookie = Cookie}, #state{static_env = #static_env{role = client, + host = Host, + port = Port, + session_cache = Cache, + session_cache_cb = CacheCb}, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, ssl_options = SslOpts, session = #session{own_certificate = OwnCert} = Session0, - connection_states = ConnectionStates0, - renegotiation = {Renegotiation, _}, - session_cache = Cache, - session_cache_cb = CacheCb + connection_states = ConnectionStates0 } = State0) -> Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts, Cache, CacheCb, Renegotiation, OwnCert), Version = Hello#client_hello.client_version, - State1 = prepare_flight(State0#state{tls_handshake_history = ssl_handshake:init_handshake_history()}), + State1 = prepare_flight(State0#state{handshake_env = + HsEnv#handshake_env{tls_handshake_history + = ssl_handshake:init_handshake_history()}}), {State2, Actions} = send_handshake(Hello, State1), State = State2#state{negotiated_version = Version, %% Requested version @@ -526,12 +550,13 @@ hello(internal, #server_hello{extensions = Extensions} = Hello, {next_state, user_hello, State#state{start_or_recv_from = undefined, hello = Hello}, [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]}; -hello(internal, #client_hello{cookie = Cookie} = Hello, - #state{role = server, - transport_cb = Transport, - socket = Socket, - protocol_specific = #{current_cookie_secret := Secret, - previous_cookie_secret := PSecret}} = State0) -> + +hello(internal, #client_hello{cookie = Cookie} = Hello, #state{static_env = #static_env{role = server, + transport_cb = Transport, + socket = Socket}, + protocol_specific = #{current_cookie_secret := Secret, + previous_cookie_secret := PSecret} + } = State0) -> {ok, {IP, Port}} = dtls_socket:peername(Transport, Socket), case dtls_handshake:cookie(Secret, IP, Port, Hello) of Cookie -> @@ -546,11 +571,12 @@ hello(internal, #client_hello{cookie = Cookie} = Hello, end end; hello(internal, #server_hello{} = Hello, - #state{connection_states = ConnectionStates0, - negotiated_version = ReqVersion, - role = client, - renegotiation = {Renegotiation, _}, - ssl_options = SslOptions} = State) -> + #state{ + static_env = #static_env{role = client}, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, + connection_states = ConnectionStates0, + negotiated_version = ReqVersion, + ssl_options = SslOptions} = State) -> case dtls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of #alert{} = Alert -> handle_own_alert(Alert, ReqVersion, ?FUNCTION_NAME, State); @@ -658,33 +684,43 @@ connection(enter, _, State) -> {keep_state, State}; connection(info, Event, State) -> gen_info(Event, ?FUNCTION_NAME, State); -connection(internal, #hello_request{}, #state{host = Host, port = Port, +connection(internal, #hello_request{}, #state{static_env = #static_env{host = Host, + port = Port, + session_cache = Cache, + session_cache_cb = CacheCb + }, + handshake_env = #handshake_env{ renegotiation = {Renegotiation, _}}, session = #session{own_certificate = Cert} = Session0, - session_cache = Cache, session_cache_cb = CacheCb, + ssl_options = SslOpts, - connection_states = ConnectionStates0, - renegotiation = {Renegotiation, _}} = State0) -> + connection_states = ConnectionStates0 + } = State0) -> Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, Cache, CacheCb, Renegotiation, Cert), Version = Hello#client_hello.client_version, HelloVersion = dtls_record:hello_version(Version, SslOpts#ssl_options.versions), State1 = prepare_flight(State0), - {State, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}), - next_event(hello, no_record, State#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}, - session = Session0#session{session_id - = Hello#client_hello.session_id}}, - Actions); -connection(internal, #client_hello{} = Hello, #state{role = server, allow_renegotiate = true} = State) -> + {State2, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}), + {Record, State} = + next_record( + State2#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}, + session = Session0#session{session_id + = Hello#client_hello.session_id}}), + next_event(hello, Record, State, Actions); +connection(internal, #client_hello{} = Hello, #state{static_env = #static_env{role = server}, + allow_renegotiate = true} = State) -> %% Mitigate Computational DoS attack %% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html %% http://www.thc.org/thc-ssl-dos/ Rather than disabling client %% initiated renegotiation we will disallow many client initiated %% renegotiations immediately after each other. erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate), - {next_state, hello, State#state{allow_renegotiate = false, renegotiation = {true, peer}}, + {next_state, hello, State#state{allow_renegotiate = false, + handshake_env = #handshake_env{renegotiation = {true, peer}}}, [{next_event, internal, Hello}]}; -connection(internal, #client_hello{}, #state{role = server, allow_renegotiate = false} = State0) -> +connection(internal, #client_hello{}, #state{static_env = #static_env{role = server}, + allow_renegotiate = false} = State0) -> Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION), State1 = send_alert(Alert, State0), {Record, State} = ssl_connection:prepare_connection(State1, ?MODULE), @@ -739,29 +775,35 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User, end, Monitor = erlang:monitor(process, User), - - #state{socket_options = SocketOptions, + InitStatEnv = #static_env{ + role = Role, + transport_cb = CbModule, + protocol_cb = ?MODULE, + data_tag = DataTag, + close_tag = CloseTag, + error_tag = ErrorTag, + host = Host, + port = Port, + socket = Socket, + session_cache_cb = SessionCacheCb + }, + + #state{static_env = InitStatEnv, + handshake_env = #handshake_env{ + tls_handshake_history = ssl_handshake:init_handshake_history(), + renegotiation = {false, first} + }, + socket_options = SocketOptions, %% We do not want to save the password in the state so that %% could be written in the clear into error logs. ssl_options = SSLOptions#ssl_options{password = undefined}, session = #session{is_resumable = new}, - transport_cb = CbModule, - data_tag = DataTag, - close_tag = CloseTag, - error_tag = ErrorTag, - role = Role, - host = Host, - port = Port, - socket = Socket, connection_states = ConnectionStates, protocol_buffers = #protocol_buffers{}, user_application = {Monitor, User}, user_data_buffer = <<>>, - session_cache_cb = SessionCacheCb, - renegotiation = {false, first}, allow_renegotiate = SSLOptions#ssl_options.client_renegotiation, start_or_recv_from = undefined, - protocol_cb = ?MODULE, flight_buffer = new_flight(), flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT} }. @@ -802,17 +844,18 @@ decode_cipher_text(#state{protocol_buffers = #protocol_buffers{dtls_cipher_texts {Alert, State} end. -dtls_version(hello, Version, #state{role = server} = State) -> +dtls_version(hello, Version, #state{static_env = #static_env{role = server}} = State) -> State#state{negotiated_version = Version}; %%Inital version dtls_version(_,_, State) -> State. handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, #state{connection_states = ConnectionStates0, - port = Port, session = #session{own_certificate = Cert} = Session0, - renegotiation = {Renegotiation, _}, - session_cache = Cache, - session_cache_cb = CacheCb, + static_env = #static_env{port = Port, + session_cache = Cache, + session_cache_cb = CacheCb}, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, + session = #session{own_certificate = Cert} = Session0, negotiated_protocol = CurrentProtocol, key_algorithm = KeyExAlg, ssl_options = SslOpts} = State0) -> @@ -831,7 +874,7 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State = prepare_flight(State0#state{connection_states = ConnectionStates, negotiated_version = Version, hashsign_algorithm = HashSign, - client_hello_version = ClientVersion, + handshake_env = HsEnv#handshake_env{client_hello_version = ClientVersion}, session = Session, negotiated_protocol = Protocol}), @@ -842,19 +885,19 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, %% raw data from socket, unpack records handle_info({Protocol, _, _, _, Data}, StateName, - #state{data_tag = Protocol} = State0) -> + #state{static_env = #static_env{data_tag = Protocol}} = State0) -> case next_dtls_record(Data, StateName, State0) of {Record, State} -> next_event(StateName, Record, State); #alert{} = Alert -> ssl_connection:handle_normal_shutdown(Alert, StateName, State0), - ssl_connection:stop({shutdown, own_alert}, State0) + {stop, {shutdown, own_alert}, State0} end; handle_info({CloseTag, Socket}, StateName, - #state{socket = Socket, + #state{static_env = #static_env{socket = Socket, + close_tag = CloseTag}, socket_options = #socket_options{active = Active}, protocol_buffers = #protocol_buffers{dtls_cipher_texts = CTs}, - close_tag = CloseTag, negotiated_version = Version} = State) -> %% Note that as of DTLS 1.2 (TLS 1.1), %% failure to properly close a connection no longer requires that a @@ -873,7 +916,7 @@ handle_info({CloseTag, Socket}, StateName, ok end, ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State), - ssl_connection:stop({shutdown, transport_closed}, State); + {stop, {shutdown, transport_closed}, State}; true -> %% Fixes non-delivery of final DTLS record in {active, once}. %% Basically allows the application the opportunity to set {active, once} again @@ -907,8 +950,8 @@ handle_alerts([Alert | Alerts], {next_state, StateName, State}) -> handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) -> handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)). -handle_own_alert(Alert, Version, StateName, #state{data_tag = udp, - role = Role, +handle_own_alert(Alert, Version, StateName, #state{static_env = #static_env{data_tag = udp, + role = Role}, ssl_options = Options} = State0) -> case ignore_alert(Alert, State0) of {true, State} -> @@ -998,10 +1041,10 @@ next_flight(Flight) -> change_cipher_spec => undefined, handshakes_after_change_cipher_spec => []}. -handle_flight_timer(#state{data_tag = udp, +handle_flight_timer(#state{static_env = #static_env{data_tag = udp}, flight_state = {retransmit, Timeout}} = State) -> start_retransmision_timer(Timeout, State); -handle_flight_timer(#state{data_tag = udp, +handle_flight_timer(#state{static_env = #static_env{data_tag = udp}, flight_state = connection} = State) -> {State, []}; handle_flight_timer(State) -> @@ -1017,8 +1060,8 @@ new_timeout(N) when N =< 30 -> new_timeout(_) -> 60. -send_handshake_flight(#state{socket = Socket, - transport_cb = Transport, +send_handshake_flight(#state{static_env = #static_env{socket = Socket, + transport_cb = Transport}, flight_buffer = #{handshakes := Flight, change_cipher_spec := undefined}, negotiated_version = Version, @@ -1029,8 +1072,8 @@ send_handshake_flight(#state{socket = Socket, send(Transport, Socket, Encoded), {State0#state{connection_states = ConnectionStates}, []}; -send_handshake_flight(#state{socket = Socket, - transport_cb = Transport, +send_handshake_flight(#state{static_env = #static_env{socket = Socket, + transport_cb = Transport}, flight_buffer = #{handshakes := [_|_] = Flight0, change_cipher_spec := ChangeCipher, handshakes_after_change_cipher_spec := []}, @@ -1043,8 +1086,8 @@ send_handshake_flight(#state{socket = Socket, send(Transport, Socket, [HsBefore, EncChangeCipher]), {State0#state{connection_states = ConnectionStates}, []}; -send_handshake_flight(#state{socket = Socket, - transport_cb = Transport, +send_handshake_flight(#state{static_env = #static_env{socket = Socket, + transport_cb = Transport}, flight_buffer = #{handshakes := [_|_] = Flight0, change_cipher_spec := ChangeCipher, handshakes_after_change_cipher_spec := Flight1}, @@ -1059,8 +1102,8 @@ send_handshake_flight(#state{socket = Socket, send(Transport, Socket, [HsBefore, EncChangeCipher, HsAfter]), {State0#state{connection_states = ConnectionStates}, []}; -send_handshake_flight(#state{socket = Socket, - transport_cb = Transport, +send_handshake_flight(#state{static_env = #static_env{socket = Socket, + transport_cb = Transport}, flight_buffer = #{handshakes := [], change_cipher_spec := ChangeCipher, handshakes_after_change_cipher_spec := Flight1}, @@ -1117,16 +1160,17 @@ log_ignore_alert(false, _, _,_) -> ok. send_application_data(Data, From, _StateName, - #state{socket = Socket, + #state{static_env = #static_env{socket = Socket, + protocol_cb = Connection, + transport_cb = Transport}, + handshake_env = HsEnv, negotiated_version = Version, - protocol_cb = Connection, - transport_cb = Transport, connection_states = ConnectionStates0, ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}} = State0) -> case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of true -> - renegotiate(State0#state{renegotiation = {true, internal}}, + renegotiate(State0#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, internal}}}, [{next_event, {call, From}, {application_data, Data}}]); false -> {Msgs, ConnectionStates} = diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl index 3f70eaec8a..6e9bf99e52 100644 --- a/lib/ssl/src/dtls_handshake.erl +++ b/lib/ssl/src/dtls_handshake.erl @@ -46,7 +46,7 @@ %% Handshake handling %%==================================================================== %%-------------------------------------------------------------------- --spec client_hello(host(), inet:port_number(), ssl_record:connection_states(), +-spec client_hello(ssl:host(), inet:port_number(), ssl_record:connection_states(), #ssl_options{}, integer(), atom(), boolean(), der_cert()) -> #client_hello{}. %% @@ -59,7 +59,7 @@ client_hello(Host, Port, ConnectionStates, SslOpts, Cache, CacheCb, Renegotiation, OwnCert). %%-------------------------------------------------------------------- --spec client_hello(host(), inet:port_number(), term(), ssl_record:connection_states(), +-spec client_hello(ssl:host(), inet:port_number(), term(), ssl_record:connection_states(), #ssl_options{}, integer(), atom(), boolean(), der_cert()) -> #client_hello{}. %% @@ -123,7 +123,7 @@ cookie(Key, Address, Port, #client_hello{client_version = {Major, Minor}, Random, SessionId, CipherSuites, CompressionMethods], crypto:hmac(sha, Key, CookieData). %%-------------------------------------------------------------------- --spec hello_verify_request(binary(), dtls_record:dtls_version()) -> #hello_verify_request{}. +-spec hello_verify_request(binary(), ssl_record:ssl_version()) -> #hello_verify_request{}. %% %% Description: Creates a hello verify request message sent by server to %% verify client @@ -151,7 +151,7 @@ encode_handshake(Handshake, Version, Seq) -> %%-------------------------------------------------------------------- %%-------------------------------------------------------------------- --spec get_dtls_handshake(dtls_record:dtls_version(), binary(), #protocol_buffers{}) -> +-spec get_dtls_handshake(ssl_record:ssl_version(), binary(), #protocol_buffers{}) -> {[dtls_handshake()], #protocol_buffers{}}. %% %% Description: Given buffered and new data from dtls_record, collects @@ -215,8 +215,6 @@ handle_client_hello_extensions(Version, Type, Random, CipherSuites, HelloExt, dtls_v1:corresponding_tls_version(Version), SslOpts, Session0, ConnectionStates0, Renegotiation) of - #alert{} = Alert -> - Alert; {Session, ConnectionStates, Protocol, ServerHelloExt} -> {Version, {Type, Session}, ConnectionStates, Protocol, ServerHelloExt, HashSign} catch throw:Alert -> @@ -225,17 +223,16 @@ handle_client_hello_extensions(Version, Type, Random, CipherSuites, handle_server_hello_extensions(Version, SessionId, Random, CipherSuite, Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation) -> - case ssl_handshake:handle_server_hello_extensions(dtls_record, Random, CipherSuite, - Compression, HelloExt, - dtls_v1:corresponding_tls_version(Version), - SslOpt, ConnectionStates0, Renegotiation) of - #alert{} = Alert -> - Alert; + try ssl_handshake:handle_server_hello_extensions(dtls_record, Random, CipherSuite, + Compression, HelloExt, + dtls_v1:corresponding_tls_version(Version), + SslOpt, ConnectionStates0, Renegotiation) of {ConnectionStates, ProtoExt, Protocol} -> {Version, SessionId, ConnectionStates, ProtoExt, Protocol} + catch throw:Alert -> + Alert end. - %%-------------------------------------------------------------------- enc_handshake(#hello_verify_request{protocol_version = {Major, Minor}, diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl index 50e92027d2..41da8e5c8c 100644 --- a/lib/ssl/src/dtls_handshake.hrl +++ b/lib/ssl/src/dtls_handshake.hrl @@ -27,6 +27,7 @@ -define(dtls_handshake, true). -include("ssl_handshake.hrl"). %% Common TLS and DTLS records and Constantes +-include("ssl_api.hrl"). -define(HELLO_VERIFY_REQUEST, 3). -define(HELLO_VERIFY_REQUEST_VERSION, {254, 255}). diff --git a/lib/ssl/src/dtls_packet_demux.erl b/lib/ssl/src/dtls_packet_demux.erl index 1497c77cf3..dccc22a448 100644 --- a/lib/ssl/src/dtls_packet_demux.erl +++ b/lib/ssl/src/dtls_packet_demux.erl @@ -144,11 +144,11 @@ handle_info({Transport, Socket, IP, InPortNo, _} = Msg, #state{listener = Socket %% UDP socket does not have a connection and should not receive an econnreset %% This does however happens on some windows versions. Just ignoring it %% appears to make things work as expected! -handle_info({Error, Socket, econnreset = Error}, #state{listener = Socket, transport = {_,_,_, udp_error}} = State) -> +handle_info({udp_error, Socket, econnreset = Error}, #state{listener = Socket, transport = {_,_,_, udp_error}} = State) -> Report = io_lib:format("Ignore SSL UDP Listener: Socket error: ~p ~n", [Error]), error_logger:info_report(Report), {noreply, State}; -handle_info({Error, Socket, Error}, #state{listener = Socket, transport = {_,_,_, Error}} = State) -> +handle_info({ErrorTag, Socket, Error}, #state{listener = Socket, transport = {_,_,_, ErrorTag}} = State) -> Report = io_lib:format("SSL Packet muliplxer shutdown: Socket error: ~p ~n", [Error]), error_logger:info_report(Report), {noreply, State#state{close=true}}; diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl index b7346d3ec8..dd33edfd77 100644 --- a/lib/ssl/src/dtls_record.erl +++ b/lib/ssl/src/dtls_record.erl @@ -49,9 +49,8 @@ is_acceptable_version/2, hello_version/2]). --export_type([dtls_version/0, dtls_atom_version/0]). +-export_type([dtls_atom_version/0]). --type dtls_version() :: ssl_record:ssl_version(). -type dtls_atom_version() :: dtlsv1 | 'dtlsv1.2'. -define(REPLAY_WINDOW_SIZE, 64). @@ -135,7 +134,7 @@ set_connection_state_by_epoch(ReadState, Epoch, #{saved_read := #{epoch := Epoch States#{saved_read := ReadState}. %%-------------------------------------------------------------------- --spec init_connection_state_seq(dtls_version(), ssl_record:connection_states()) -> +-spec init_connection_state_seq(ssl_record:ssl_version(), ssl_record:connection_states()) -> ssl_record:connection_state(). %% %% Description: Copy the read sequence number to the write sequence number @@ -163,7 +162,7 @@ current_connection_state_epoch(#{current_write := #{epoch := Epoch}}, Epoch. %%-------------------------------------------------------------------- --spec get_dtls_records(binary(), [dtls_version()], binary()) -> {[binary()], binary()} | #alert{}. +-spec get_dtls_records(binary(), [ssl_record:ssl_version()], binary()) -> {[binary()], binary()} | #alert{}. %% %% Description: Given old buffer and new data from UDP/SCTP, packs up a records %% and returns it as a list of tls_compressed binaries also returns leftover @@ -188,7 +187,7 @@ get_dtls_records(Data, Versions, Buffer) -> %%==================================================================== %%-------------------------------------------------------------------- --spec encode_handshake(iolist(), dtls_version(), integer(), ssl_record:connection_states()) -> +-spec encode_handshake(iolist(), ssl_record:ssl_version(), integer(), ssl_record:connection_states()) -> {iolist(), ssl_record:connection_states()}. % %% Description: Encodes a handshake message to send on the ssl-socket. @@ -198,7 +197,7 @@ encode_handshake(Frag, Version, Epoch, ConnectionStates) -> %%-------------------------------------------------------------------- --spec encode_alert_record(#alert{}, dtls_version(), ssl_record:connection_states()) -> +-spec encode_alert_record(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) -> {iolist(), ssl_record:connection_states()}. %% %% Description: Encodes an alert message to send on the ssl-socket. @@ -210,7 +209,7 @@ encode_alert_record(#alert{level = Level, description = Description}, ConnectionStates). %%-------------------------------------------------------------------- --spec encode_change_cipher_spec(dtls_version(), integer(), ssl_record:connection_states()) -> +-spec encode_change_cipher_spec(ssl_record:ssl_version(), integer(), ssl_record:connection_states()) -> {iolist(), ssl_record:connection_states()}. %% %% Description: Encodes a change_cipher_spec-message to send on the ssl socket. @@ -219,7 +218,7 @@ encode_change_cipher_spec(Version, Epoch, ConnectionStates) -> encode_plain_text(?CHANGE_CIPHER_SPEC, Version, Epoch, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates). %%-------------------------------------------------------------------- --spec encode_data(binary(), dtls_version(), ssl_record:connection_states()) -> +-spec encode_data(binary(), ssl_record:ssl_version(), ssl_record:connection_states()) -> {iolist(),ssl_record:connection_states()}. %% %% Description: Encodes data to send on the ssl-socket. @@ -248,8 +247,8 @@ decode_cipher_text(#ssl_tls{epoch = Epoch} = CipherText, ConnnectionStates0) -> %%==================================================================== %%-------------------------------------------------------------------- --spec protocol_version(dtls_atom_version() | dtls_version()) -> - dtls_version() | dtls_atom_version(). +-spec protocol_version(dtls_atom_version() | ssl_record:ssl_version()) -> + ssl_record:ssl_version() | dtls_atom_version(). %% %% Description: Creates a protocol version record from a version atom %% or vice versa. @@ -263,7 +262,7 @@ protocol_version({254, 253}) -> protocol_version({254, 255}) -> dtlsv1. %%-------------------------------------------------------------------- --spec lowest_protocol_version(dtls_version(), dtls_version()) -> dtls_version(). +-spec lowest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version(). %% %% Description: Lowes protocol version of two given versions %%-------------------------------------------------------------------- @@ -277,7 +276,7 @@ lowest_protocol_version(_,Version) -> Version. %%-------------------------------------------------------------------- --spec lowest_protocol_version([dtls_version()]) -> dtls_version(). +-spec lowest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version(). %% %% Description: Lowest protocol version present in a list %%-------------------------------------------------------------------- @@ -288,7 +287,7 @@ lowest_protocol_version(Versions) -> lowest_list_protocol_version(Ver, Vers). %%-------------------------------------------------------------------- --spec highest_protocol_version([dtls_version()]) -> dtls_version(). +-spec highest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version(). %% %% Description: Highest protocol version present in a list %%-------------------------------------------------------------------- @@ -299,7 +298,7 @@ highest_protocol_version(Versions) -> highest_list_protocol_version(Ver, Vers). %%-------------------------------------------------------------------- --spec highest_protocol_version(dtls_version(), dtls_version()) -> dtls_version(). +-spec highest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version(). %% %% Description: Highest protocol version of two given versions %%-------------------------------------------------------------------- @@ -315,7 +314,7 @@ highest_protocol_version(_,Version) -> Version. %%-------------------------------------------------------------------- --spec is_higher(V1 :: dtls_version(), V2::dtls_version()) -> boolean(). +-spec is_higher(V1 :: ssl_record:ssl_version(), V2::ssl_record:ssl_version()) -> boolean(). %% %% Description: Is V1 > V2 %%-------------------------------------------------------------------- @@ -327,7 +326,7 @@ is_higher(_, _) -> false. %%-------------------------------------------------------------------- --spec supported_protocol_versions() -> [dtls_version()]. +-spec supported_protocol_versions() -> [ssl_record:ssl_version()]. %% %% Description: Protocol versions supported %%-------------------------------------------------------------------- @@ -370,7 +369,7 @@ supported_protocol_versions([_|_] = Vsns) -> end. %%-------------------------------------------------------------------- --spec is_acceptable_version(dtls_version(), Supported :: [dtls_version()]) -> boolean(). +-spec is_acceptable_version(ssl_record:ssl_version(), Supported :: [ssl_record:ssl_version()]) -> boolean(). %% %% Description: ssl version 2 is not acceptable security risks are too big. %% @@ -378,7 +377,7 @@ supported_protocol_versions([_|_] = Vsns) -> is_acceptable_version(Version, Versions) -> lists:member(Version, Versions). --spec hello_version(dtls_version(), [dtls_version()]) -> dtls_version(). +-spec hello_version(ssl_record:ssl_version(), [ssl_record:ssl_version()]) -> ssl_record:ssl_version(). hello_version(Version, Versions) -> case dtls_v1:corresponding_tls_version(Version) of TLSVersion when TLSVersion >= {3, 3} -> diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl index a4f8bb7562..5cab35fd4b 100644 --- a/lib/ssl/src/inet_tls_dist.erl +++ b/lib/ssl/src/inet_tls_dist.erl @@ -480,22 +480,25 @@ allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host) -> allowed_nodes(PeerCert, Allowed, PeerIP) end. - - setup(Node, Type, MyNode, LongOrShortNames, SetupTime) -> gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime). gen_setup(Driver, Node, Type, MyNode, LongOrShortNames, SetupTime) -> Kernel = self(), monitor_pid( - spawn_opt( - fun() -> - do_setup( - Driver, Kernel, Node, Type, - MyNode, LongOrShortNames, SetupTime) - end, - [link, {priority, max}])). + spawn_opt(setup_fun(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime), + [link, {priority, max}])). + +-spec setup_fun(_,_,_,_,_,_,_) -> fun(() -> no_return()). +setup_fun(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> + fun() -> + do_setup( + Driver, Kernel, Node, Type, + MyNode, LongOrShortNames, SetupTime) + end. + +-spec do_setup(_,_,_,_,_,_,_) -> no_return(). do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> {Name, Address} = split_node(Driver, Node, LongOrShortNames), ErlEpmd = net_kernel:epmd_module(), @@ -520,6 +523,8 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> trace({getaddr_failed, Driver, Address, Other})) end. +-spec do_setup_connect(_,_,_,_,_,_,_,_,_,_) -> no_return(). + do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer) -> Opts = trace(connect_options(get_ssl_options(client))), dist_util:reset_timer(Timer), @@ -564,7 +569,7 @@ gen_close(Driver, Socket) -> %% Determine if EPMD module supports address resolving. Default %% is to use inet_tcp:getaddr/2. %% ------------------------------------------------------------ -get_address_resolver(EpmdModule, Driver) -> +get_address_resolver(EpmdModule, _Driver) -> case erlang:function_exported(EpmdModule, address_please, 3) of true -> {EpmdModule, address_please}; _ -> {erl_epmd, address_please} diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 03a1e40bfc..a7d6f28c7a 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -61,16 +61,321 @@ -deprecated({ssl_accept, 2, eventually}). -deprecated({ssl_accept, 3, eventually}). +-export_type([socket/0, + sslsocket/0, + socket_option/0, + tls_client_option/0, + tls_option/0, + tls_server_option/0, + active_msgs/0, + erl_cipher_suite/0, + protocol_version/0, + dtls_version/0, + tls_version/0, + prf_random/0, + hello_extensions/0, + error_alert/0, + session_id/0, + path/0, + hostname/0, + host/0, + prf/0, + srp_param_type/0, + cipher_filters/0, + ssl_imp/0, + private_key_type/0, + cipher/0, + hash/0, + key_algo/0, + sign_algo/0 + ]). +%% ------------------------------------------------------------------------------------------------------- +-type socket() :: gen_tcp:socket(). +-type socket_option() :: socket_connect_option() | socket_listen_option(). +-type socket_connect_option() :: gen_tcp:connect_option() | gen_udp:option(). +-type socket_listen_option() :: gen_tcp:listen_option() | gen_udp:option(). +-opaque sslsocket() :: #sslsocket{}. +-type tls_option() :: tls_client_option() | tls_server_option(). +-type tls_client_option() :: client_option() | socket_connect_option() | transport_option(). +-type tls_server_option() :: server_option() | socket_listen_option() | transport_option(). +-type active_msgs() :: {ssl, sslsocket(), Data::binary() | list()} | {ssl_closed, sslsocket()} | + {ssl_error, sslsocket(), Reason::term()}. +-type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(), + ClosedTag::atom(), ErrTag::atom()}}. +-type path() :: file:filename(). +-type host() :: hostname() | ip_address(). +-type hostname() :: string(). +-type ip_address() :: inet:ip_address(). +-type session_id() :: binary(). +-type protocol_version() :: tls_version() | dtls_version(). +-type tls_version() :: tlsv1 | 'tlsv1.1' | 'tlsv1.2' | 'tlsv1.3' | legacy_version(). +-type dtls_version() :: 'dtlsv1' | 'dtlsv1.2'. +-type legacy_version() :: sslv3. +-type verify_type() :: verify_none | verify_peer. +-type cipher() :: aes_128_cbc | + aes_256_cbc | + aes_128_gcm | + aes_256_gcm | + chacha20_poly1305 | + legacy_cipher(). +-type legacy_cipher() :: rc4_128 | + des_cbc | + '3des_ede_cbc'. + +-type hash() :: sha | + sha2() | + legacy_hash(). + +-type sha2() :: sha224 | + sha256 | + sha384 | + sha512. + +-type legacy_hash() :: md5. + +-type sign_algo() :: rsa | dsa | ecdsa. +-type key_algo() :: rsa | + dhe_rsa | dhe_dss | + ecdhe_ecdsa | ecdh_ecdsa | ecdh_rsa | + srp_rsa| srp_dss | + psk | dhe_psk | rsa_psk | + dh_anon | ecdh_anon | srp_anon | + any. %% TLS 1.3 +-type prf() :: hash() | default_prf. +-type erl_cipher_suite() :: #{key_exchange := key_algo(), + cipher := cipher(), + mac := hash() | aead, + prf := hash() | default_prf %% Old cipher suites, version dependent + }. + +-type named_curve() :: sect571r1 | + sect571k1 | + secp521r1 | + brainpoolP512r1 | + sect409k1 | + sect409r1 | + brainpoolP384r1 | + secp384r1 | + sect283k1 | + sect283r1 | + brainpoolP256r1 | + secp256k1 | + secp256r1 | + sect239k1 | + sect233k1 | + sect233r1 | + secp224k1 | + secp224r1 | + sect193r1 | + sect193r2 | + secp192k1 | + secp192r1 | + sect163k1 | + sect163r1 | + sect163r2 | + secp160k1 | + secp160r1 | + secp160r2. + +-type srp_param_type() :: srp_1024 | + srp_1536 | + srp_2048 | + srp_3072 | + srp_4096 | + srp_6144 | + srp_8192. + +-type error_alert() :: {tls_alert, {tls_alert(), Description::string()}}. + +-type tls_alert() :: + close_notify | + unexpected_message | + bad_record_mac | + record_overflow | + handshake_failure | + bad_certificate | + unsupported_certificate | + certificate_revoked | + certificate_expired | + certificate_unknown | + illegal_parameter | + unknown_ca | + access_denied | + decode_error | + decrypt_error | + export_restriction| + protocol_version | + insufficient_security | + internal_error | + inappropriate_fallback | + user_canceled | + no_renegotiation | + unsupported_extension | + certificate_unobtainable | + unrecognized_name | + bad_certificate_status_response | + bad_certificate_hash_value | + unknown_psk_identity | + no_application_protocol. +%% ------------------------------------------------------------------------------------------------------- +-type common_option() :: {protocol, protocol()} | + {handshake, handshake_completion()} | + {cert, cert()} | + {certfile, cert_pem()} | + {key, key()} | + {keyfile, key_pem()} | + {password, key_password()} | + {ciphers, cipher_suites()} | + {eccs, eccs()} | + {secure_renegotiate, secure_renegotiation()} | + {depth, allowed_cert_chain_length()} | + {verify_fun, custom_verify()} | + {crl_check, crl_check()} | + {crl_cache, crl_cache_opts()} | + {max_handshake_size, handshake_size()} | + {partial_chain, root_fun()} | + {versions, protocol_versions()} | + {user_lookup_fun, custom_user_lookup()} | + {log_alert, log_alert()} | + {hibernate_after, hibernate_after()} | + {padding_check, padding_check()} | + {beast_mitigation, beast_mitigation()}. + +-type protocol() :: tls | dtls. +-type handshake_completion() :: hello | full. +-type cert() :: public_key:der_encoded(). +-type cert_pem() :: ssl:path(). +-type key() :: {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', + public_key:der_encoded()} | + #{algorithm := rsa | dss | ecdsa, + engine := crypto:engine_ref(), + key_id := crypto:key_id(), + password => crypto:password()}. +-type key_pem() :: ssl:path(). +-type key_password() :: string(). +-type cipher_suites() :: ciphers(). +-type ciphers() :: [erl_cipher_suite()] | + string(). % (according to old API) +-type cipher_filters() :: list({key_exchange | cipher | mac | prf, + algo_filter()}). +-type algo_filter() :: fun((key_algo()|cipher()|hash()|aead|default_prf) -> true | false). +-type eccs() :: [named_curve()]. +-type secure_renegotiation() :: boolean(). +-type allowed_cert_chain_length() :: integer(). +-type custom_verify() :: {Verifyfun :: fun(), InitialUserState :: term()}. +-type crl_check() :: boolean() | peer | best_effort. +-type crl_cache_opts() :: [term()]. +-type handshake_size() :: integer(). +-type hibernate_after() :: timeout(). +-type root_fun() :: fun(). +-type protocol_versions() :: [protocol_version()]. +-type signature_algs() :: [{hash(), sign_algo()}]. +-type custom_user_lookup() :: {Lookupfun :: fun(), UserState :: term()}. +-type padding_check() :: boolean(). +-type beast_mitigation() :: one_n_minus_one | zero_n | disabled. +-type srp_identity() :: {Username :: string(), Password :: string()}. +-type psk_identity() :: string(). +-type log_alert() :: boolean(). + +%% ------------------------------------------------------------------------------------------------------- + +-type client_option() :: {verify, client_verify_type()} | + {reuse_session, client_reuse_session()} | + {reuse_sessions, client_reuse_sessions()} | + {cacerts, client_cacerts()} | + {cacertfile, client_cafile()} | + {alpn_advertised_protocols, client_alpn()} | + {client_preferred_next_protocols, client_preferred_next_protocols()} | + {psk_identity, client_psk_identity()} | + {srp_identity, client_srp_identity()} | + {server_name_indication, sni()} | + {customize_hostname_check, customize_hostname_check()} | + {signature_algs, client_signature_algs()} | + {fallback, fallback()}. + +-type client_verify_type() :: verify_type(). +-type client_reuse_session() :: ssl:session_id(). +-type client_reuse_sessions() :: boolean() | save. +-type client_cacerts() :: [public_key:der_encoded()]. +-type client_cafile() :: ssl:path(). +-type app_level_protocol() :: binary(). +-type client_alpn() :: [app_level_protocol()]. +-type client_preferred_next_protocols() :: {Precedence :: server | client, + ClientPrefs :: [app_level_protocol()]} | + {Precedence :: server | client, + ClientPrefs :: [app_level_protocol()], + Default::app_level_protocol()}. +-type client_psk_identity() :: psk_identity(). +-type client_srp_identity() :: srp_identity(). +-type customize_hostname_check() :: list(). +-type sni() :: HostName :: ssl:hostname() | disable. +-type client_signature_algs() :: signature_algs(). +-type fallback() :: boolean(). + +%% ------------------------------------------------------------------------------------------------------- + +-type server_option() :: {cacerts, server_cacerts()} | + {cacertfile, server_cafile()} | + {dh, dh_der()} | + {dhfile, dh_file()} | + {verify, server_verify_type()} | + {fail_if_no_peer_cert, fail_if_no_peer_cert()} | + {reuse_sessions, server_reuse_sessions()} | + {reuse_session, server_reuse_session()} | + {alpn_preferred_protocols, server_alpn()} | + {next_protocols_advertised, server_next_protocol()} | + {psk_identity, server_psk_identity()} | + {honor_cipher_order, boolean()} | + {sni_hosts, sni_hosts()} | + {sni_fun, sni_fun()} | + {honor_cipher_order, honor_cipher_order()} | + {honor_ecc_order, honor_ecc_order()} | + {client_renegotiation, client_renegotiation()}| + {signature_algs, server_signature_algs()}. + +-type server_cacerts() :: [public_key:der_encoded()]. +-type server_cafile() :: ssl:path(). +-type server_alpn() :: [app_level_protocol()]. +-type server_next_protocol() :: [app_level_protocol()]. +-type server_psk_identity() :: psk_identity(). +-type dh_der() :: binary(). +-type dh_file() :: ssl:path(). +-type server_verify_type() :: verify_type(). +-type fail_if_no_peer_cert() :: boolean(). +-type server_signature_algs() :: signature_algs(). +-type server_reuse_session() :: fun(). +-type server_reuse_sessions() :: boolean(). +-type sni_hosts() :: [{ssl:hostname(), [server_option() | common_option()]}]. +-type sni_fun() :: fun(). +-type honor_cipher_order() :: boolean(). +-type honor_ecc_order() :: boolean(). +-type client_renegotiation() :: boolean(). +%% ------------------------------------------------------------------------------------------------------- + +-type ssl_imp() :: new | old. + + +-type prf_random() :: client_random | server_random. + +-type private_key_type() :: rsa | %% Backwards compatibility + dsa | %% Backwards compatibility + 'RSAPrivateKey' | + 'DSAPrivateKey' | + 'ECPrivateKey' | + 'PrivateKeyInfo'. + +-type hello_extensions() :: #{signature_algs => sign_algo()}. %% TODO +%% ------------------------------------------------------------------------------------------------------- %%-------------------------------------------------------------------- --spec start() -> ok | {error, reason()}. --spec start(permanent | transient | temporary) -> ok | {error, reason()}. %% %% Description: Utility function that starts the ssl and applications %% that it depends on. %% see application(3) %%-------------------------------------------------------------------- +-spec start() -> ok | {error, reason()}. start() -> start(temporary). +-spec start(permanent | transient | temporary) -> ok | {error, reason()}. start(Type) -> case application:ensure_all_started(ssl, Type) of {ok, _} -> @@ -87,20 +392,17 @@ stop() -> application:stop(ssl). %%-------------------------------------------------------------------- --spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} | - {error, reason()}. --spec connect(host() | port(), [connect_option()] | inet:port_number(), - timeout() | list()) -> - {ok, #sslsocket{}} | {error, reason()}. --spec connect(host() | port(), inet:port_number(), list(), timeout()) -> - {ok, #sslsocket{}} | {error, reason()}. - %% %% Description: Connect to an ssl server. %%-------------------------------------------------------------------- +-spec connect(host() | port(), [client_option()]) -> {ok, #sslsocket{}} | + {error, reason()}. connect(Socket, SslOptions) when is_port(Socket) -> connect(Socket, SslOptions, infinity). +-spec connect(host() | port(), [client_option()] | inet:port_number(), + timeout() | list()) -> + {ok, #sslsocket{}} | {error, reason()}. connect(Socket, SslOptions0, Timeout) when is_port(Socket), (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0, @@ -117,6 +419,8 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket), connect(Host, Port, Options) -> connect(Host, Port, Options, infinity). +-spec connect(host() | port(), inet:port_number(), [client_option()], timeout()) -> + {ok, #sslsocket{}} | {error, reason()}. connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> try {ok, Config} = handle_options(Options, client, Host), @@ -132,7 +436,7 @@ connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout end. %%-------------------------------------------------------------------- --spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}. +-spec listen(inet:port_number(), [tls_server_option()]) ->{ok, #sslsocket{}} | {error, reason()}. %% %% Description: Creates an ssl listen socket. @@ -148,16 +452,16 @@ listen(Port, Options0) -> Error end. %%-------------------------------------------------------------------- --spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}} | - {error, reason()}. --spec transport_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} | - {error, reason()}. %% %% Description: Performs transport accept on an ssl listen socket %%-------------------------------------------------------------------- +-spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}} | + {error, reason()}. transport_accept(ListenSocket) -> transport_accept(ListenSocket, infinity). +-spec transport_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} | + {error, reason()}. transport_accept(#sslsocket{pid = {ListenSocket, #config{connection_cb = ConnectionCb} = Config}}, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> @@ -169,25 +473,25 @@ transport_accept(#sslsocket{pid = {ListenSocket, end. %%-------------------------------------------------------------------- --spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}. --spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option() - | transport_option()]) -> - ok | {ok, #sslsocket{}} | {error, reason()}. - --spec ssl_accept(#sslsocket{} | port(), [ssl_option()] | [ssl_option()| transport_option()], timeout()) -> - ok | {ok, #sslsocket{}} | {error, reason()}. %% %% Description: Performs accept on an ssl listen socket. e.i. performs %% ssl handshake. %%-------------------------------------------------------------------- +-spec ssl_accept(#sslsocket{}) -> ok | {error, timeout | closed | {options, any()}| error_alert()}. ssl_accept(ListenSocket) -> ssl_accept(ListenSocket, [], infinity). + +-spec ssl_accept(#sslsocket{} | port(), timeout()| [tls_server_option()]) -> + ok | {ok, #sslsocket{}} | {error, timeout | closed | {options, any()}| error_alert()}. ssl_accept(Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> ssl_accept(Socket, [], Timeout); ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) -> ssl_accept(ListenSocket, SslOptions, infinity); ssl_accept(Socket, Timeout) -> ssl_accept(Socket, [], Timeout). + +-spec ssl_accept(#sslsocket{} | port(), [tls_server_option()], timeout()) -> + ok | {ok, #sslsocket{}} | {error, timeout | closed | {options, any()}| error_alert()}. ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) -> handshake(Socket, SslOptions, Timeout); ssl_accept(Socket, SslOptions, Timeout) -> @@ -198,20 +502,18 @@ ssl_accept(Socket, SslOptions, Timeout) -> Error end. %%-------------------------------------------------------------------- --spec handshake(#sslsocket{}) -> {ok, #sslsocket{}} | {error, reason()}. --spec handshake(#sslsocket{} | port(), timeout()| [ssl_option() - | transport_option()]) -> - {ok, #sslsocket{}} | {error, reason()}. - --spec handshake(#sslsocket{} | port(), [ssl_option()] | [ssl_option()| transport_option()], timeout()) -> - {ok, #sslsocket{}} | {error, reason()}. %% %% Description: Performs accept on an ssl listen socket. e.i. performs %% ssl handshake. %%-------------------------------------------------------------------- + +%% Performs the SSL/TLS/DTLS server-side handshake. +-spec handshake(#sslsocket{}) -> {ok, #sslsocket{}} | {error, timeout | closed | {options, any()} | error_alert()}. handshake(ListenSocket) -> handshake(ListenSocket, infinity). +-spec handshake(#sslsocket{} | port(), timeout()| [tls_server_option()]) -> + {ok, #sslsocket{}} | {error, timeout | closed | {options, any()} | error_alert()}. handshake(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> ssl_connection:handshake(Socket, Timeout); @@ -219,6 +521,8 @@ handshake(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Tim handshake(ListenSocket, SslOptions) when is_port(ListenSocket) -> handshake(ListenSocket, SslOptions, infinity). +-spec handshake(#sslsocket{} | port(), [tls_server_option()], timeout()) -> + {ok, #sslsocket{}} | {error, timeout | closed | {options, any()} | error_alert()}. handshake(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> handshake(Socket, Timeout); @@ -261,7 +565,7 @@ handshake(Socket, SslOptions, Timeout) when is_port(Socket), %%-------------------------------------------------------------------- --spec handshake_continue(#sslsocket{}, [ssl_option()]) -> +-spec handshake_continue(#sslsocket{}, [tls_client_option() | tls_server_option()]) -> {ok, #sslsocket{}} | {error, reason()}. %% %% @@ -270,7 +574,7 @@ handshake(Socket, SslOptions, Timeout) when is_port(Socket), handshake_continue(Socket, SSLOptions) -> handshake_continue(Socket, SSLOptions, infinity). %%-------------------------------------------------------------------- --spec handshake_continue(#sslsocket{}, [ssl_option()], timeout()) -> +-spec handshake_continue(#sslsocket{}, [tls_client_option() | tls_server_option()], timeout()) -> {ok, #sslsocket{}} | {error, reason()}. %% %% @@ -331,13 +635,14 @@ send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _} Transport:send(ListenSocket, Data). %% {error,enotconn} %%-------------------------------------------------------------------- --spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}. --spec recv(#sslsocket{}, integer(), timeout()) -> {ok, binary()| list()} | {error, reason()}. %% %% Description: Receives data when active = false %%-------------------------------------------------------------------- +-spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}. recv(Socket, Length) -> recv(Socket, Length, infinity). + +-spec recv(#sslsocket{}, integer(), timeout()) -> {ok, binary()| list()} | {error, reason()}. recv(#sslsocket{pid = [Pid|_]}, Length, Timeout) when is_pid(Pid), (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> ssl_connection:recv(Pid, Length, Timeout); @@ -460,9 +765,9 @@ cipher_suites(all) -> [ssl_cipher_format:erl_suite_definition(Suite) || Suite <- available_suites(all)]. %%-------------------------------------------------------------------- --spec cipher_suites(default | all | anonymous, tls_record:tls_version() | dtls_record:dtls_version() | +-spec cipher_suites(default | all | anonymous, ssl_record:ssl_version() | tls_record:tls_atom_version() | dtls_record:dtls_atom_version()) -> - [ssl_cipher_format:erl_cipher_suite()]. + [erl_cipher_suite()]. %% Description: Returns all default and all supported cipher suites for a %% TLS/DTLS version %%-------------------------------------------------------------------- @@ -478,9 +783,9 @@ cipher_suites(Base, Version) -> [ssl_cipher_format:suite_definition(Suite) || Suite <- supported_suites(Base, Version)]. %%-------------------------------------------------------------------- --spec filter_cipher_suites([ssl_cipher_format:erl_cipher_suite()], +-spec filter_cipher_suites([erl_cipher_suite()], [{key_exchange | cipher | mac | prf, fun()}] | []) -> - [ssl_cipher_format:erl_cipher_suite()]. + [erl_cipher_suite()]. %% Description: Removes cipher suites if any of the filter functions returns false %% for any part of the cipher suite. This function also calls default filter functions %% to make sure the cipher suite are supported by crypto. @@ -497,10 +802,10 @@ filter_cipher_suites(Suites, Filters0) -> prf_filters => add_filter(proplists:get_value(prf, Filters0), PrfF)}, ssl_cipher:filter_suites(Suites, Filters). %%-------------------------------------------------------------------- --spec prepend_cipher_suites([ssl_cipher_format:erl_cipher_suite()] | +-spec prepend_cipher_suites([erl_cipher_suite()] | [{key_exchange | cipher | mac | prf, fun()}], - [ssl_cipher_format:erl_cipher_suite()]) -> - [ssl_cipher_format:erl_cipher_suite()]. + [erl_cipher_suite()]) -> + [erl_cipher_suite()]. %% Description: Make <Preferred> suites become the most prefered %% suites that is put them at the head of the cipher suite list %% and remove them from <Suites> if present. <Preferred> may be a @@ -515,10 +820,10 @@ prepend_cipher_suites(Filters, Suites) -> Preferred = filter_cipher_suites(Suites, Filters), Preferred ++ (Suites -- Preferred). %%-------------------------------------------------------------------- --spec append_cipher_suites(Deferred :: [ssl_cipher_format:erl_cipher_suite()] | +-spec append_cipher_suites(Deferred :: [erl_cipher_suite()] | [{key_exchange | cipher | mac | prf, fun()}], - [ssl_cipher_format:erl_cipher_suite()]) -> - [ssl_cipher_format:erl_cipher_suite()]. + [erl_cipher_suite()]) -> + [erl_cipher_suite()]. %% Description: Make <Deferred> suites suites become the %% least prefered suites that is put them at the end of the cipher suite list %% and removed them from <Suites> if present. @@ -540,8 +845,8 @@ eccs() -> eccs_filter_supported(Curves). %%-------------------------------------------------------------------- --spec eccs(tls_record:tls_version() | tls_record:tls_atom_version() | - dtls_record:dtls_version() | dtls_record:dtls_atom_version()) -> +-spec eccs(tls_record:tls_atom_version() | + ssl_record:ssl_version() | dtls_record:dtls_atom_version()) -> tls_v1:curves(). %% Description: returns the curves supported for a given version of %% ssl/tls. @@ -723,7 +1028,7 @@ versions() -> SupportedDTLSVsns = [dtls_record:protocol_version(Vsn) || Vsn <- DTLSVsns], AvailableTLSVsns = ?ALL_AVAILABLE_VERSIONS, AvailableDTLSVsns = ?ALL_AVAILABLE_DATAGRAM_VERSIONS, - [{ssl_app, ?VSN}, {supported, SupportedTLSVsns}, + [{ssl_app, "9.2"}, {supported, SupportedTLSVsns}, {supported_dtls, SupportedDTLSVsns}, {available, AvailableTLSVsns}, {available_dtls, AvailableDTLSVsns}]. @@ -783,8 +1088,8 @@ format_error(Reason) when is_list(Reason) -> Reason; format_error(closed) -> "TLS connection is closed"; -format_error({tls_alert, Description}) -> - "TLS Alert: " ++ Description; +format_error({tls_alert, {_, Description}}) -> + Description; format_error({options,{FileType, File, Reason}}) when FileType == cacertfile; FileType == certfile; FileType == keyfile; @@ -813,7 +1118,7 @@ tls_version({254, _} = Version) -> %%-------------------------------------------------------------------- --spec suite_to_str(ssl_cipher_format:erl_cipher_suite()) -> string(). +-spec suite_to_str(erl_cipher_suite()) -> string(). %% %% Description: Return the string representation of a cipher suite. %%-------------------------------------------------------------------- @@ -891,8 +1196,6 @@ handle_options(Opts0, Role, Host) -> {list, [{mode, list}]}], Opts0), assert_proplist(Opts), RecordCb = record_cb(Opts), - - ReuseSessionFun = fun(_, _, _, _) -> true end, CaCerts = handle_option(cacerts, Opts, undefined), {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun, PartialChainHanlder, VerifyClientOnce} = @@ -945,9 +1248,8 @@ handle_options(Opts0, Role, Host) -> default_option_role(server, tls_v1:default_signature_algs(Versions), Role)), tls_version(RecordCb:highest_protocol_version(Versions))), - %% Server side option - reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun), - reuse_sessions = handle_option(reuse_sessions, Opts, true), + reuse_sessions = handle_reuse_sessions_option(reuse_sessions, Opts, Role), + reuse_session = handle_reuse_session_option(reuse_session, Opts, Role), secure_renegotiate = handle_option(secure_renegotiate, Opts, true), client_renegotiation = handle_option(client_renegotiation, Opts, default_option_role(server, true, Role), @@ -1003,8 +1305,8 @@ handle_options(Opts0, Role, Host) -> alpn_preferred_protocols, next_protocols_advertised, client_preferred_next_protocols, log_alert, server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache, - fallback, signature_algs, eccs, honor_ecc_order, beast_mitigation, - max_handshake_size, handshake, customize_hostname_check], + fallback, signature_algs, eccs, honor_ecc_order, + beast_mitigation, max_handshake_size, handshake, customize_hostname_check], SockOpts = lists:foldl(fun(Key, PropList) -> proplists:delete(Key, PropList) end, Opts, SslOptions), @@ -1138,11 +1440,16 @@ validate_option(srp_identity, {Username, Password}) {unicode:characters_to_binary(Username), unicode:characters_to_binary(Password)}; +validate_option(reuse_session, undefined) -> + undefined; validate_option(reuse_session, Value) when is_function(Value) -> Value; +validate_option(reuse_session, Value) when is_binary(Value) -> + Value; validate_option(reuse_sessions, Value) when is_boolean(Value) -> Value; - +validate_option(reuse_sessions, save = Value) -> + Value; validate_option(secure_renegotiate, Value) when is_boolean(Value) -> Value; validate_option(client_renegotiation, Value) when is_boolean(Value) -> @@ -1265,6 +1572,26 @@ handle_hashsigns_option(_, Version) when Version >= {3, 3} -> handle_hashsigns_option(_, _Version) -> undefined. +handle_reuse_sessions_option(Key, Opts, client) -> + Value = proplists:get_value(Key, Opts, true), + validate_option(Key, Value), + Value; +handle_reuse_sessions_option(Key, Opts0, server) -> + Opts = proplists:delete({Key, save}, Opts0), + Value = proplists:get_value(Key, Opts, true), + validate_option(Key, Value), + Value. + +handle_reuse_session_option(Key, Opts, client) -> + Value = proplists:get_value(Key, Opts, undefined), + validate_option(Key, Value), + Value; +handle_reuse_session_option(Key, Opts, server) -> + ReuseSessionFun = fun(_, _, _, _) -> true end, + Value = proplists:get_value(Key, Opts, ReuseSessionFun), + validate_option(Key, Value), + Value. + validate_options([]) -> []; validate_options([{Opt, Value} | Tail]) -> diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl index 34e9797f1f..2a20d13cd5 100644 --- a/lib/ssl/src/ssl_alert.erl +++ b/lib/ssl/src/ssl_alert.erl @@ -48,8 +48,8 @@ decode(Bin) -> decode(Bin, [], 0). %%-------------------------------------------------------------------- --spec reason_code(#alert{}, client | server) -> - closed | {tls_alert, unicode:chardata()}. +%% -spec reason_code(#alert{}, client | server) -> +%% {tls_alert, unicode:chardata()} | closed. %-spec reason_code(#alert{}, client | server) -> closed | {essl, string()}. %% %% Description: Returns the error reason that will be returned to the @@ -58,8 +58,10 @@ decode(Bin) -> reason_code(#alert{description = ?CLOSE_NOTIFY}, _) -> closed; -reason_code(#alert{description = Description}, _) -> - {tls_alert, string:casefold(description_txt(Description))}. +reason_code(#alert{description = Description, role = Role} = Alert, Role) -> + {tls_alert, {description_atom(Description), own_alert_txt(Alert)}}; +reason_code(#alert{description = Description} = Alert, Role) -> + {tls_alert, {description_atom(Description), alert_txt(Alert#alert{role = Role})}}. %%-------------------------------------------------------------------- -spec own_alert_txt(#alert{}) -> string(). @@ -181,3 +183,70 @@ description_txt(?NO_APPLICATION_PROTOCOL) -> "No application protocol"; description_txt(Enum) -> lists:flatten(io_lib:format("unsupported/unknown alert: ~p", [Enum])). + +description_atom(?CLOSE_NOTIFY) -> + close_notify; +description_atom(?UNEXPECTED_MESSAGE) -> + unexpected_message; +description_atom(?BAD_RECORD_MAC) -> + bad_record_mac; +description_atom(?DECRYPTION_FAILED_RESERVED) -> + decryption_failed_reserved; +description_atom(?RECORD_OVERFLOW) -> + record_overflow; +description_atom(?DECOMPRESSION_FAILURE) -> + decompression_failure; +description_atom(?HANDSHAKE_FAILURE) -> + handshake_failure; +description_atom(?NO_CERTIFICATE_RESERVED) -> + no_certificate_reserved; +description_atom(?BAD_CERTIFICATE) -> + bad_certificate; +description_atom(?UNSUPPORTED_CERTIFICATE) -> + unsupported_certificate; +description_atom(?CERTIFICATE_REVOKED) -> + certificate_revoked; +description_atom(?CERTIFICATE_EXPIRED) -> + certificate_expired; +description_atom(?CERTIFICATE_UNKNOWN) -> + certificate_unknown; +description_atom(?ILLEGAL_PARAMETER) -> + illegal_parameter; +description_atom(?UNKNOWN_CA) -> + unknown_ca; +description_atom(?ACCESS_DENIED) -> + access_denied; +description_atom(?DECODE_ERROR) -> + decode_error; +description_atom(?DECRYPT_ERROR) -> + decrypt_error; +description_atom(?EXPORT_RESTRICTION) -> + export_restriction; +description_atom(?PROTOCOL_VERSION) -> + protocol_version; +description_atom(?INSUFFICIENT_SECURITY) -> + insufficient_security; +description_atom(?INTERNAL_ERROR) -> + internal_error; +description_atom(?USER_CANCELED) -> + user_canceled; +description_atom(?NO_RENEGOTIATION) -> + no_renegotiation; +description_atom(?UNSUPPORTED_EXTENSION) -> + unsupported_extension; +description_atom(?CERTIFICATE_UNOBTAINABLE) -> + certificate_unobtainable; +description_atom(?UNRECOGNISED_NAME) -> + unrecognised_name; +description_atom(?BAD_CERTIFICATE_STATUS_RESPONSE) -> + bad_certificate_status_response; +description_atom(?BAD_CERTIFICATE_HASH_VALUE) -> + bad_certificate_hash_value; +description_atom(?UNKNOWN_PSK_IDENTITY) -> + unknown_psk_identity; +description_atom(?INAPPROPRIATE_FALLBACK) -> + inappropriate_fallback; +description_atom(?NO_APPLICATION_PROTOCOL) -> + no_application_protocol; +description_atom(_) -> + 'unsupported/unkonwn_alert'. diff --git a/lib/ssl/src/ssl_api.hrl b/lib/ssl/src/ssl_api.hrl index 7b7b1cbcd9..f4594912bd 100644 --- a/lib/ssl/src/ssl_api.hrl +++ b/lib/ssl/src/ssl_api.hrl @@ -21,56 +21,7 @@ -ifndef(ssl_api). -define(ssl_api, true). --include("ssl_cipher.hrl"). - -%% Visible in API --export_type([connect_option/0, listen_option/0, ssl_option/0, transport_option/0, - prf_random/0, sslsocket/0]). - - %% Looks like it does for backwards compatibility reasons -record(sslsocket, {fd = nil, pid = nil}). - --type sslsocket() :: #sslsocket{}. --type connect_option() :: socket_connect_option() | ssl_option() | transport_option(). --type socket_connect_option() :: gen_tcp:connect_option(). --type listen_option() :: socket_listen_option() | ssl_option() | transport_option(). --type socket_listen_option() :: gen_tcp:listen_option(). - --type ssl_option() :: {versions, ssl_record:ssl_atom_version()} | - {verify, verify_type()} | - {verify_fun, {fun(), InitialUserState::term()}} | - {fail_if_no_peer_cert, boolean()} | {depth, integer()} | - {cert, Der::binary()} | {certfile, path()} | - {key, {private_key_type(), Der::binary()}} | - {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} | - {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} | - {user_lookup_fun, {fun(), InitialUserState::term()}} | - {psk_identity, string()} | - {srp_identity, {string(), string()}} | - {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | - {reuse_session, fun()} | {hibernate_after, integer()|undefined} | - {alpn_advertised_protocols, [binary()]} | - {alpn_preferred_protocols, [binary()]} | - {next_protocols_advertised, list(binary())} | - {client_preferred_next_protocols, binary(), client | server, list(binary())}. - --type verify_type() :: verify_none | verify_peer. --type path() :: string(). --type ciphers() :: [ssl_cipher_format:erl_cipher_suite()] | - string(). % (according to old API) --type ssl_imp() :: new | old. - --type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(), - ClosedTag::atom(), ErrTag::atom()}}. --type prf_random() :: client_random | server_random. - --type private_key_type() :: rsa | %% Backwards compatibility - dsa | %% Backwards compatibility - 'RSAPrivateKey' | - 'DSAPrivateKey' | - 'ECPrivateKey' | - 'PrivateKeyInfo'. - -endif. % -ifdef(ssl_api). diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 54c04c13e5..cf1bec6332 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -481,8 +481,8 @@ filter(DerCert, Ciphers0, Version) -> filter_suites_signature(Sign, Ciphers, Version). %%-------------------------------------------------------------------- --spec filter_suites([ssl_cipher_format:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()], map()) -> - [ssl_cipher_format:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()]. +-spec filter_suites([ssl:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()], map()) -> + [ssl:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()]. %% %% Description: Filter suites using supplied filter funs %%------------------------------------------------------------------- @@ -508,8 +508,8 @@ filter_suite(Suite, Filters) -> filter_suite(ssl_cipher_format:suite_definition(Suite), Filters). %%-------------------------------------------------------------------- --spec filter_suites([ssl_cipher_format:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()]) -> - [ssl_cipher_format:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()]. +-spec filter_suites([ssl:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()]) -> + [ssl:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()]. %% %% Description: Filter suites for algorithms supported by crypto. %%------------------------------------------------------------------- @@ -593,7 +593,7 @@ is_acceptable_cipher(rc4_128, Algos) -> is_acceptable_cipher(des_cbc, Algos) -> proplists:get_bool(des_cbc, Algos); is_acceptable_cipher('3des_ede_cbc', Algos) -> - proplists:get_bool(des3_cbc, Algos); + proplists:get_bool(des_ede3, Algos); is_acceptable_cipher(aes_128_cbc, Algos) -> proplists:get_bool(aes_cbc128, Algos); is_acceptable_cipher(aes_256_cbc, Algos) -> @@ -889,7 +889,7 @@ is_correct_padding(GenBlockCipher, {3, 1}, false) -> is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _, _) -> Len == byte_size(Padding) andalso - list_to_binary(lists:duplicate(Len, Len)) == Padding. + binary:copy(?byte(Len), Len) == Padding. get_padding(Length, BlockSize) -> get_padding_aux(BlockSize, Length rem BlockSize). @@ -898,7 +898,7 @@ get_padding_aux(_, 0) -> {0, <<>>}; get_padding_aux(BlockSize, PadLength) -> N = BlockSize - PadLength, - {N, list_to_binary(lists:duplicate(N, N))}. + {N, binary:copy(?byte(N), N)}. random_iv(IV) -> IVSz = byte_size(IV), diff --git a/lib/ssl/src/ssl_cipher_format.erl b/lib/ssl/src/ssl_cipher_format.erl index c311c0d097..f7af96583f 100644 --- a/lib/ssl/src/ssl_cipher_format.erl +++ b/lib/ssl/src/ssl_cipher_format.erl @@ -25,26 +25,25 @@ %%---------------------------------------------------------------------- -module(ssl_cipher_format). +-include("ssl_api.hrl"). -include("ssl_cipher.hrl"). -include("ssl_internal.hrl"). -include_lib("public_key/include/public_key.hrl"). --export_type([cipher_suite/0, - erl_cipher_suite/0, old_erl_cipher_suite/0, openssl_cipher_suite/0, - hash/0, key_algo/0, sign_algo/0]). +-export_type([old_erl_cipher_suite/0, openssl_cipher_suite/0, cipher_suite/0]). --type cipher() :: null |rc4_128 | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305. --type hash() :: null | md5 | sha | sha224 | sha256 | sha384 | sha512. --type sign_algo() :: rsa | dsa | ecdsa. --type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon. --type erl_cipher_suite() :: #{key_exchange := key_algo(), - cipher := cipher(), - mac := hash() | aead, - prf := hash() | default_prf %% Old cipher suites, version dependent +-type internal_cipher() :: null | ssl:cipher(). +-type internal_hash() :: null | ssl:hash(). +-type internal_key_algo() :: null | ssl:key_algo(). +-type internal_erl_cipher_suite() :: #{key_exchange := internal_key_algo(), + cipher := internal_cipher(), + mac := internal_hash() | aead, + prf := internal_hash() | default_prf %% Old cipher suites, version dependent }. --type old_erl_cipher_suite() :: {key_algo(), cipher(), hash()} % Pre TLS 1.2 +-type old_erl_cipher_suite() :: {ssl:key_algo(), internal_cipher(), internal_hash()} % Pre TLS 1.2 %% TLS 1.2, internally PRE TLS 1.2 will use default_prf - | {key_algo(), cipher(), hash(), hash() | default_prf}. + | {ssl:key_algo(), internal_cipher(), internal_hash(), + internal_hash() | default_prf}. -type cipher_suite() :: binary(). -type openssl_cipher_suite() :: string(). @@ -53,7 +52,7 @@ openssl_suite/1, openssl_suite_name/1]). %%-------------------------------------------------------------------- --spec suite_to_str(erl_cipher_suite()) -> string(). +-spec suite_to_str(internal_erl_cipher_suite()) -> string(). %% %% Description: Return the string representation of a cipher suite. %%-------------------------------------------------------------------- @@ -77,7 +76,7 @@ suite_to_str(#{key_exchange := Kex, "_" ++ string:to_upper(atom_to_list(Mac)). %%-------------------------------------------------------------------- --spec suite_definition(cipher_suite()) -> erl_cipher_suite(). +-spec suite_definition(cipher_suite()) -> internal_erl_cipher_suite(). %% %% Description: Return erlang cipher suite definition. %% Note: Currently not supported suites are commented away. @@ -805,7 +804,7 @@ suite_definition(?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256) -> prf => sha256}. %%-------------------------------------------------------------------- --spec erl_suite_definition(cipher_suite() | erl_cipher_suite()) -> old_erl_cipher_suite(). +-spec erl_suite_definition(cipher_suite() | internal_erl_cipher_suite()) -> old_erl_cipher_suite(). %% %% Description: Return erlang cipher suite definition. Filters last value %% for now (compatibility reasons). @@ -822,7 +821,7 @@ erl_suite_definition(#{key_exchange := KeyExchange, cipher := Cipher, end. %%-------------------------------------------------------------------- --spec suite(erl_cipher_suite()) -> cipher_suite(). +-spec suite(internal_erl_cipher_suite()) -> cipher_suite(). %% %% Description: Return TLS cipher suite definition. %%-------------------------------------------------------------------- @@ -1585,7 +1584,7 @@ openssl_suite("ECDH-RSA-AES256-GCM-SHA384") -> ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384. %%-------------------------------------------------------------------- --spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite() | erl_cipher_suite(). +-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite() | internal_erl_cipher_suite(). %% %% Description: Return openssl cipher suite name if possible %%------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 4b406b4c1e..41a45089d0 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -51,7 +51,7 @@ %% Alert and close handling -export([handle_own_alert/4, handle_alert/3, - handle_normal_shutdown/3, stop/2, stop_and_reply/3, + handle_normal_shutdown/3, handle_trusted_certs_db/1]). %% Data handling @@ -77,7 +77,7 @@ %%==================================================================== %%-------------------------------------------------------------------- -spec connect(tls_connection | dtls_connection, - host(), inet:port_number(), + ssl:host(), inet:port_number(), port() | {tuple(), port()}, %% TLS | DTLS {#ssl_options{}, #socket_options{}, %% Tracker only needed on server side @@ -143,7 +143,7 @@ handshake(#sslsocket{pid = [Pid|_]} = Socket, SslOptions, Timeout) -> end. %%-------------------------------------------------------------------- --spec handshake_continue(#sslsocket{}, [ssl_option()], +-spec handshake_continue(#sslsocket{}, [ssl:tls_server_option()], timeout()) -> {ok, #sslsocket{}}| {error, reason()}. %% %% Description: Continues handshake with new options @@ -335,8 +335,8 @@ prf(ConnectionPid, Secret, Label, Seed, WantedLength) -> %% Alert and close handling %%==================================================================== handle_own_alert(Alert, _, StateName, - #state{role = Role, - protocol_cb = Connection, + #state{static_env = #static_env{role = Role, + protocol_cb = Connection}, ssl_options = SslOpts} = State) -> try %% Try to tell the other side send_alert(Alert, StateName, State) @@ -349,77 +349,95 @@ handle_own_alert(Alert, _, StateName, catch _:_ -> ok end, - stop({shutdown, own_alert}, State). - -handle_normal_shutdown(Alert, _, #state{socket = Socket, - transport_cb = Transport, - protocol_cb = Connection, - start_or_recv_from = StartFrom, - tracker = Tracker, - role = Role, renegotiation = {false, first}} = State) -> + {stop, {shutdown, own_alert}, State}. + +handle_normal_shutdown(Alert, _, #state{static_env = #static_env{role = Role, + socket = Socket, + transport_cb = Transport, + protocol_cb = Connection, + tracker = Tracker}, + handshake_env = #handshake_env{renegotiation = {false, first}}, + start_or_recv_from = StartFrom} = State) -> Pids = Connection:pids(State), alert_user(Pids, Transport, Tracker,Socket, StartFrom, Alert, Role, Connection); -handle_normal_shutdown(Alert, StateName, #state{socket = Socket, - socket_options = Opts, - transport_cb = Transport, - protocol_cb = Connection, - user_application = {_Mon, Pid}, - tracker = Tracker, - start_or_recv_from = RecvFrom, role = Role} = State) -> +handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = Role, + socket = Socket, + transport_cb = Transport, + protocol_cb = Connection, + tracker = Tracker}, + socket_options = Opts, + user_application = {_Mon, Pid}, + start_or_recv_from = RecvFrom} = State) -> Pids = Connection:pids(State), alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection). handle_alert(#alert{level = ?FATAL} = Alert, StateName, - #state{socket = Socket, transport_cb = Transport, - protocol_cb = Connection, - ssl_options = SslOpts, start_or_recv_from = From, host = Host, - port = Port, session = Session, user_application = {_Mon, Pid}, - role = Role, socket_options = Opts, tracker = Tracker} = State) -> + #state{static_env = #static_env{role = Role, + socket = Socket, + host = Host, + port = Port, + tracker = Tracker, + transport_cb = Transport, + protocol_cb = Connection}, + ssl_options = SslOpts, + start_or_recv_from = From, + session = Session, user_application = {_Mon, Pid}, + socket_options = Opts} = State) -> invalidate_session(Role, Host, Port, Session), log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}), Pids = Connection:pids(State), alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role, Connection), - stop(normal, State); + {stop, {shutdown, normal}, State}; handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert, - StateName, State) -> + downgrade= StateName, State) -> + {next_state, StateName, State, [{next_event, internal, Alert}]}; +handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert, + StateName, State) -> handle_normal_shutdown(Alert, StateName, State), - stop({shutdown, peer_close}, State); - + {stop,{shutdown, peer_close}, State}; handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName, - #state{role = Role, ssl_options = SslOpts, protocol_cb = Connection, - renegotiation = {true, internal}} = State) -> + #state{static_env = #static_env{role = Role, + protocol_cb = Connection}, + handshake_env = #handshake_env{renegotiation = {true, internal}}, + ssl_options = SslOpts} = State) -> log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}), handle_normal_shutdown(Alert, StateName, State), - stop({shutdown, peer_close}, State); + {stop,{shutdown, peer_close}, State}; handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, connection = StateName, - #state{role = Role, - ssl_options = SslOpts, renegotiation = {true, From}, - protocol_cb = Connection} = State0) -> + #state{static_env = #static_env{role = Role, + protocol_cb = Connection}, + handshake_env = #handshake_env{renegotiation = {true, From}} = HsEnv, + ssl_options = SslOpts + } = State0) -> log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}), gen_statem:reply(From, {error, renegotiation_rejected}), State = Connection:reinit_handshake_data(State0), - Connection:next_event(connection, no_record, State#state{renegotiation = undefined}); + Connection:next_event(connection, no_record, State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}}); handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName, - #state{role = Role, - ssl_options = SslOpts, renegotiation = {true, From}, - protocol_cb = Connection} = State0) -> + #state{static_env = #static_env{role = Role, + protocol_cb = Connection}, + handshake_env = #handshake_env{renegotiation = {true, From}} = HsEnv, + ssl_options = SslOpts + } = State0) -> log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}), gen_statem:reply(From, {error, renegotiation_rejected}), %% Go back to connection! - State = Connection:reinit(State0#state{renegotiation = undefined}), + State = Connection:reinit(State0#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}}), Connection:next_event(connection, no_record, State); %% Gracefully log and ignore all other warning alerts handle_alert(#alert{level = ?WARNING} = Alert, StateName, - #state{ssl_options = SslOpts, protocol_cb = Connection, role = Role} = State) -> + #state{static_env = #static_env{role = Role, + protocol_cb = Connection}, + ssl_options = SslOpts} = State) -> log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}), Connection:next_event(StateName, no_record, State). @@ -427,7 +445,6 @@ handle_alert(#alert{level = ?WARNING} = Alert, StateName, %%==================================================================== %% Data handling %%==================================================================== - passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName, Connection) -> case Buffer of <<>> -> @@ -442,89 +459,106 @@ passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName, Connectio end end. -read_application_data(Data, #state{user_application = {_Mon, Pid}, - socket = Socket, - protocol_cb = Connection, - transport_cb = Transport, - socket_options = SOpts, - bytes_to_read = BytesToRead, - start_or_recv_from = RecvFrom, - timer = Timer, - user_data_buffer = Buffer0, - tracker = Tracker} = State0) -> - Buffer1 = if - Buffer0 =:= <<>> -> Data; - Data =:= <<>> -> Buffer0; - true -> <<Buffer0/binary, Data/binary>> - end, - case get_data(SOpts, BytesToRead, Buffer1) of +read_application_data( + Data, + #state{ + user_data_buffer = Buffer0, + erl_dist_handle = DHandle} = State) -> + %% + Buffer = bincat(Buffer0, Data), + case DHandle of + undefined -> + #state{ + socket_options = SocketOpts, + bytes_to_read = BytesToRead, + start_or_recv_from = RecvFrom, + timer = Timer} = State, + read_application_data( + Buffer, State, SocketOpts, RecvFrom, Timer, BytesToRead); + _ -> + try read_application_dist_data(Buffer, State, DHandle) + catch error:_ -> + {stop,disconnect, + State#state{ + user_data_buffer = Buffer, + bytes_to_read = undefined}} + end + end. + +read_application_dist_data(Buffer, State, DHandle) -> + case Buffer of + <<Size:32,Data:Size/binary>> -> + erlang:dist_ctrl_put_data(DHandle, Data), + {no_record, + State#state{ + user_data_buffer = <<>>, + bytes_to_read = undefined}}; + <<Size:32,Data:Size/binary,Rest/binary>> -> + erlang:dist_ctrl_put_data(DHandle, Data), + read_application_dist_data(Rest, State, DHandle); + _ -> + {no_record, + State#state{ + user_data_buffer = Buffer, + bytes_to_read = undefined}} + end. + +read_application_data( + Buffer0, State, SocketOpts0, RecvFrom, Timer, BytesToRead) -> + %% + case get_data(SocketOpts0, BytesToRead, Buffer0) of {ok, ClientData, Buffer} -> % Send data - #state{ssl_options = #ssl_options{erl_dist = Dist}, - erl_dist_data = DistData} = State0, - case Dist andalso is_dist_up(DistData) of - true -> - dist_app_data(ClientData, State0#state{user_data_buffer = Buffer, - bytes_to_read = undefined}); - _ -> - SocketOpt = - deliver_app_data(Connection:pids(State0), - Transport, Socket, SOpts, - ClientData, Pid, RecvFrom, Tracker, Connection), - cancel_timer(Timer), - State = - State0#state{ - user_data_buffer = Buffer, - start_or_recv_from = undefined, - timer = undefined, - bytes_to_read = undefined, - socket_options = SocketOpt - }, - if - SocketOpt#socket_options.active =:= false; - Buffer =:= <<>> -> - %% Passive mode, wait for active once or recv - %% Active and empty, get more data - {no_record, State}; - true -> %% We have more data - read_application_data(<<>>, State) - end - end; + #state{ + static_env = + #static_env{ + socket = Socket, + protocol_cb = Connection, + transport_cb = Transport, + tracker = Tracker}, + user_application = {_Mon, Pid}} = State, + SocketOpts = + deliver_app_data( + Connection:pids(State), + Transport, Socket, SocketOpts0, + ClientData, Pid, RecvFrom, Tracker, Connection), + cancel_timer(Timer), + if + SocketOpts#socket_options.active =:= false; + Buffer =:= <<>> -> + %% Passive mode, wait for active once or recv + %% Active and empty, get more data + {no_record, + State#state{ + user_data_buffer = Buffer, + start_or_recv_from = undefined, + timer = undefined, + bytes_to_read = undefined, + socket_options = SocketOpts + }}; + true -> %% We have more data + read_application_data( + Buffer, State, SocketOpts, + undefined, undefined, undefined) + end; {more, Buffer} -> % no reply, we need more data - {no_record, State0#state{user_data_buffer = Buffer}}; + {no_record, State#state{user_data_buffer = Buffer}}; {passive, Buffer} -> - {no_record, State0#state{user_data_buffer = Buffer}}; + {no_record, State#state{user_data_buffer = Buffer}}; {error,_Reason} -> %% Invalid packet in packet mode - deliver_packet_error(Connection:pids(State0), - Transport, Socket, SOpts, Buffer1, Pid, RecvFrom, Tracker, Connection), - stop(normal, State0) + #state{ + static_env = + #static_env{ + socket = Socket, + protocol_cb = Connection, + transport_cb = Transport, + tracker = Tracker}, + user_application = {_Mon, Pid}} = State, + deliver_packet_error( + Connection:pids(State), Transport, Socket, SocketOpts0, + Buffer0, Pid, RecvFrom, Tracker, Connection), + {stop, {shutdown, normal}, State} end. -dist_app_data(ClientData, #state{erl_dist_data = #{dist_handle := undefined, - dist_buffer := DistBuff} = DistData} = State) -> - {no_record, State#state{erl_dist_data = DistData#{dist_buffer => [ClientData, DistBuff]}}}; -dist_app_data(ClientData, #state{erl_dist_data = #{dist_handle := DHandle, - dist_buffer := DistBuff} = ErlDistData, - user_data_buffer = Buffer, - socket_options = SOpts} = State) -> - Data = merge_dist_data(DistBuff, ClientData), - try erlang:dist_ctrl_put_data(DHandle, Data) of - _ when SOpts#socket_options.active =:= false; - Buffer =:= <<>> -> - %% Passive mode, wait for active once or recv - %% Active and empty, get more data - {no_record, State#state{erl_dist_data = ErlDistData#{dist_buffer => <<>>}}}; - _ -> %% We have more data - read_application_data(<<>>, State) - catch error:_ -> - stop(State, disconnect) - end. - -merge_dist_data(<<>>, ClientData) -> - ClientData; -merge_dist_data(DistBuff, <<>>) -> - DistBuff; -merge_dist_data(DistBuff, ClientData) -> - [DistBuff, ClientData]. %%==================================================================== %% Help functions for tls|dtls_connection.erl %%==================================================================== @@ -573,7 +607,8 @@ handle_session(#server_hello{cipher_suite = CipherSuite, ssl_config(Opts, Role, State) -> ssl_config(Opts, Role, State, new). -ssl_config(Opts, Role, State0, Type) -> +ssl_config(Opts, Role, #state{static_env = InitStatEnv0, + handshake_env = HsEnv} = State0, Type) -> {ok, #{cert_db_ref := Ref, cert_db_handle := CertDbHandle, fileref_db_handle := FileRefHandle, @@ -585,20 +620,23 @@ ssl_config(Opts, Role, State0, Type) -> ssl_config:init(Opts, Role), TimeStamp = erlang:monotonic_time(), Session = State0#state.session, + State = State0#state{session = Session#session{own_certificate = OwnCert, time_stamp = TimeStamp}, - file_ref_db = FileRefHandle, - cert_db_ref = Ref, - cert_db = CertDbHandle, - crl_db = CRLDbHandle, - session_cache = CacheHandle, + static_env = InitStatEnv0#static_env{ + file_ref_db = FileRefHandle, + cert_db_ref = Ref, + cert_db = CertDbHandle, + crl_db = CRLDbHandle, + session_cache = CacheHandle + }, private_key = Key, diffie_hellman_params = DHParams, ssl_options = Opts}, case Type of new -> - Handshake = ssl_handshake:init_handshake_history(), - State#state{tls_handshake_history = Handshake}; + Hist = ssl_handshake:init_handshake_history(), + State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}; continue -> State end. @@ -618,7 +656,8 @@ init({call, From}, {start, Timeout}, State0, Connection) -> Timer = start_or_recv_cancel_timer(Timeout, From), Connection:next_event(hello, no_record, State0#state{start_or_recv_from = From, timer = Timer}); init({call, From}, {start, {Opts, EmOpts}, Timeout}, - #state{role = Role, ssl_options = OrigSSLOptions, + #state{static_env = #static_env{role = Role}, + ssl_options = OrigSSLOptions, socket_options = SockOpts} = State0, Connection) -> try SslOpts = ssl:handle_options(Opts, OrigSSLOptions), @@ -627,7 +666,7 @@ init({call, From}, {start, {Opts, EmOpts}, Timeout}, State#state{ssl_options = SslOpts, socket_options = new_emulated(EmOpts, SockOpts)}, Connection) catch throw:Error -> - stop_and_reply(normal, {reply, From, {error, Error}}, State0) + {stop_and_reply, {shutdown, normal}, {reply, From, {error, Error}}, State0} end; init({call, From}, {new_user, _} = Msg, State, Connection) -> handle_call(Msg, From, ?FUNCTION_NAME, State, Connection); @@ -643,7 +682,7 @@ init(_Type, _Event, _State, _Connection) -> gen_statem:state_function_result(). %%-------------------------------------------------------------------- error({call, From}, {close, _}, State, _Connection) -> - stop_and_reply(normal, {reply, From, ok}, State); + {stop_and_reply, {shutdown, normal}, {reply, From, ok}, State}; error({call, From}, _Msg, State, _Connection) -> {next_state, ?FUNCTION_NAME, State, [{reply, From, {error, closed}}]}. @@ -666,10 +705,11 @@ user_hello({call, From}, cancel, #state{negotiated_version = Version} = State, _ gen_statem:reply(From, ok), handle_own_alert(?ALERT_REC(?FATAL, ?USER_CANCELED, user_canceled), Version, ?FUNCTION_NAME, State); -user_hello({call, From}, {handshake_continue, NewOptions, Timeout}, #state{hello = Hello, - role = Role, - start_or_recv_from = RecvFrom, - ssl_options = Options0} = State0, _Connection) -> +user_hello({call, From}, {handshake_continue, NewOptions, Timeout}, + #state{hello = Hello, + static_env = #static_env{role = Role}, + start_or_recv_from = RecvFrom, + ssl_options = Options0} = State0, _Connection) -> Timer = start_or_recv_cancel_timer(Timeout, RecvFrom), Options = ssl:handle_options(NewOptions, Options0#ssl_options{handshake = full}), State = ssl_config(Options, Role, State0, continue), @@ -688,16 +728,16 @@ user_hello(_, _, _, _) -> abbreviated({call, From}, Msg, State, Connection) -> handle_call(Msg, From, ?FUNCTION_NAME, State, Connection); abbreviated(internal, #finished{verify_data = Data} = Finished, - #state{role = server, + #state{static_env = #static_env{role = server}, + handshake_env = #handshake_env{tls_handshake_history = Hist}, negotiated_version = Version, expecting_finished = true, - tls_handshake_history = Handshake, session = #session{master_secret = MasterSecret}, connection_states = ConnectionStates0} = State0, Connection) -> case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, client, get_current_prf(ConnectionStates0, write), - MasterSecret, Handshake) of + MasterSecret, Hist) of verified -> ConnectionStates = ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0), @@ -708,13 +748,14 @@ abbreviated(internal, #finished{verify_data = Data} = Finished, handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0) end; abbreviated(internal, #finished{verify_data = Data} = Finished, - #state{role = client, tls_handshake_history = Handshake0, + #state{static_env = #static_env{role = client}, + handshake_env = #handshake_env{tls_handshake_history = Hist0}, session = #session{master_secret = MasterSecret}, negotiated_version = Version, connection_states = ConnectionStates0} = State0, Connection) -> case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, server, get_pending_prf(ConnectionStates0, write), - MasterSecret, Handshake0) of + MasterSecret, Hist0) of verified -> ConnectionStates1 = ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0), @@ -729,7 +770,8 @@ abbreviated(internal, #finished{verify_data = Data} = Finished, %% only allowed to send next_protocol message after change cipher spec %% & before finished message and it is not allowed during renegotiation abbreviated(internal, #next_protocol{selected_protocol = SelectedProtocol}, - #state{role = server, expecting_next_protocol_negotiation = true} = State, + #state{static_env = #static_env{role = server}, + expecting_next_protocol_negotiation = true} = State, Connection) -> Connection:next_event(?FUNCTION_NAME, no_record, State#state{negotiated_protocol = SelectedProtocol, @@ -759,32 +801,34 @@ certify({call, From}, Msg, State, Connection) -> certify(info, Msg, State, _) -> handle_info(Msg, ?FUNCTION_NAME, State); certify(internal, #certificate{asn1_certificates = []}, - #state{role = server, negotiated_version = Version, + #state{static_env = #static_env{role = server}, + negotiated_version = Version, ssl_options = #ssl_options{verify = verify_peer, fail_if_no_peer_cert = true}} = State, _) -> Alert = ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE), handle_own_alert(Alert, Version, ?FUNCTION_NAME, State); certify(internal, #certificate{asn1_certificates = []}, - #state{role = server, + #state{static_env = #static_env{role = server}, ssl_options = #ssl_options{verify = verify_peer, fail_if_no_peer_cert = false}} = State0, Connection) -> Connection:next_event(?FUNCTION_NAME, no_record, State0#state{client_certificate_requested = false}); certify(internal, #certificate{}, - #state{role = server, + #state{static_env = #static_env{role = server}, negotiated_version = Version, ssl_options = #ssl_options{verify = verify_none}} = State, _) -> Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, unrequested_certificate), handle_own_alert(Alert, Version, ?FUNCTION_NAME, State); certify(internal, #certificate{} = Cert, - #state{negotiated_version = Version, - role = Role, - host = Host, - cert_db = CertDbHandle, - cert_db_ref = CertDbRef, - crl_db = CRLDbInfo, + #state{static_env = #static_env{ + role = Role, + host = Host, + cert_db = CertDbHandle, + cert_db_ref = CertDbRef, + crl_db = CRLDbInfo}, + negotiated_version = Version, ssl_options = Opts} = State, Connection) -> case ssl_handshake:certify(Cert, CertDbHandle, CertDbRef, Opts, CRLDbInfo, Role, Host) of @@ -795,7 +839,8 @@ certify(internal, #certificate{} = Cert, handle_own_alert(Alert, Version, ?FUNCTION_NAME, State) end; certify(internal, #server_key_exchange{exchange_keys = Keys}, - #state{role = client, negotiated_version = Version, + #state{static_env = #static_env{role = client}, + negotiated_version = Version, key_algorithm = Alg, public_key_info = PubKeyInfo, session = Session, @@ -829,7 +874,8 @@ certify(internal, #server_key_exchange{exchange_keys = Keys}, end end; certify(internal, #certificate_request{}, - #state{role = client, negotiated_version = Version, + #state{static_env = #static_env{role = client}, + negotiated_version = Version, key_algorithm = Alg} = State, _) when Alg == dh_anon; Alg == ecdh_anon; Alg == psk; Alg == dhe_psk; Alg == ecdhe_psk; Alg == rsa_psk; @@ -837,17 +883,17 @@ certify(internal, #certificate_request{}, handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Version, ?FUNCTION_NAME, State); certify(internal, #certificate_request{}, - #state{session = #session{own_certificate = undefined}, - role = client} = State, Connection) -> + #state{static_env = #static_env{role = client}, + session = #session{own_certificate = undefined}} = State, Connection) -> %% The client does not have a certificate and will send an empty reply, the server may fail %% or accept the connection by its own preference. No signature algorihms needed as there is %% no certificate to verify. Connection:next_event(?FUNCTION_NAME, no_record, State#state{client_certificate_requested = true}); certify(internal, #certificate_request{} = CertRequest, - #state{session = #session{own_certificate = Cert}, - role = client, - ssl_options = #ssl_options{signature_algs = SupportedHashSigns}, - negotiated_version = Version} = State, Connection) -> + #state{static_env = #static_env{role = client}, + session = #session{own_certificate = Cert}, + ssl_options = #ssl_options{signature_algs = SupportedHashSigns}, + negotiated_version = Version} = State, Connection) -> case ssl_handshake:select_hashsign(CertRequest, Cert, SupportedHashSigns, ssl:tls_version(Version)) of #alert {} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State); @@ -858,12 +904,12 @@ certify(internal, #certificate_request{} = CertRequest, end; %% PSK and RSA_PSK might bypass the Server-Key-Exchange certify(internal, #server_hello_done{}, - #state{session = #session{master_secret = undefined}, + #state{static_env = #static_env{role = client}, + session = #session{master_secret = undefined}, negotiated_version = Version, psk_identity = PSKIdentity, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, premaster_secret = undefined, - role = client, key_algorithm = Alg} = State0, Connection) when Alg == psk -> case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup) of @@ -875,12 +921,12 @@ certify(internal, #server_hello_done{}, client_certify_and_key_exchange(State, Connection) end; certify(internal, #server_hello_done{}, - #state{session = #session{master_secret = undefined}, + #state{static_env = #static_env{role = client}, + session = #session{master_secret = undefined}, ssl_options = #ssl_options{user_lookup_fun = PSKLookup}, negotiated_version = {Major, Minor} = Version, psk_identity = PSKIdentity, premaster_secret = undefined, - role = client, key_algorithm = Alg} = State0, Connection) when Alg == rsa_psk -> Rand = ssl_cipher:random_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2), @@ -896,11 +942,11 @@ certify(internal, #server_hello_done{}, end; %% Master secret was determined with help of server-key exchange msg certify(internal, #server_hello_done{}, - #state{session = #session{master_secret = MasterSecret} = Session, + #state{static_env = #static_env{role = client}, + session = #session{master_secret = MasterSecret} = Session, connection_states = ConnectionStates0, negotiated_version = Version, - premaster_secret = undefined, - role = client} = State0, Connection) -> + premaster_secret = undefined} = State0, Connection) -> case ssl_handshake:master_secret(ssl:tls_version(Version), Session, ConnectionStates0, client) of {MasterSecret, ConnectionStates} -> @@ -911,11 +957,11 @@ certify(internal, #server_hello_done{}, end; %% Master secret is calculated from premaster_secret certify(internal, #server_hello_done{}, - #state{session = Session0, + #state{static_env = #static_env{role = client}, + session = Session0, connection_states = ConnectionStates0, negotiated_version = Version, - premaster_secret = PremasterSecret, - role = client} = State0, Connection) -> + premaster_secret = PremasterSecret} = State0, Connection) -> case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret, ConnectionStates0, client) of {MasterSecret, ConnectionStates} -> @@ -927,7 +973,7 @@ certify(internal, #server_hello_done{}, handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0) end; certify(internal = Type, #client_key_exchange{} = Msg, - #state{role = server, + #state{static_env = #static_env{role = server}, client_certificate_requested = true, ssl_options = #ssl_options{fail_if_no_peer_cert = true}} = State, Connection) -> @@ -957,19 +1003,19 @@ cipher(info, Msg, State, _) -> handle_info(Msg, ?FUNCTION_NAME, State); cipher(internal, #certificate_verify{signature = Signature, hashsign_algorithm = CertHashSign}, - #state{role = server, + #state{static_env = #static_env{role = server}, + handshake_env = #handshake_env{tls_handshake_history = Hist}, key_algorithm = KexAlg, public_key_info = PublicKeyInfo, negotiated_version = Version, - session = #session{master_secret = MasterSecret}, - tls_handshake_history = Handshake + session = #session{master_secret = MasterSecret} } = State, Connection) -> TLSVersion = ssl:tls_version(Version), %% Use negotiated value if TLS-1.2 otherwhise return default HashSign = negotiated_hashsign(CertHashSign, KexAlg, PublicKeyInfo, TLSVersion), case ssl_handshake:certificate_verify(Signature, PublicKeyInfo, - TLSVersion, HashSign, MasterSecret, Handshake) of + TLSVersion, HashSign, MasterSecret, Hist) of valid -> Connection:next_event(?FUNCTION_NAME, no_record, State#state{cert_hashsign_algorithm = HashSign}); @@ -978,27 +1024,28 @@ cipher(internal, #certificate_verify{signature = Signature, end; %% client must send a next protocol message if we are expecting it cipher(internal, #finished{}, - #state{role = server, expecting_next_protocol_negotiation = true, + #state{static_env = #static_env{role = server}, + expecting_next_protocol_negotiation = true, negotiated_protocol = undefined, negotiated_version = Version} = State0, _Connection) -> handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, ?FUNCTION_NAME, State0); cipher(internal, #finished{verify_data = Data} = Finished, - #state{negotiated_version = Version, - host = Host, - port = Port, - role = Role, - expecting_finished = true, + #state{static_env = #static_env{role = Role, + host = Host, + port = Port}, + negotiated_version = Version, + expecting_finished = true, session = #session{master_secret = MasterSecret} = Session0, ssl_options = SslOpts, connection_states = ConnectionStates0, - tls_handshake_history = Handshake0} = State, Connection) -> + handshake_env = #handshake_env{tls_handshake_history = Hist}} = State, Connection) -> case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, opposite_role(Role), get_current_prf(ConnectionStates0, read), - MasterSecret, Handshake0) of + MasterSecret, Hist) of verified -> - Session = register_session(Role, host_id(Role, Host, SslOpts), Port, Session0), + Session = handle_session(Role, SslOpts, Host, Port, Session0), cipher_role(Role, Data, Session, State#state{expecting_finished = false}, Connection); #alert{} = Alert -> @@ -1007,12 +1054,13 @@ cipher(internal, #finished{verify_data = Data} = Finished, %% only allowed to send next_protocol message after change cipher spec %% & before finished message and it is not allowed during renegotiation cipher(internal, #next_protocol{selected_protocol = SelectedProtocol}, - #state{role = server, expecting_next_protocol_negotiation = true, - expecting_finished = true} = State, Connection) -> - Connection:next_event(?FUNCTION_NAME, no_record, - State#state{expecting_next_protocol_negotiation = false, - negotiated_protocol = SelectedProtocol - }); + #state{static_env = #static_env{role = server}, + expecting_next_protocol_negotiation = true, + expecting_finished = true} = State0, Connection) -> + {Record, State} = + Connection:next_record(State0#state{negotiated_protocol = SelectedProtocol}), + Connection:next_event(?FUNCTION_NAME, Record, + State#state{expecting_next_protocol_negotiation = false}); cipher(internal, #change_cipher_spec{type = <<1>>}, #state{connection_states = ConnectionStates0} = State, Connection) -> ConnectionStates = @@ -1029,15 +1077,18 @@ cipher(Type, Msg, State, Connection) -> gen_statem:state_function_result(). %%-------------------------------------------------------------------- connection({call, RecvFrom}, {recv, N, Timeout}, - #state{protocol_cb = Connection, socket_options = - #socket_options{active = false}} = State0, Connection) -> + #state{static_env = #static_env{protocol_cb = Connection}, + socket_options = + #socket_options{active = false}} = State0, Connection) -> Timer = start_or_recv_cancel_timer(Timeout, RecvFrom), passive_receive(State0#state{bytes_to_read = N, start_or_recv_from = RecvFrom, timer = Timer}, ?FUNCTION_NAME, Connection); -connection({call, From}, renegotiate, #state{protocol_cb = Connection} = State, + +connection({call, From}, renegotiate, #state{static_env = #static_env{protocol_cb = Connection}, + handshake_env = HsEnv} = State, Connection) -> - Connection:renegotiate(State#state{renegotiation = {true, From}}, []); + Connection:renegotiate(State#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, From}}}, []); connection({call, From}, peer_certificate, #state{session = #session{peer_certificate = Cert}} = State, _) -> hibernate_after(?FUNCTION_NAME, State, [{reply, From, {ok, Cert}}]); @@ -1056,22 +1107,22 @@ connection({call, From}, negotiated_protocol, [{reply, From, {ok, SelectedProtocol}}]); connection({call, From}, Msg, State, Connection) -> handle_call(Msg, From, ?FUNCTION_NAME, State, Connection); -connection(cast, {internal_renegotiate, WriteState}, #state{protocol_cb = Connection, +connection(cast, {internal_renegotiate, WriteState}, #state{static_env = #static_env{protocol_cb = Connection}, + handshake_env = HsEnv, connection_states = ConnectionStates} = State, Connection) -> - Connection:renegotiate(State#state{renegotiation = {true, internal}, + Connection:renegotiate(State#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, internal}}, connection_states = ConnectionStates#{current_write => WriteState}}, []); connection(cast, {dist_handshake_complete, DHandle}, #state{ssl_options = #ssl_options{erl_dist = true}, - erl_dist_data = ErlDistData, socket_options = SockOpts} = State0, Connection) -> process_flag(priority, normal), State1 = State0#state{ - socket_options = - SockOpts#socket_options{active = true}, - erl_dist_data = ErlDistData#{dist_handle => DHandle}}, - {Record, State} = dist_app_data(<<>>, State1), + socket_options = SockOpts#socket_options{active = true}, + erl_dist_handle = DHandle, + bytes_to_read = undefined}, + {Record, State} = read_application_data(<<>>, State1), Connection:next_event(connection, Record, State); connection(info, Msg, State, _) -> handle_info(Msg, ?FUNCTION_NAME, State); @@ -1085,22 +1136,6 @@ connection(Type, Msg, State, Connection) -> #state{}, tls_connection | dtls_connection) -> gen_statem:state_function_result(). %%-------------------------------------------------------------------- -downgrade(internal, #alert{description = ?CLOSE_NOTIFY}, - #state{transport_cb = Transport, socket = Socket, - downgrade = {Pid, From}} = State, _) -> - tls_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]), - Transport:controlling_process(Socket, Pid), - gen_statem:reply(From, {ok, Socket}), - stop(normal, State); -downgrade(timeout, downgrade, #state{downgrade = {_, From}} = State, _) -> - gen_statem:reply(From, {error, timeout}), - stop(normal, State); -downgrade( - info, {CloseTag, Socket}, - #state{socket = Socket, close_tag = CloseTag, downgrade = {_, From}} = - State, _) -> - gen_statem:reply(From, {error, CloseTag}), - stop(normal, State); downgrade(Type, Event, State, Connection) -> handle_common_event(Type, Event, ?FUNCTION_NAME, State, Connection). @@ -1109,14 +1144,17 @@ downgrade(Type, Event, State, Connection) -> %% common or unexpected events for the state. %%-------------------------------------------------------------------- handle_common_event(internal, {handshake, {#hello_request{} = Handshake, _}}, connection = StateName, - #state{role = client} = State, _) -> + #state{static_env = #static_env{role = client}, + handshake_env = HsEnv} = State, _) -> %% Should not be included in handshake history - {next_state, StateName, State#state{renegotiation = {true, peer}}, [{next_event, internal, Handshake}]}; -handle_common_event(internal, {handshake, {#hello_request{}, _}}, StateName, #state{role = client}, _) + {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, peer}}}, + [{next_event, internal, Handshake}]}; +handle_common_event(internal, {handshake, {#hello_request{}, _}}, StateName, + #state{static_env = #static_env{role = client}}, _) when StateName =/= connection -> - {keep_state_and_data}; + keep_state_and_data; handle_common_event(internal, {handshake, {Handshake, Raw}}, StateName, - #state{tls_handshake_history = Hs0} = State0, + #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv} = State0, Connection) -> PossibleSNI = Connection:select_sni_extension(Handshake), @@ -1124,27 +1162,14 @@ handle_common_event(internal, {handshake, {Handshake, Raw}}, StateName, %% a client_hello, which needs to be determined by the connection callback. %% In other cases this is a noop State = handle_sni_extension(PossibleSNI, State0), - HsHist = ssl_handshake:update_handshake_history(Hs0, iolist_to_binary(Raw)), - {next_state, StateName, State#state{tls_handshake_history = HsHist}, + + Hist = ssl_handshake:update_handshake_history(Hist0, Raw), + {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}, [{next_event, internal, Handshake}]}; handle_common_event(internal, {protocol_record, TLSorDTLSRecord}, StateName, State, Connection) -> - Connection:handle_common_event(internal, TLSorDTLSRecord, StateName, State); + Connection:handle_protocol_record(TLSorDTLSRecord, StateName, State); handle_common_event(timeout, hibernate, _, _, _) -> {keep_state_and_data, [hibernate]}; -handle_common_event(internal, {application_data, Data}, StateName, State0, Connection) -> - case read_application_data(Data, State0) of - {stop, _, _} = Stop-> - Stop; - {Record, State1} -> - case Connection:next_event(StateName, Record, State1) of - {next_state, StateName, State} -> - hibernate_after(StateName, State, []); - {next_state, StateName, State, Actions} -> - hibernate_after(StateName, State, Actions); - {stop, _, _} = Stop -> - Stop - end - end; handle_common_event(internal, #change_cipher_spec{type = <<1>>}, StateName, #state{negotiated_version = Version} = State, _) -> handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Version, @@ -1157,47 +1182,37 @@ handle_common_event(_Type, Msg, StateName, #state{negotiated_version = Version} handle_call({application_data, _Data}, _, _, _, _) -> %% In renegotiation priorities handshake, send data when handshake is finished {keep_state_and_data, [postpone]}; -handle_call({close, {Pid, Timeout}}, From, StateName, State0, Connection) when is_pid(Pid) -> - %% terminate will send close alert to peer - State = State0#state{downgrade = {Pid, From}}, - Connection:terminate(downgrade, StateName, State), - %% User downgrades connection - %% When downgrading an TLS connection to a transport connection - %% we must recive the close alert from the peer before releasing the - %% transport socket. - {next_state, downgrade, State#state{terminated = true}, [{timeout, Timeout, downgrade}]}; handle_call({close, _} = Close, From, StateName, State, _Connection) -> %% Run terminate before returning so that the reuseaddr %% inet-option works properly Result = terminate(Close, StateName, State), - stop_and_reply( - {shutdown, normal}, - {reply, From, Result}, State#state{terminated = true}); + {stop_and_reply, + {shutdown, normal}, + {reply, From, Result}, State#state{terminated = true}}; handle_call({shutdown, read_write = How}, From, StateName, - #state{transport_cb = Transport, - socket = Socket} = State, _) -> - + #state{static_env = #static_env{transport_cb = Transport, + socket = Socket}} = State, _) -> try send_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), - StateName, State) of + StateName, State) of _ -> case Transport:shutdown(Socket, How) of ok -> {next_state, StateName, State#state{terminated = true}, [{reply, From, ok}]}; Error -> - {stop, StateName, State#state{terminated = true}, [{reply, From, Error}]} + {stop_and_reply, {shutdown, normal}, {reply, From, Error}, State#state{terminated = true}} end catch throw:Return -> Return end; handle_call({shutdown, How0}, From, StateName, - #state{transport_cb = Transport, - socket = Socket} = State, _) -> + #state{static_env = #static_env{transport_cb = Transport, + socket = Socket}} = State, _) -> case Transport:shutdown(Socket, How0) of ok -> {next_state, StateName, State, [{reply, From, ok}]}; Error -> - {stop, StateName, State, [{reply, From, Error}]} + {stop_and_reply, {shutdown, normal}, {reply, From, Error}, State} end; handle_call({recv, _N, _Timeout}, From, _, #state{socket_options = @@ -1217,15 +1232,16 @@ handle_call({new_user, User}, From, StateName, {next_state, StateName, State#state{user_application = {NewMon,User}}, [{reply, From, ok}]}; handle_call({get_opts, OptTags}, From, _, - #state{socket = Socket, - transport_cb = Transport, + #state{static_env = #static_env{socket = Socket, + transport_cb = Transport}, socket_options = SockOpts}, Connection) -> OptsReply = get_socket_opts(Connection, Transport, Socket, OptTags, SockOpts, []), {keep_state_and_data, [{reply, From, OptsReply}]}; handle_call({set_opts, Opts0}, From, StateName, - #state{socket_options = Opts1, - socket = Socket, - transport_cb = Transport} = State0, Connection) -> + #state{static_env = #static_env{socket = Socket, + transport_cb = Transport}, + socket_options = Opts1 + } = State0, Connection) -> {Reply, Opts} = set_socket_opts(Connection, Transport, Socket, Opts0, Opts1, []), State = State0#state{socket_options = Opts}, handle_active_option(Opts#socket_options.active, StateName, From, Reply, State); @@ -1266,22 +1282,25 @@ handle_call(_,_,_,_,_) -> {keep_state_and_data, [postpone]}. handle_info({ErrorTag, Socket, econnaborted}, StateName, - #state{socket = Socket, transport_cb = Transport, - protocol_cb = Connection, - start_or_recv_from = StartFrom, role = Role, - error_tag = ErrorTag, - tracker = Tracker} = State) when StateName =/= connection -> + #state{static_env = #static_env{role = Role, + socket = Socket, + transport_cb = Transport, + error_tag = ErrorTag, + tracker = Tracker, + protocol_cb = Connection}, + start_or_recv_from = StartFrom + } = State) when StateName =/= connection -> Pids = Connection:pids(State), alert_user(Pids, Transport, Tracker,Socket, StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, Connection), - stop(normal, State); + {stop, {shutdown, normal}, State}; -handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket, - error_tag = ErrorTag} = State) -> +handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_env{socket = Socket, + error_tag = ErrorTag}} = State) -> Report = io_lib:format("SSL: Socket error: ~p ~n", [Reason]), error_logger:error_report(Report), handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State), - stop(normal, State); + {stop, {shutdown,normal}, State}; handle_info({'DOWN', MonitorRef, _, _, Reason}, _, #state{user_application = {MonitorRef, _Pid}, @@ -1289,7 +1308,7 @@ handle_info({'DOWN', MonitorRef, _, _, Reason}, _, {stop, {shutdown, Reason}}; handle_info({'DOWN', MonitorRef, _, _, _}, _, #state{user_application = {MonitorRef, _Pid}}) -> - {stop, normal}; + {stop, {shutdown, normal}}; handle_info({'EXIT', Pid, _Reason}, StateName, #state{user_application = {_MonitorRef, Pid}} = State) -> %% It seems the user application has linked to us @@ -1297,22 +1316,22 @@ handle_info({'EXIT', Pid, _Reason}, StateName, {next_state, StateName, State}; %%% So that terminate will be run when supervisor issues shutdown handle_info({'EXIT', _Sup, shutdown}, _StateName, State) -> - stop(shutdown, State); -handle_info({'EXIT', Socket, normal}, _StateName, #state{socket = Socket} = State) -> + {stop, shutdown, State}; +handle_info({'EXIT', Socket, normal}, _StateName, #state{static_env = #static_env{socket = Socket}} = State) -> %% Handle as transport close" - stop({shutdown, transport_closed}, State); -handle_info({'EXIT', Socket, Reason}, _StateName, #state{socket = Socket} = State) -> - stop({shutdown, Reason}, State); + {stop,{shutdown, transport_closed}, State}; +handle_info({'EXIT', Socket, Reason}, _StateName, #state{static_env = #static_env{socket = Socket}} = State) -> + {stop,{shutdown, Reason}, State}; handle_info(allow_renegotiate, StateName, State) -> {next_state, StateName, State#state{allow_renegotiate = true}}; handle_info({cancel_start_or_recv, StartFrom}, StateName, - #state{renegotiation = {false, first}} = State) when StateName =/= connection -> - stop_and_reply( - {shutdown, user_timeout}, - {reply, StartFrom, {error, timeout}}, - State#state{timer = undefined}); + #state{handshake_env = #handshake_env{renegotiation = {false, first}}} = State) when StateName =/= connection -> + {stop_and_reply, + {shutdown, user_timeout}, + {reply, StartFrom, {error, timeout}}, + State#state{timer = undefined}}; handle_info({cancel_start_or_recv, RecvFrom}, StateName, #state{start_or_recv_from = RecvFrom} = State) when RecvFrom =/= undefined -> {next_state, StateName, State#state{start_or_recv_from = undefined, @@ -1321,7 +1340,7 @@ handle_info({cancel_start_or_recv, RecvFrom}, StateName, handle_info({cancel_start_or_recv, _RecvFrom}, StateName, State) -> {next_state, StateName, State#state{timer = undefined}}; -handle_info(Msg, StateName, #state{socket = Socket, error_tag = Tag} = State) -> +handle_info(Msg, StateName, #state{static_env = #static_env{socket = Socket, error_tag = Tag}} = State) -> Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [{Msg, Tag, Socket}]), error_logger:info_report(Report), {next_state, StateName, State}. @@ -1338,14 +1357,15 @@ terminate(_, _, #state{terminated = true}) -> %% before run by gen_statem which will end up here ok; terminate({shutdown, transport_closed} = Reason, - _StateName, #state{protocol_cb = Connection, - socket = Socket, transport_cb = Transport} = State) -> + _StateName, #state{static_env = #static_env{protocol_cb = Connection, + socket = Socket, + transport_cb = Transport}} = State) -> handle_trusted_certs_db(State), Connection:close(Reason, Socket, Transport, undefined, undefined); terminate({shutdown, own_alert}, _StateName, #state{ - protocol_cb = Connection, - socket = Socket, - transport_cb = Transport} = State) -> + static_env = #static_env{protocol_cb = Connection, + socket = Socket, + transport_cb = Transport}} = State) -> handle_trusted_certs_db(State), case application:get_env(ssl, alert_timeout) of {ok, Timeout} when is_integer(Timeout) -> @@ -1353,23 +1373,27 @@ terminate({shutdown, own_alert}, _StateName, #state{ _ -> Connection:close({timeout, ?DEFAULT_TIMEOUT}, Socket, Transport, undefined, undefined) end; -terminate(downgrade = Reason, connection, #state{protocol_cb = Connection, - transport_cb = Transport, socket = Socket - } = State) -> +terminate({shutdown, downgrade = Reason}, downgrade, #state{static_env = #static_env{protocol_cb = Connection, + transport_cb = Transport, + socket = Socket} + } = State) -> handle_trusted_certs_db(State), Connection:close(Reason, Socket, Transport, undefined, undefined); -terminate(Reason, connection, #state{protocol_cb = Connection, +terminate(Reason, connection, #state{static_env = #static_env{ + protocol_cb = Connection, + transport_cb = Transport, + socket = Socket}, connection_states = ConnectionStates, - ssl_options = #ssl_options{padding_check = Check}, - transport_cb = Transport, socket = Socket + ssl_options = #ssl_options{padding_check = Check} } = State) -> handle_trusted_certs_db(State), Alert = terminate_alert(Reason), %% Send the termination ALERT if possible - catch (Connection:send_alert_in_connection(Alert, State)), + catch (ok = Connection:send_alert_in_connection(Alert, State)), Connection:close({timeout, ?DEFAULT_TIMEOUT}, Socket, Transport, ConnectionStates, Check); -terminate(Reason, _StateName, #state{transport_cb = Transport, protocol_cb = Connection, - socket = Socket +terminate(Reason, _StateName, #state{static_env = #static_env{transport_cb = Transport, + protocol_cb = Connection, + socket = Socket} } = State) -> handle_trusted_certs_db(State), Connection:close(Reason, Socket, Transport, undefined, undefined). @@ -1388,7 +1412,7 @@ format_status(terminate, [_, StateName, State]) -> [{data, [{"State", {StateName, State#state{connection_states = ?SECRET_PRINTOUT, protocol_buffers = ?SECRET_PRINTOUT, user_data_buffer = ?SECRET_PRINTOUT, - tls_handshake_history = ?SECRET_PRINTOUT, + handshake_env = ?SECRET_PRINTOUT, session = ?SECRET_PRINTOUT, private_key = ?SECRET_PRINTOUT, diffie_hellman_params = ?SECRET_PRINTOUT, @@ -1403,15 +1427,15 @@ format_status(terminate, [_, StateName, State]) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -send_alert(Alert, connection, #state{protocol_cb = Connection} = State) -> +send_alert(Alert, connection, #state{static_env = #static_env{protocol_cb = Connection}} = State) -> Connection:send_alert_in_connection(Alert, State); -send_alert(Alert, _, #state{protocol_cb = Connection} = State) -> +send_alert(Alert, _, #state{static_env = #static_env{protocol_cb = Connection}} = State) -> Connection:send_alert(Alert, State). -connection_info(#state{sni_hostname = SNIHostname, - session = #session{session_id = SessionId, +connection_info(#state{static_env = #static_env{protocol_cb = Connection}, + sni_hostname = SNIHostname, + session = #session{session_id = SessionId, cipher_suite = CipherSuite, ecc = ECCCurve}, - protocol_cb = Connection, negotiated_version = {_,_} = Version, ssl_options = Opts}) -> RecordCB = record_cb(Connection), @@ -1532,9 +1556,10 @@ handle_peer_cert_key(client, _, handle_peer_cert_key(_, _, _, _, State) -> State. -certify_client(#state{client_certificate_requested = true, role = client, - cert_db = CertDbHandle, - cert_db_ref = CertDbRef, +certify_client(#state{static_env = #static_env{role = client, + cert_db = CertDbHandle, + cert_db_ref = CertDbRef}, + client_certificate_requested = true, session = #session{own_certificate = OwnCert}} = State, Connection) -> Certificate = ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, client), @@ -1542,16 +1567,17 @@ certify_client(#state{client_certificate_requested = true, role = client, certify_client(#state{client_certificate_requested = false} = State, _) -> State. -verify_client_cert(#state{client_certificate_requested = true, role = client, +verify_client_cert(#state{static_env = #static_env{role = client}, + handshake_env = #handshake_env{tls_handshake_history = Hist}, + client_certificate_requested = true, negotiated_version = Version, private_key = PrivateKey, session = #session{master_secret = MasterSecret, own_certificate = OwnCert}, - cert_hashsign_algorithm = HashSign, - tls_handshake_history = Handshake0} = State, Connection) -> + cert_hashsign_algorithm = HashSign} = State, Connection) -> case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret, - ssl:tls_version(Version), HashSign, PrivateKey, Handshake0) of + ssl:tls_version(Version), HashSign, PrivateKey, Hist) of #certificate_verify{} = Verified -> Connection:queue_handshake(Verified, State); ignore -> @@ -1587,7 +1613,9 @@ server_certify_and_key_exchange(State0, Connection) -> request_client_cert(State2, Connection). certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS}, - #state{private_key = Key, client_hello_version = {Major, Minor} = Version} = State, Connection) -> + #state{private_key = Key, + handshake_env = #handshake_env{client_hello_version = {Major, Minor} = Version}} + = State, Connection) -> FakeSecret = make_premaster_secret(Version, rsa), %% Countermeasure for Bleichenbacher attack always provide some kind of premaster secret %% and fail handshake later.RFC 5246 section 7.4.7.1. @@ -1662,8 +1690,8 @@ certify_server(#state{key_algorithm = Algo} = State, _) when Algo == dh_anon; Algo == ecdhe_psk; Algo == srp_anon -> State; -certify_server(#state{cert_db = CertDbHandle, - cert_db_ref = CertDbRef, +certify_server(#state{static_env = #static_env{cert_db = CertDbHandle, + cert_db_ref = CertDbRef}, session = #session{own_certificate = OwnCert}} = State, Connection) -> case ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, server) of Cert = #certificate{} -> @@ -1672,9 +1700,9 @@ certify_server(#state{cert_db = CertDbHandle, throw(Alert) end. -key_exchange(#state{role = server, key_algorithm = rsa} = State,_) -> +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa} = State,_) -> State; -key_exchange(#state{role = server, key_algorithm = Algo, +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, hashsign_algorithm = HashSignAlgo, diffie_hellman_params = #'DHParameter'{} = Params, private_key = PrivateKey, @@ -1695,12 +1723,14 @@ key_exchange(#state{role = server, key_algorithm = Algo, PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = DHKeys}; -key_exchange(#state{role = server, private_key = #'ECPrivateKey'{parameters = ECCurve} = Key, key_algorithm = Algo, +key_exchange(#state{static_env = #static_env{role = server}, + private_key = #'ECPrivateKey'{parameters = ECCurve} = Key, + key_algorithm = Algo, session = Session} = State, _) when Algo == ecdh_ecdsa; Algo == ecdh_rsa -> State#state{diffie_hellman_keys = Key, session = Session#session{ecc = ECCurve}}; -key_exchange(#state{role = server, key_algorithm = Algo, +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, hashsign_algorithm = HashSignAlgo, private_key = PrivateKey, session = #session{ecc = ECCCurve}, @@ -1722,10 +1752,10 @@ key_exchange(#state{role = server, key_algorithm = Algo, PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = ECDHKeys}; -key_exchange(#state{role = server, key_algorithm = psk, +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk, ssl_options = #ssl_options{psk_identity = undefined}} = State, _) -> State; -key_exchange(#state{role = server, key_algorithm = psk, +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, hashsign_algorithm = HashSignAlgo, private_key = PrivateKey, @@ -1742,7 +1772,7 @@ key_exchange(#state{role = server, key_algorithm = psk, ServerRandom, PrivateKey}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{role = server, key_algorithm = dhe_psk, +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = dhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, hashsign_algorithm = HashSignAlgo, diffie_hellman_params = #'DHParameter'{} = Params, @@ -1763,7 +1793,7 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk, PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = DHKeys}; -key_exchange(#state{role = server, key_algorithm = ecdhe_psk, +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = ecdhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, hashsign_algorithm = HashSignAlgo, private_key = PrivateKey, @@ -1784,10 +1814,10 @@ key_exchange(#state{role = server, key_algorithm = ecdhe_psk, PrivateKey}), State = Connection:queue_handshake(Msg, State0), State#state{diffie_hellman_keys = ECDHKeys}; -key_exchange(#state{role = server, key_algorithm = rsa_psk, +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa_psk, ssl_options = #ssl_options{psk_identity = undefined}} = State, _) -> State; -key_exchange(#state{role = server, key_algorithm = rsa_psk, +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = rsa_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, hashsign_algorithm = HashSignAlgo, private_key = PrivateKey, @@ -1804,7 +1834,7 @@ key_exchange(#state{role = server, key_algorithm = rsa_psk, ServerRandom, PrivateKey}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{role = server, key_algorithm = Algo, +key_exchange(#state{static_env = #static_env{role = server}, key_algorithm = Algo, ssl_options = #ssl_options{user_lookup_fun = LookupFun}, hashsign_algorithm = HashSignAlgo, session = #session{srp_username = Username}, @@ -1834,14 +1864,14 @@ key_exchange(#state{role = server, key_algorithm = Algo, State = Connection:queue_handshake(Msg, State0), State#state{srp_params = SrpParams, srp_keys = Keys}; -key_exchange(#state{role = client, +key_exchange(#state{static_env = #static_env{role = client}, key_algorithm = rsa, public_key_info = PublicKeyInfo, negotiated_version = Version, premaster_secret = PremasterSecret} = State0, Connection) -> Msg = rsa_key_exchange(ssl:tls_version(Version), PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); -key_exchange(#state{role = client, +key_exchange(#state{static_env = #static_env{role = client}, key_algorithm = Algorithm, negotiated_version = Version, diffie_hellman_keys = {DhPubKey, _} @@ -1852,7 +1882,7 @@ key_exchange(#state{role = client, Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {dh, DhPubKey}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{role = client, +key_exchange(#state{static_env = #static_env{role = client}, key_algorithm = Algorithm, negotiated_version = Version, session = Session, @@ -1862,14 +1892,14 @@ key_exchange(#state{role = client, Algorithm == ecdh_anon -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdh, Key}), Connection:queue_handshake(Msg, State0#state{session = Session#session{ecc = ECCurve}}); -key_exchange(#state{role = client, +key_exchange(#state{static_env = #static_env{role = client}, ssl_options = SslOpts, key_algorithm = psk, negotiated_version = Version} = State0, Connection) -> Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {psk, SslOpts#ssl_options.psk_identity}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{role = client, +key_exchange(#state{static_env = #static_env{role = client}, ssl_options = SslOpts, key_algorithm = dhe_psk, negotiated_version = Version, @@ -1879,7 +1909,7 @@ key_exchange(#state{role = client, SslOpts#ssl_options.psk_identity, DhPubKey}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{role = client, +key_exchange(#state{static_env = #static_env{role = client}, ssl_options = SslOpts, key_algorithm = ecdhe_psk, negotiated_version = Version, @@ -1889,7 +1919,7 @@ key_exchange(#state{role = client, SslOpts#ssl_options.psk_identity, ECDHKeys}), Connection:queue_handshake(Msg, State0); -key_exchange(#state{role = client, +key_exchange(#state{static_env = #static_env{role = client}, ssl_options = SslOpts, key_algorithm = rsa_psk, public_key_info = PublicKeyInfo, @@ -1899,7 +1929,7 @@ key_exchange(#state{role = client, Msg = rsa_psk_key_exchange(ssl:tls_version(Version), SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo), Connection:queue_handshake(Msg, State0); -key_exchange(#state{role = client, +key_exchange(#state{static_env = #static_env{role = client}, key_algorithm = Algorithm, negotiated_version = Version, srp_keys = {ClientPubKey, _}} @@ -1949,11 +1979,11 @@ request_client_cert(#state{key_algorithm = Alg} = State, _) Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon -> State; -request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer, - signature_algs = SupportedHashSigns}, - connection_states = ConnectionStates0, - cert_db = CertDbHandle, - cert_db_ref = CertDbRef, +request_client_cert(#state{static_env = #static_env{cert_db = CertDbHandle, + cert_db_ref = CertDbRef}, + ssl_options = #ssl_options{verify = verify_peer, + signature_algs = SupportedHashSigns}, + connection_states = ConnectionStates0, negotiated_version = Version} = State0, Connection) -> #{security_parameters := #security_parameters{cipher_suite = CipherSuite}} = @@ -1998,7 +2028,7 @@ finalize_handshake(State0, StateName, Connection) -> State = next_protocol(State2, Connection), finished(State, StateName, Connection). -next_protocol(#state{role = server} = State, _) -> +next_protocol(#state{static_env = #static_env{role = server}} = State, _) -> State; next_protocol(#state{negotiated_protocol = undefined} = State, _) -> State; @@ -2011,14 +2041,16 @@ next_protocol(#state{negotiated_protocol = NextProtocol} = State0, Connection) - cipher_protocol(State, Connection) -> Connection:queue_change_cipher(#change_cipher_spec{}, State). -finished(#state{role = Role, negotiated_version = Version, +finished(#state{static_env = #static_env{role = Role}, + handshake_env = #handshake_env{tls_handshake_history = Hist}, + negotiated_version = Version, session = Session, - connection_states = ConnectionStates0, - tls_handshake_history = Handshake0} = State0, StateName, Connection) -> + connection_states = ConnectionStates0} = State0, + StateName, Connection) -> MasterSecret = Session#session.master_secret, Finished = ssl_handshake:finished(ssl:tls_version(Version), Role, get_current_prf(ConnectionStates0, write), - MasterSecret, Handshake0), + MasterSecret, Hist), ConnectionStates = save_verify_data(Role, Finished, ConnectionStates0, StateName), Connection:send_handshake(Finished, State0#state{connection_states = ConnectionStates}). @@ -2090,8 +2122,9 @@ calculate_secret(#server_srp_params{srp_n = Prime, srp_g = Generator} = ServerKe master_secret(#alert{} = Alert, _) -> Alert; -master_secret(PremasterSecret, #state{session = Session, - negotiated_version = Version, role = Role, +master_secret(PremasterSecret, #state{static_env = #static_env{role = Role}, + session = Session, + negotiated_version = Version, connection_states = ConnectionStates0} = State) -> case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret, ConnectionStates0, Role) of @@ -2325,18 +2358,18 @@ handle_trusted_certs_db(#state{ssl_options = #ssl_options{cacertfile = <<>>, cacerts = []}}) -> %% No trusted certs specified ok; -handle_trusted_certs_db(#state{cert_db_ref = Ref, - cert_db = CertDb, - ssl_options = #ssl_options{cacertfile = <<>>}}) when CertDb =/= undefined -> +handle_trusted_certs_db(#state{static_env = #static_env{cert_db_ref = Ref, + cert_db = CertDb}, + ssl_options = #ssl_options{cacertfile = <<>>}}) when CertDb =/= undefined -> %% Certs provided as DER directly can not be shared %% with other connections and it is safe to delete them when the connection ends. ssl_pkix_db:remove_trusted_certs(Ref, CertDb); -handle_trusted_certs_db(#state{file_ref_db = undefined}) -> +handle_trusted_certs_db(#state{static_env = #static_env{file_ref_db = undefined}}) -> %% Something went wrong early (typically cacertfile does not %% exist) so there is nothing to handle ok; -handle_trusted_certs_db(#state{cert_db_ref = Ref, - file_ref_db = RefDb, +handle_trusted_certs_db(#state{static_env = #static_env{cert_db_ref = Ref, + file_ref_db = RefDb}, ssl_options = #ssl_options{cacertfile = File}}) -> case ssl_pkix_db:ref_count(Ref, RefDb, -1) of 0 -> @@ -2345,7 +2378,7 @@ handle_trusted_certs_db(#state{cert_db_ref = Ref, ok end. -prepare_connection(#state{renegotiation = Renegotiate, +prepare_connection(#state{handshake_env = #handshake_env{renegotiation = Renegotiate}, start_or_recv_from = RecvFrom} = State0, Connection) when Renegotiate =/= {false, first}, RecvFrom =/= undefined -> @@ -2355,18 +2388,18 @@ prepare_connection(State0, Connection) -> State = Connection:reinit(State0), {no_record, ack_connection(State)}. -ack_connection(#state{renegotiation = {true, Initiater}} = State) when Initiater == peer; - Initiater == internal -> - State#state{renegotiation = undefined}; -ack_connection(#state{renegotiation = {true, From}} = State) -> +ack_connection(#state{handshake_env = #handshake_env{renegotiation = {true, Initiater}} = HsEnv} = State) when Initiater == peer; + Initiater == internal -> + State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}}; +ack_connection(#state{handshake_env = #handshake_env{renegotiation = {true, From}} = HsEnv} = State) -> gen_statem:reply(From, ok), - State#state{renegotiation = undefined}; -ack_connection(#state{renegotiation = {false, first}, + State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}}; +ack_connection(#state{handshake_env = #handshake_env{renegotiation = {false, first}} = HsEnv, start_or_recv_from = StartFrom, timer = Timer} = State) when StartFrom =/= undefined -> gen_statem:reply(StartFrom, connected), cancel_timer(Timer), - State#state{renegotiation = undefined, + State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}, start_or_recv_from = undefined, timer = undefined}; ack_connection(State) -> State. @@ -2382,15 +2415,35 @@ session_handle_params(#server_ecdh_params{curve = ECCurve}, Session) -> session_handle_params(_, Session) -> Session. -register_session(client, Host, Port, #session{is_resumable = new} = Session0) -> +handle_session(Role = server, #ssl_options{reuse_sessions = true} = SslOpts, + Host, Port, Session0) -> + register_session(Role, host_id(Role, Host, SslOpts), Port, Session0, true); +handle_session(Role = client, #ssl_options{verify = verify_peer, + reuse_sessions = Reuse} = SslOpts, + Host, Port, Session0) when Reuse =/= false -> + register_session(Role, host_id(Role, Host, SslOpts), Port, Session0, reg_type(Reuse)); +handle_session(server, _, Host, Port, Session) -> + %% Remove "session of type new" entry from session DB + ssl_manager:invalidate_session(Host, Port, Session), + Session; +handle_session(client, _,_,_, Session) -> + %% In client case there is no entry yet, so nothing to remove + Session. + +reg_type(save) -> + true; +reg_type(true) -> + unique. + +register_session(client, Host, Port, #session{is_resumable = new} = Session0, Save) -> Session = Session0#session{is_resumable = true}, - ssl_manager:register_session(Host, Port, Session), + ssl_manager:register_session(Host, Port, Session, Save), Session; -register_session(server, _, Port, #session{is_resumable = new} = Session0) -> +register_session(server, _, Port, #session{is_resumable = new} = Session0, _) -> Session = Session0#session{is_resumable = true}, ssl_manager:register_session(Port, Session), Session; -register_session(_, _, _, Session) -> +register_session(_, _, _, Session, _) -> Session. %% Already registered host_id(client, _Host, #ssl_options{server_name_indication = Hostname}) when is_list(Hostname) -> @@ -2399,19 +2452,22 @@ host_id(_, Host, _) -> Host. handle_new_session(NewId, CipherSuite, Compression, - #state{session = Session0, - protocol_cb = Connection} = State0) -> + #state{static_env = #static_env{protocol_cb = Connection}, + session = Session0 + } = State0) -> Session = Session0#session{session_id = NewId, cipher_suite = CipherSuite, compression_method = Compression}, Connection:next_event(certify, no_record, State0#state{session = Session}). -handle_resumed_session(SessId, #state{connection_states = ConnectionStates0, - negotiated_version = Version, - host = Host, port = Port, - protocol_cb = Connection, - session_cache = Cache, - session_cache_cb = CacheCb} = State) -> +handle_resumed_session(SessId, #state{static_env = #static_env{host = Host, + port = Port, + protocol_cb = Connection, + session_cache = Cache, + session_cache_cb = CacheCb}, + connection_states = ConnectionStates0, + negotiated_version = Version + } = State) -> Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}), case ssl_handshake:master_secret(ssl:tls_version(Version), Session, ConnectionStates0, client) of @@ -2468,8 +2524,8 @@ ssl_options_list([Key | Keys], [Value | Values], Acc) -> handle_active_option(false, connection = StateName, To, Reply, State) -> hibernate_after(StateName, State, [{reply, To, Reply}]); -handle_active_option(_, connection = StateName0, To, Reply, #state{protocol_cb = Connection, - user_data_buffer = <<>>} = State0) -> +handle_active_option(_, connection = StateName0, To, Reply, #state{static_env = #static_env{protocol_cb = Connection}, + user_data_buffer = <<>>} = State0) -> case Connection:next_event(StateName0, no_record, State0) of {next_state, StateName, State} -> hibernate_after(StateName, State, [{reply, To, Reply}]); @@ -2483,7 +2539,8 @@ handle_active_option(_, StateName, To, Reply, #state{user_data_buffer = <<>>} = {next_state, StateName, State, [{reply, To, Reply}]}; %% user_data_buffer =/= <<>> -handle_active_option(_, StateName0, To, Reply, #state{protocol_cb = Connection} = State0) -> +handle_active_option(_, StateName0, To, Reply, + #state{static_env = #static_env{protocol_cb = Connection}} = State0) -> case read_application_data(<<>>, State0) of {stop, _, _} = Stop -> Stop; @@ -2545,21 +2602,28 @@ decode_packet(Type, Buffer, PacketOpts) -> %% Note that if the user has explicitly configured the socket to expect %% HTTP headers using the {packet, httph} option, we don't do any automatic %% switching of states. -deliver_app_data(CPids, Transport, Socket, SOpts = #socket_options{active=Active, packet=Type}, - Data, Pid, From, Tracker, Connection) -> - send_or_reply(Active, Pid, From, - format_reply(CPids, Transport, Socket, SOpts, Data, Tracker, Connection)), - SO = case Data of - {P, _, _, _} when ((P =:= http_request) or (P =:= http_response)), - ((Type =:= http) or (Type =:= http_bin)) -> - SOpts#socket_options{packet={Type, headers}}; - http_eoh when tuple_size(Type) =:= 2 -> - % End of headers - expect another Request/Response line - {Type1, headers} = Type, - SOpts#socket_options{packet=Type1}; - _ -> - SOpts - end, +deliver_app_data( + CPids, Transport, Socket, + #socket_options{active=Active, packet=Type} = SOpts, + Data, Pid, From, Tracker, Connection) -> + %% + send_or_reply( + Active, Pid, From, + format_reply( + CPids, Transport, Socket, SOpts, Data, Tracker, Connection)), + SO = + case Data of + {P, _, _, _} + when ((P =:= http_request) or (P =:= http_response)), + ((Type =:= http) or (Type =:= http_bin)) -> + SOpts#socket_options{packet={Type, headers}}; + http_eoh when tuple_size(Type) =:= 2 -> + %% End of headers - expect another Request/Response line + {Type1, headers} = Type, + SOpts#socket_options{packet=Type1}; + _ -> + SOpts + end, case Active of once -> SO#socket_options{active=false}; @@ -2664,7 +2728,7 @@ invalidate_session(server, _, Port, Session) -> handle_sni_extension(undefined, State) -> State; -handle_sni_extension(#sni{hostname = Hostname}, State0) -> +handle_sni_extension(#sni{hostname = Hostname}, #state{static_env = #static_env{role = Role} = InitStatEnv0} = State0) -> NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname), case NewOptions of undefined -> @@ -2678,19 +2742,21 @@ handle_sni_extension(#sni{hostname = Hostname}, State0) -> private_key := Key, dh_params := DHParams, own_certificate := OwnCert}} = - ssl_config:init(NewOptions, State0#state.role), + ssl_config:init(NewOptions, Role), State0#state{ session = State0#state.session#session{own_certificate = OwnCert}, - file_ref_db = FileRefHandle, - cert_db_ref = Ref, - cert_db = CertDbHandle, - crl_db = CRLDbHandle, - session_cache = CacheHandle, + static_env = InitStatEnv0#static_env{ + file_ref_db = FileRefHandle, + cert_db_ref = Ref, + cert_db = CertDbHandle, + crl_db = CRLDbHandle, + session_cache = CacheHandle + }, private_key = Key, - diffie_hellman_params = DHParams, - ssl_options = NewOptions, - sni_hostname = Hostname - } + diffie_hellman_params = DHParams, + ssl_options = NewOptions, + sni_hostname = Hostname + } end. update_ssl_options_from_sni(OrigSSLOptions, SNIHostname) -> @@ -2714,13 +2780,10 @@ new_emulated([], EmOpts) -> new_emulated(NewEmOpts, _) -> NewEmOpts. -stop(Reason, State) -> - {stop, Reason, State}. - -stop_and_reply(Reason, Replies, State) -> - {stop_and_reply, Reason, Replies, State}. - -is_dist_up(#{dist_handle := Handle}) when Handle =/= undefined -> - true; -is_dist_up(_) -> - false. +-compile({inline, [bincat/2]}). +bincat(<<>>, B) -> + B; +bincat(A, <<>>) -> + A; +bincat(A, B) -> + <<A/binary, B/binary>>. diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 66e3182313..a46407b27e 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -33,71 +33,85 @@ -include("ssl_cipher.hrl"). -include_lib("public_key/include/public_key.hrl"). +-record(static_env, { + role :: client | server, + transport_cb :: atom(), % callback module + protocol_cb :: tls_connection | dtls_connection, + data_tag :: atom(), % ex tcp. + close_tag :: atom(), % ex tcp_closed + error_tag :: atom(), % ex tcp_error + host :: string() | inet:ip_address(), + port :: integer(), + socket :: port() | tuple(), %% TODO: dtls socket + cert_db :: reference() | 'undefined', + session_cache :: db_handle(), + session_cache_cb :: atom(), + crl_db :: term(), + file_ref_db :: db_handle(), + cert_db_ref :: certdb_ref() | 'undefined', + tracker :: pid() | 'undefined' %% Tracker process for listen socket + }). + +-record(handshake_env, { + client_hello_version :: ssl_record:ssl_version() | 'undefined', + unprocessed_handshake_events = 0 :: integer(), + tls_handshake_history :: ssl_handshake:ssl_handshake_history() | secret_printout() + | 'undefined', + renegotiation :: undefined | {boolean(), From::term() | internal | peer} + }). + -record(state, { - role :: client | server, - user_application :: {Monitor::reference(), User::pid()}, - transport_cb :: atom(), % callback module - protocol_cb :: tls_connection | dtls_connection, - data_tag :: atom(), % ex tcp. - close_tag :: atom(), % ex tcp_closed - error_tag :: atom(), % ex tcp_error - host :: string() | inet:ip_address(), - port :: integer(), - socket :: port() | tuple(), %% TODO: dtls socket - sender :: pid() | undefined, - ssl_options :: #ssl_options{}, - socket_options :: #socket_options{}, - connection_states :: ssl_record:connection_states() | secret_printout(), - protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hrl - unprocessed_handshake_events = 0 :: integer(), - tls_handshake_history :: ssl_handshake:ssl_handshake_history() | secret_printout() - | 'undefined', - cert_db :: reference() | 'undefined', - session :: #session{} | secret_printout(), - session_cache :: db_handle(), - session_cache_cb :: atom(), - crl_db :: term(), - negotiated_version :: ssl_record:ssl_version() | 'undefined', - client_hello_version :: ssl_record:ssl_version() | 'undefined', - client_certificate_requested = false :: boolean(), - key_algorithm :: ssl_cipher_format:key_algo(), - hashsign_algorithm = {undefined, undefined}, - cert_hashsign_algorithm = {undefined, undefined}, - public_key_info :: ssl_handshake:public_key_info() | 'undefined', - private_key :: public_key:private_key() | secret_printout() | 'undefined', - diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), - diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), - psk_identity :: binary() | 'undefined', % server psk identity hint - srp_params :: #srp_user{} | secret_printout() | 'undefined', - srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', - premaster_secret :: binary() | secret_printout() | 'undefined', - file_ref_db :: db_handle(), - cert_db_ref :: certdb_ref() | 'undefined', - bytes_to_read :: undefined | integer(), %% bytes to read in passive mode - user_data_buffer :: undefined | binary() | secret_printout(), - erl_dist_data = #{} :: map(), - renegotiation :: undefined | {boolean(), From::term() | internal | peer}, - start_or_recv_from :: term(), - timer :: undefined | reference(), % start_or_recive_timer - %%send_queue :: queue:queue(), - hello, %%:: #client_hello{} | #server_hello{}, - terminated = false ::boolean(), - allow_renegotiate = true ::boolean(), - expecting_next_protocol_negotiation = false ::boolean(), - expecting_finished = false ::boolean(), - next_protocol = undefined :: undefined | binary(), - negotiated_protocol, - tracker :: pid() | 'undefined', %% Tracker process for listen socket - sni_hostname = undefined, - downgrade, - flight_buffer = [] :: list() | map(), %% Buffer of TLS/DTLS records, used during the TLS handshake - %% to when possible pack more than one TLS record into the - %% underlaying packet format. Introduced by DTLS - RFC 4347. - %% The mecahnism is also usefull in TLS although we do not - %% need to worry about packet loss in TLS. In DTLS we need to track DTLS handshake seqnr - flight_state = reliable, %% reliable | {retransmit, integer()}| {waiting, ref(), integer()} - last two is used in DTLS over udp. - protocol_specific = #{} :: map() - }). + static_env :: #static_env{}, + handshake_env :: #handshake_env{} | secret_printout(), + %% Change seldome + user_application :: {Monitor::reference(), User::pid()}, + ssl_options :: #ssl_options{}, + socket_options :: #socket_options{}, + session :: #session{} | secret_printout(), + allow_renegotiate = true ::boolean(), + terminated = false ::boolean() | closed, + negotiated_version :: ssl_record:ssl_version() | 'undefined', + bytes_to_read :: undefined | integer(), %% bytes to read in passive mode + downgrade, + + %% Changed often + connection_states :: ssl_record:connection_states() | secret_printout(), + protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hr + user_data_buffer :: undefined | binary() | secret_printout(), + + %% Used only in HS + + client_certificate_requested = false :: boolean(), + key_algorithm :: ssl:key_algo(), + hashsign_algorithm = {undefined, undefined}, + cert_hashsign_algorithm = {undefined, undefined}, + public_key_info :: ssl_handshake:public_key_info() | 'undefined', + private_key :: public_key:private_key() | secret_printout() | 'undefined', + diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), + diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), + psk_identity :: binary() | 'undefined', % server psk identity hint + srp_params :: #srp_user{} | secret_printout() | 'undefined', + srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', + premaster_secret :: binary() | secret_printout() | 'undefined', + start_or_recv_from :: term(), + timer :: undefined | reference(), % start_or_recive_timer + hello, %%:: #client_hello{} | #server_hello{}, + expecting_next_protocol_negotiation = false ::boolean(), + expecting_finished = false ::boolean(), + next_protocol = undefined :: undefined | binary(), + negotiated_protocol, + sni_hostname = undefined, + flight_buffer = [] :: list() | map(), %% Buffer of TLS/DTLS records, used during the TLS handshake + %% to when possible pack more than one TLS record into the + %% underlaying packet format. Introduced by DTLS - RFC 4347. + %% The mecahnism is also usefull in TLS although we do not + %% need to worry about packet loss in TLS. In DTLS we need to track DTLS handshake seqnr + flight_state = reliable, %% reliable | {retransmit, integer()}| {waiting, ref(), integer()} - last two is used in DTLS over udp. + erl_dist_handle = undefined :: erlang:dist_handle() | undefined, + protocol_specific = #{} :: map() + }). + + -define(DEFAULT_DIFFIE_HELLMAN_PARAMS, #'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME, base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}). diff --git a/lib/ssl/src/ssl_crl_cache.erl b/lib/ssl/src/ssl_crl_cache.erl index 9c1af86eeb..841620ce57 100644 --- a/lib/ssl/src/ssl_crl_cache.erl +++ b/lib/ssl/src/ssl_crl_cache.erl @@ -28,6 +28,10 @@ -behaviour(ssl_crl_cache_api). +-export_type([crl_src/0, uri/0]). +-type crl_src() :: {file, file:filename()} | {der, public_key:der_encoded()}. +-type uri() :: uri_string:uri_string(). + -export([lookup/3, select/2, fresh_crl/2]). -export([insert/1, insert/2, delete/1]). diff --git a/lib/ssl/src/ssl_crl_cache_api.erl b/lib/ssl/src/ssl_crl_cache_api.erl index d5380583e7..8a750b3929 100644 --- a/lib/ssl/src/ssl_crl_cache_api.erl +++ b/lib/ssl/src/ssl_crl_cache_api.erl @@ -21,12 +21,15 @@ %% -module(ssl_crl_cache_api). - -include_lib("public_key/include/public_key.hrl"). --type db_handle() :: term(). --type issuer_name() :: {rdnSequence, [#'AttributeTypeAndValue'{}]}. +-export_type([dist_point/0, crl_cache_ref/0]). + +-type crl_cache_ref() :: any(). +-type issuer_name() :: {rdnSequence,[#'AttributeTypeAndValue'{}]}. +-type dist_point() :: #'DistributionPoint'{}. --callback lookup(#'DistributionPoint'{}, issuer_name(), db_handle()) -> not_available | [public_key:der_encoded()]. --callback select(issuer_name(), db_handle()) -> [public_key:der_encoded()]. --callback fresh_crl(#'DistributionPoint'{}, public_key:der_encoded()) -> public_key:der_encoded(). + +-callback lookup(dist_point(), issuer_name(), crl_cache_ref()) -> not_available | [public_key:der_encoded()]. +-callback select(issuer_name(), crl_cache_ref()) -> [public_key:der_encoded()]. +-callback fresh_crl(dist_point(), public_key:der_encoded()) -> public_key:der_encoded(). diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 14df1d2e02..27c071d6dd 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -610,7 +610,7 @@ encode_hello_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats ?UINT16(Len), ?BYTE(ListLen), ECPointFormatList/binary, Acc/binary>>); encode_hello_extensions([#srp{username = UserName} | Rest], Acc) -> SRPLen = byte_size(UserName), - Len = SRPLen + 2, + Len = SRPLen + 1, encode_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), UserName/binary, Acc/binary>>); encode_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) -> @@ -729,7 +729,7 @@ decode_hello_extensions(Extensions) -> dec_hello_extensions(Extensions, #hello_extensions{}). %%-------------------------------------------------------------------- --spec decode_server_key(binary(), ssl_cipher_format:key_algo(), ssl_record:ssl_version()) -> +-spec decode_server_key(binary(), ssl:key_algo(), ssl_record:ssl_version()) -> #server_key_params{}. %% %% Description: Decode server_key data and return appropriate type @@ -738,7 +738,7 @@ decode_server_key(ServerKey, Type, Version) -> dec_server_key(ServerKey, key_exchange_alg(Type), Version). %%-------------------------------------------------------------------- --spec decode_client_key(binary(), ssl_cipher_format:key_algo(), ssl_record:ssl_version()) -> +-spec decode_client_key(binary(), ssl:key_algo(), ssl_record:ssl_version()) -> #encrypted_premaster_secret{} | #client_diffie_hellman_public{} | #client_ec_diffie_hellman_public{} @@ -972,34 +972,30 @@ handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites, #session{cipher_suite = NegotiatedCipherSuite, compression_method = Compression} = Session0, ConnectionStates0, Renegotiation) -> - Session = handle_srp_extension(SRP, Session0), - ConnectionStates = handle_renegotiation_extension(server, RecordCB, Version, Info, - Random, NegotiatedCipherSuite, + Session = handle_srp_extension(SRP, Session0), + ConnectionStates = handle_renegotiation_extension(server, RecordCB, Version, Info, + Random, NegotiatedCipherSuite, ClientCipherSuites, Compression, - ConnectionStates0, Renegotiation, SecureRenegotation), - - ServerHelloExtensions = #hello_extensions{ - renegotiation_info = renegotiation_info(RecordCB, server, - ConnectionStates, Renegotiation), - ec_point_formats = server_ecc_extension(Version, ECCFormat) - }, - + ConnectionStates0, Renegotiation, SecureRenegotation), + + ServerHelloExtensions = #hello_extensions{ + renegotiation_info = renegotiation_info(RecordCB, server, + ConnectionStates, Renegotiation), + ec_point_formats = server_ecc_extension(Version, ECCFormat) + }, + %% If we receive an ALPN extension and have ALPN configured for this connection, %% we handle it. Otherwise we check for the NPN extension. if ALPN =/= undefined, ALPNPreferredProtocols =/= undefined -> - case handle_alpn_extension(ALPNPreferredProtocols, decode_alpn(ALPN)) of - #alert{} = Alert -> - Alert; - Protocol -> - {Session, ConnectionStates, Protocol, - ServerHelloExtensions#hello_extensions{alpn=encode_alpn([Protocol], Renegotiation)}} - end; + Protocol = handle_alpn_extension(ALPNPreferredProtocols, decode_alpn(ALPN)), + {Session, ConnectionStates, Protocol, + ServerHelloExtensions#hello_extensions{alpn=encode_alpn([Protocol], Renegotiation)}}; true -> - ProtocolsToAdvertise = handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, Opts), + ProtocolsToAdvertise = handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, Opts), {Session, ConnectionStates, undefined, - ServerHelloExtensions#hello_extensions{next_protocol_negotiation= - encode_protocols_advertised_on_server(ProtocolsToAdvertise)}} + ServerHelloExtensions#hello_extensions{next_protocol_negotiation= + encode_protocols_advertised_on_server(ProtocolsToAdvertise)}} end. handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression, @@ -1022,12 +1018,8 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression, [Protocol] when not Renegotiation -> {ConnectionStates, alpn, Protocol}; undefined -> - case handle_next_protocol(NextProtocolNegotiation, NextProtoSelector, Renegotiation) of - #alert{} = Alert -> - Alert; - Protocol -> - {ConnectionStates, npn, Protocol} - end; + Protocol = handle_next_protocol(NextProtocolNegotiation, NextProtoSelector, Renegotiation), + {ConnectionStates, npn, Protocol}; {error, Reason} -> ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason); [] -> @@ -1941,7 +1933,7 @@ dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binar RenegotiateInfo}}); dec_hello_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), SRP:SRPLen/binary, Rest/binary>>, Acc) - when Len == SRPLen + 2 -> + when Len == SRPLen + 1 -> dec_hello_extensions(Rest, Acc#hello_extensions{srp = #srp{username = SRP}}); dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len), @@ -2189,30 +2181,26 @@ filter_unavailable_ecc_suites(_, Suites) -> handle_renegotiation_extension(Role, RecordCB, Version, Info, Random, NegotiatedCipherSuite, ClientCipherSuites, Compression, ConnectionStates0, Renegotiation, SecureRenegotation) -> - case handle_renegotiation_info(RecordCB, Role, Info, ConnectionStates0, - Renegotiation, SecureRenegotation, - ClientCipherSuites) of - {ok, ConnectionStates} -> - hello_pending_connection_states(RecordCB, Role, - Version, - NegotiatedCipherSuite, - Random, - Compression, - ConnectionStates); - #alert{} = Alert -> - throw(Alert) - end. + {ok, ConnectionStates} = handle_renegotiation_info(RecordCB, Role, Info, ConnectionStates0, + Renegotiation, SecureRenegotation, + ClientCipherSuites), + hello_pending_connection_states(RecordCB, Role, + Version, + NegotiatedCipherSuite, + Random, + Compression, + ConnectionStates). %% Receive protocols, choose one from the list, return it. handle_alpn_extension(_, {error, Reason}) -> - ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason); + throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason)); handle_alpn_extension([], _) -> - ?ALERT_REC(?FATAL, ?NO_APPLICATION_PROTOCOL); + throw(?ALERT_REC(?FATAL, ?NO_APPLICATION_PROTOCOL)); handle_alpn_extension([ServerProtocol|Tail], ClientProtocols) -> - case lists:member(ServerProtocol, ClientProtocols) of - true -> ServerProtocol; - false -> handle_alpn_extension(Tail, ClientProtocols) - end. + case lists:member(ServerProtocol, ClientProtocols) of + true -> ServerProtocol; + false -> handle_alpn_extension(Tail, ClientProtocols) + end. handle_next_protocol(undefined, _NextProtocolSelector, _Renegotiating) -> @@ -2225,14 +2213,14 @@ handle_next_protocol(#next_protocol_negotiation{} = NextProtocols, true -> select_next_protocol(decode_next_protocols(NextProtocols), NextProtocolSelector); false -> - ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_next_protocol_extension) + throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_next_protocol_extension)) end. handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, SslOpts)-> case handle_next_protocol_on_server(NextProtocolNegotiation, Renegotiation, SslOpts) of #alert{} = Alert -> - Alert; + throw(Alert); ProtocolsToAdvertise -> ProtocolsToAdvertise end. @@ -2428,14 +2416,14 @@ handle_renegotiation_info(_RecordCB, client, #renegotiation_info{renegotiated_co true -> {ok, ConnectionStates}; false -> - ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, client_renegotiation) + throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, client_renegotiation)) end; handle_renegotiation_info(_RecordCB, server, #renegotiation_info{renegotiated_connection = ClientVerify}, ConnectionStates, true, _, CipherSuites) -> case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of true -> - ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv}); + throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv})); false -> ConnectionState = ssl_record:current_connection_state(ConnectionStates, read), Data = maps:get(client_verify_data, ConnectionState), @@ -2443,7 +2431,7 @@ handle_renegotiation_info(_RecordCB, server, #renegotiation_info{renegotiated_co true -> {ok, ConnectionStates}; false -> - ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, server_renegotiation) + throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, server_renegotiation)) end end; @@ -2453,7 +2441,7 @@ handle_renegotiation_info(RecordCB, client, undefined, ConnectionStates, true, S handle_renegotiation_info(RecordCB, server, undefined, ConnectionStates, true, SecureRenegotation, CipherSuites) -> case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of true -> - ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv}); + throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv})); false -> handle_renegotiation_info(RecordCB, ConnectionStates, SecureRenegotation) end. @@ -2462,9 +2450,9 @@ handle_renegotiation_info(_RecordCB, ConnectionStates, SecureRenegotation) -> ConnectionState = ssl_record:current_connection_state(ConnectionStates, read), case {SecureRenegotation, maps:get(secure_renegotiation, ConnectionState)} of {_, true} -> - ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, already_secure); + throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, already_secure)); {true, false} -> - ?ALERT_REC(?FATAL, ?NO_RENEGOTIATION); + throw(?ALERT_REC(?FATAL, ?NO_RENEGOTIATION)); {false, false} -> {ok, ConnectionStates} end. diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 63e751440a..57c72aa122 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -31,8 +31,6 @@ -type reply() :: term(). -type msg() :: term(). -type from() :: term(). --type host() :: inet:ip_address() | inet:hostname(). --type session_id() :: 0 | binary(). -type certdb_ref() :: reference(). -type db_handle() :: term(). -type der_cert() :: binary(). @@ -111,10 +109,10 @@ %% Local policy for the server if it want's to reuse the session %% or not. Defaluts to allways returning true. %% fun(SessionId, PeerCert, Compression, CipherSuite) -> boolean() - reuse_session, + reuse_session :: fun() | binary() | undefined, %% Server side is a fun() %% If false sessions will never be reused, if true they %% will be reused if possible. - reuse_sessions :: boolean(), + reuse_sessions :: boolean() | save, %% Only client side can use value save renegotiate_at, secure_renegotiate, client_renegotiation, @@ -148,6 +146,8 @@ max_handshake_size :: integer(), handshake, customize_hostname_check + %% , + %% save_session :: boolean() }). -record(socket_options, diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 4b735b2400..c56675b691 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -30,7 +30,7 @@ connection_init/3, cache_pem_file/2, lookup_trusted_cert/4, new_session_id/1, clean_cert_db/2, - register_session/2, register_session/3, invalidate_session/2, + register_session/2, register_session/4, invalidate_session/2, insert_crls/2, insert_crls/3, delete_crls/1, delete_crls/2, invalidate_session/3, name/1]). @@ -42,6 +42,8 @@ -include("ssl_handshake.hrl"). -include("ssl_internal.hrl"). +-include("ssl_api.hrl"). + -include_lib("kernel/include/file.hrl"). -record(state, { @@ -148,7 +150,7 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) -> ssl_pkix_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer). %%-------------------------------------------------------------------- --spec new_session_id(integer()) -> session_id(). +-spec new_session_id(integer()) -> ssl:session_id(). %% %% Description: Creates a session id for the server. %%-------------------------------------------------------------------- @@ -170,9 +172,11 @@ clean_cert_db(Ref, File) -> %% %% Description: Make the session available for reuse. %%-------------------------------------------------------------------- --spec register_session(host(), inet:port_number(), #session{}) -> ok. -register_session(Host, Port, Session) -> - cast({register_session, Host, Port, Session}). +-spec register_session(ssl:host(), inet:port_number(), #session{}, unique | true) -> ok. +register_session(Host, Port, Session, true) -> + call({register_session, Host, Port, Session}); +register_session(Host, Port, Session, unique = Save) -> + cast({register_session, Host, Port, Session, Save}). -spec register_session(inet:port_number(), #session{}) -> ok. register_session(Port, Session) -> @@ -183,7 +187,7 @@ register_session(Port, Session) -> %% a the session has been marked "is_resumable = false" for some while %% it will be safe to remove the data from the session database. %%-------------------------------------------------------------------- --spec invalidate_session(host(), inet:port_number(), #session{}) -> ok. +-spec invalidate_session(ssl:host(), inet:port_number(), #session{}) -> ok. invalidate_session(Host, Port, Session) -> load_mitigation(), cast({invalidate_session, Host, Port, Session}). @@ -301,7 +305,10 @@ handle_call({{new_session_id, Port}, _}, _, #state{session_cache_cb = CacheCb, session_cache_server = Cache} = State) -> Id = new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb), - {reply, Id, State}. + {reply, Id, State}; +handle_call({{register_session, Host, Port, Session},_}, _, State0) -> + State = client_register_session(Host, Port, Session, State0), + {reply, ok, State}. %%-------------------------------------------------------------------- -spec handle_cast(msg(), #state{}) -> {noreply, #state{}}. @@ -311,8 +318,12 @@ handle_call({{new_session_id, Port}, _}, %% %% Description: Handling cast messages %%-------------------------------------------------------------------- -handle_cast({register_session, Host, Port, Session}, State0) -> - State = ssl_client_register_session(Host, Port, Session, State0), +handle_cast({register_session, Host, Port, Session, unique}, State0) -> + State = client_register_unique_session(Host, Port, Session, State0), + {noreply, State}; + +handle_cast({register_session, Host, Port, Session, true}, State0) -> + State = client_register_session(Host, Port, Session, State0), {noreply, State}; handle_cast({register_session, Port, Session}, State0) -> @@ -540,10 +551,10 @@ clean_cert_db(Ref, CertDb, RefDb, FileMapDb, File) -> ok end. -ssl_client_register_session(Host, Port, Session, #state{session_cache_client = Cache, - session_cache_cb = CacheCb, - session_cache_client_max = Max, - session_client_invalidator = Pid0} = State) -> +client_register_unique_session(Host, Port, Session, #state{session_cache_client = Cache, + session_cache_cb = CacheCb, + session_cache_client_max = Max, + session_client_invalidator = Pid0} = State) -> TimeStamp = erlang:monotonic_time(), NewSession = Session#session{time_stamp = TimeStamp}, @@ -557,6 +568,17 @@ ssl_client_register_session(Host, Port, Session, #state{session_cache_client = C register_unique_session(Sessions, NewSession, {Host, Port}, State) end. +client_register_session(Host, Port, Session, #state{session_cache_client = Cache, + session_cache_cb = CacheCb, + session_cache_client_max = Max, + session_client_invalidator = Pid0} = State) -> + TimeStamp = erlang:monotonic_time(), + NewSession = Session#session{time_stamp = TimeStamp}, + Pid = do_register_session({{Host, Port}, + NewSession#session.session_id}, + NewSession, Max, Pid0, Cache, CacheCb), + State#state{session_client_invalidator = Pid}. + server_register_session(Port, Session, #state{session_cache_server_max = Max, session_cache_server = Cache, session_cache_cb = CacheCb, diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl index c9607489e9..44305c65fe 100644 --- a/lib/ssl/src/ssl_session.erl +++ b/lib/ssl/src/ssl_session.erl @@ -27,6 +27,7 @@ -include("ssl_handshake.hrl"). -include("ssl_internal.hrl"). +-include("ssl_api.hrl"). %% Internal application API -export([is_new/2, client_id/4, server_id/6, valid_session/2]). @@ -34,7 +35,7 @@ -type seconds() :: integer(). %%-------------------------------------------------------------------- --spec is_new(session_id(), session_id()) -> boolean(). +-spec is_new(ssl:session_id(), ssl:session_id()) -> boolean(). %% %% Description: Checks if the session id decided by the server is a %% new or resumed sesion id. @@ -47,12 +48,19 @@ is_new(_ClientSuggestion, _ServerDecision) -> true. %%-------------------------------------------------------------------- --spec client_id({host(), inet:port_number(), #ssl_options{}}, db_handle(), atom(), +-spec client_id({ssl:host(), inet:port_number(), #ssl_options{}}, db_handle(), atom(), undefined | binary()) -> binary(). %% %% Description: Should be called by the client side to get an id %% for the client hello message. %%-------------------------------------------------------------------- +client_id({Host, Port, #ssl_options{reuse_session = SessionId}}, Cache, CacheCb, _) when is_binary(SessionId)-> + case CacheCb:lookup(Cache, {{Host, Port}, SessionId}) of + undefined -> + <<>>; + #session{} -> + SessionId + end; client_id(ClientInfo, Cache, CacheCb, OwnCert) -> case select_session(ClientInfo, Cache, CacheCb, OwnCert) of no_session -> @@ -91,7 +99,8 @@ server_id(Port, SuggestedId, Options, Cert, Cache, CacheCb) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -select_session({_, _, #ssl_options{reuse_sessions=false}}, _Cache, _CacheCb, _OwnCert) -> +select_session({_, _, #ssl_options{reuse_sessions = Reuse}}, _Cache, _CacheCb, _OwnCert) when Reuse =/= true -> + %% If reuse_sessions == true | save a new session should be created no_session; select_session({HostIP, Port, SslOpts}, Cache, CacheCb, OwnCert) -> Sessions = CacheCb:select_session(Cache, {HostIP, Port}), @@ -132,7 +141,7 @@ is_resumable(SuggestedSessionId, Port, #ssl_options{reuse_session = ReuseFun} = false -> {false, undefined} end; undefined -> - {false, undefined} + {false, undefined} end. resumable(new) -> diff --git a/lib/ssl/src/ssl_session_cache_api.erl b/lib/ssl/src/ssl_session_cache_api.erl index b68c75a09b..5f96f905b1 100644 --- a/lib/ssl/src/ssl_session_cache_api.erl +++ b/lib/ssl/src/ssl_session_cache_api.erl @@ -23,14 +23,20 @@ -module(ssl_session_cache_api). -include("ssl_handshake.hrl"). -include("ssl_internal.hrl"). +-include("ssl_api.hrl"). --type key() :: {{host(), inet:port_number()}, session_id()} | {inet:port_number(), session_id()}. +-export_type([session_cache_key/0, session/0, partial_key/0, session_cache_ref/0]). --callback init(list()) -> db_handle(). --callback terminate(db_handle()) -> any(). --callback lookup(db_handle(), key()) -> #session{} | undefined. --callback update(db_handle(), key(), #session{}) -> any(). --callback delete(db_handle(), key()) -> any(). --callback foldl(fun(), term(), db_handle()) -> term(). --callback select_session(db_handle(), {host(), inet:port_number()} | inet:port_number()) -> [#session{}]. --callback size(db_handle()) -> integer(). +-type session_cache_ref() :: any(). +-type session_cache_key() :: {partial_key(), ssl:session_id()}. +-opaque session() :: #session{}. +-opaque partial_key() :: {ssl:host(), inet:port_number()} | inet:port_number(). + +-callback init(list()) -> session_cache_ref(). +-callback terminate(session_cache_ref()) -> any(). +-callback lookup(session_cache_ref(), session_cache_key()) -> #session{} | undefined. +-callback update(session_cache_ref(), session_cache_key(), #session{}) -> any(). +-callback delete(session_cache_ref(), session_cache_key()) -> any(). +-callback foldl(fun(), term(), session_cache_ref()) -> term(). +-callback select_session(session_cache_ref(), {ssl:host(), inet:port_number()} | inet:port_number()) -> [#session{}]. +-callback size(session_cache_ref()) -> integer(). diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 0f986b5e21..cee69a05a5 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -17,7 +17,6 @@ %% %% %CopyrightEnd% %% - %% %%---------------------------------------------------------------------- %% Purpose: Handles an ssl connection, e.i. both the setup @@ -47,7 +46,7 @@ %% State transition handling -export([next_event/3, next_event/4, - handle_common_event/4]). + handle_protocol_record/3]). %% Handshake handling -export([renegotiation/2, renegotiate/2, send_handshake/2, @@ -109,7 +108,7 @@ start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = true},_, Tracker} = end. %%-------------------------------------------------------------------- --spec start_link(atom(), pid(), host(), inet:port_number(), port(), list(), pid(), tuple()) -> +-spec start_link(atom(), pid(), ssl:host(), inet:port_number(), port(), list(), pid(), tuple()) -> {ok, pid()} | ignore | {error, reason()}. %% %% Description: Creates a gen_statem process which calls Module:init/1 to @@ -144,28 +143,31 @@ pids(#state{protocol_specific = #{sender := Sender}}) -> %%==================================================================== %% State transition handling %%==================================================================== -next_record(#state{unprocessed_handshake_events = N} = State) when N > 0 -> - {no_record, State#state{unprocessed_handshake_events = N-1}}; - +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_packets = [], tls_cipher_texts = [CT | Rest]} - = Buffers, - connection_states = ConnStates0, - ssl_options = #ssl_options{padding_check = Check}} = State) -> - case tls_record:decode_cipher_text(CT, ConnStates0, Check) of - {Plain, ConnStates} -> - {Plain, State#state{protocol_buffers = - Buffers#protocol_buffers{tls_cipher_texts = Rest}, - connection_states = ConnStates}}; - #alert{} = Alert -> - {Alert, State} - end; + #protocol_buffers{tls_packets = [], tls_cipher_texts = [#ssl_tls{type = Type}| _] = CipherTexts0} + = Buffers, + connection_states = ConnectionStates0, + ssl_options = #ssl_options{padding_check = Check}} = State) -> + case decode_cipher_texts(Type, CipherTexts0, ConnectionStates0, Check, <<>>) of + {#ssl_tls{} = Record, ConnectionStates, CipherTexts} -> + {Record, State#state{protocol_buffers = Buffers#protocol_buffers{tls_cipher_texts = CipherTexts}, + connection_states = ConnectionStates}}; + {#alert{} = Alert, ConnectionStates, CipherTexts} -> + {Alert, State#state{protocol_buffers = Buffers#protocol_buffers{tls_cipher_texts = CipherTexts}, + connection_states = ConnectionStates}} + end; next_record(#state{protocol_buffers = #protocol_buffers{tls_packets = [], tls_cipher_texts = []}, protocol_specific = #{active_n_toggle := true, active_n := N} = ProtocolSpec, - socket = Socket, - close_tag = CloseTag, - transport_cb = Transport} = State) -> - case tls_socket:setopts(Transport, Socket, [{active, N}]) of + 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}}}; _ -> @@ -196,11 +198,34 @@ next_event(StateName, Record, State, Actions) -> {next_state, StateName, State, [{next_event, internal, Alert} | Actions]} end. -handle_common_event(internal, #alert{} = Alert, StateName, - #state{negotiated_version = Version} = State) -> - ssl_connection:handle_own_alert(Alert, Version, StateName, State); +decode_cipher_texts(Type, [] = CipherTexts, ConnectionStates, _, Acc) -> + {#ssl_tls{type = Type, fragment = Acc}, ConnectionStates, CipherTexts}; +decode_cipher_texts(Type, + [#ssl_tls{type = Type} = CT | CipherTexts], ConnectionStates0, Check, Acc) -> + case tls_record:decode_cipher_text(CT, ConnectionStates0, Check) of + {#ssl_tls{type = ?APPLICATION_DATA, fragment = Plain}, ConnectionStates} -> + decode_cipher_texts(Type, CipherTexts, + ConnectionStates, Check, <<Acc/binary, Plain/binary>>); + {#ssl_tls{type = Type, fragment = Plain}, ConnectionStates} -> + {#ssl_tls{type = Type, fragment = Plain}, ConnectionStates, CipherTexts}; + #alert{} = Alert -> + {Alert, ConnectionStates0, CipherTexts} + end; +decode_cipher_texts(Type, CipherTexts, ConnectionStates, _, Acc) -> + {#ssl_tls{type = Type, fragment = Acc}, ConnectionStates, CipherTexts}. + +%%% TLS record protocol level application data messages + +handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State0) -> + case ssl_connection:read_application_data(Data, State0) of + {stop, _, _} = Stop-> + Stop; + {Record, State1} -> + {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_common_event(internal, #ssl_tls{type = ?HANDSHAKE, fragment = Data}, +handle_protocol_record(#ssl_tls{type = ?HANDSHAKE, fragment = Data}, StateName, #state{protocol_buffers = #protocol_buffers{tls_handshake_buffer = Buf0} = Buffers, negotiated_version = Version, @@ -220,22 +245,23 @@ handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE, fragment = Data}, connection -> ssl_connection:hibernate_after(StateName, State, Events); _ -> + HsEnv = State#state.handshake_env, {next_state, StateName, - State#state{unprocessed_handshake_events = unprocessed_events(Events)}, Events} + State#state{protocol_buffers = Buffers, + handshake_env = + HsEnv#handshake_env{unprocessed_handshake_events + = unprocessed_events(Events)}}, Events} end end catch throw:#alert{} = Alert -> ssl_connection:handle_own_alert(Alert, Version, StateName, State0) end; -%%% TLS record protocol level application data messages -handle_common_event(internal, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State) -> - {next_state, StateName, State, [{next_event, internal, {application_data, Data}}]}; %%% TLS record protocol level change cipher messages -handle_common_event(internal, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) -> +handle_protocol_record(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) -> {next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]}; %%% TLS record protocol level Alert messages -handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName, - #state{negotiated_version = Version} = State) -> +handle_protocol_record(#ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName, + #state{negotiated_version = Version} = State) -> try decode_alerts(EncAlerts) of Alerts = [_|_] -> handle_alerts(Alerts, {next_state, StateName, State}); @@ -251,23 +277,25 @@ handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, Sta end; %% Ignore unknown TLS record level protocol messages -handle_common_event(internal, #ssl_tls{type = _Unknown}, StateName, State) -> - {next_state, StateName, State}. +handle_protocol_record(#ssl_tls{type = _Unknown}, StateName, State) -> + {next_state, StateName, State, []}. %%==================================================================== %% Handshake handling %%==================================================================== renegotiation(Pid, WriteState) -> gen_statem:call(Pid, {user_renegotiate, WriteState}). -renegotiate(#state{role = client} = State, Actions) -> +renegotiate(#state{static_env = #static_env{role = client}, + handshake_env = HsEnv} = State, Actions) -> %% Handle same way as if server requested %% the renegotiation Hs0 = ssl_handshake:init_handshake_history(), - {next_state, connection, State#state{tls_handshake_history = Hs0}, + {next_state, connection, State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = Hs0}}, [{next_event, internal, #hello_request{}} | Actions]}; -renegotiate(#state{role = server, - socket = Socket, - transport_cb = Transport, +renegotiate(#state{static_env = #static_env{role = server, + socket = Socket, + transport_cb = Transport}, + handshake_env = HsEnv, negotiated_version = Version, connection_states = ConnectionStates0} = State0, Actions) -> HelloRequest = ssl_handshake:hello_request(), @@ -278,24 +306,24 @@ renegotiate(#state{role = server, send(Transport, Socket, BinMsg), State = State0#state{connection_states = ConnectionStates, - tls_handshake_history = Hs0}, + handshake_env = HsEnv#handshake_env{tls_handshake_history = Hs0}}, next_event(hello, no_record, State, Actions). send_handshake(Handshake, State) -> send_handshake_flight(queue_handshake(Handshake, State)). queue_handshake(Handshake, #state{negotiated_version = Version, - tls_handshake_history = Hist0, + handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv, flight_buffer = Flight0, connection_states = ConnectionStates0} = State0) -> {BinHandshake, ConnectionStates, Hist} = encode_handshake(Handshake, Version, ConnectionStates0, Hist0), State0#state{connection_states = ConnectionStates, - tls_handshake_history = Hist, + handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}, flight_buffer = Flight0 ++ [BinHandshake]}. -send_handshake_flight(#state{socket = Socket, - transport_cb = Transport, +send_handshake_flight(#state{static_env = #static_env{socket = Socket, + transport_cb = Transport}, flight_buffer = Flight} = State0) -> send(Transport, Socket, Flight), {State0#state{flight_buffer = []}, []}. @@ -314,14 +342,14 @@ reinit(#state{protocol_specific = #{sender := Sender}, tls_sender:update_connection_state(Sender, Write, Version), reinit_handshake_data(State). -reinit_handshake_data(State) -> +reinit_handshake_data(#state{handshake_env = HsEnv} =State) -> %% premaster_secret, public_key_info and tls_handshake_info %% are only needed during the handshake phase. %% To reduce memory foot print of a connection reinitialize them. State#state{ premaster_secret = undefined, public_key_info = undefined, - tls_handshake_history = ssl_handshake:init_handshake_history() + handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history()} }. select_sni_extension(#client_hello{extensions = HelloExtensions}) -> @@ -345,8 +373,8 @@ encode_alert(#alert{} = Alert, Version, ConnectionStates) -> tls_record:encode_alert_record(Alert, Version, ConnectionStates). send_alert(Alert, #state{negotiated_version = Version, - socket = Socket, - transport_cb = Transport, + static_env = #static_env{socket = Socket, + transport_cb = Transport}, connection_states = ConnectionStates0} = StateData0) -> {BinMsg, ConnectionStates} = encode_alert(Alert, Version, ConnectionStates0), @@ -429,14 +457,17 @@ getopts(Transport, Socket, Tag) -> %%-------------------------------------------------------------------- init({call, From}, {start, Timeout}, - #state{host = Host, port = Port, role = client, + #state{static_env = #static_env{role = client, + host = Host, + port = Port, + transport_cb = Transport, + socket = Socket, + session_cache = Cache, + session_cache_cb = CacheCb}, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, ssl_options = SslOpts, session = #session{own_certificate = Cert} = Session0, - transport_cb = Transport, socket = Socket, - connection_states = ConnectionStates0, - renegotiation = {Renegotiation, _}, - session_cache = Cache, - session_cache_cb = CacheCb + connection_states = ConnectionStates0 } = State0) -> Timer = ssl_connection:start_or_recv_cancel_timer(Timeout, From), Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, @@ -452,7 +483,7 @@ init({call, From}, {start, Timeout}, negotiated_version = Version, %% Requested version session = Session0#session{session_id = Hello#client_hello.session_id}, - tls_handshake_history = Handshake, + handshake_env = HsEnv#handshake_env{tls_handshake_history = Handshake}, start_or_recv_from = From, timer = Timer}, next_event(hello, no_record, State); @@ -466,8 +497,9 @@ init(Type, Event, State) -> %%-------------------------------------------------------------------- error({call, From}, {start, _Timeout}, #state{protocol_specific = #{error := Error}} = State) -> - ssl_connection:stop_and_reply( - normal, {reply, From, {error, Error}}, State); + {stop_and_reply, {shutdown, normal}, + [{reply, From, {error, Error}}], State}; + error({call, _} = Call, Msg, State) -> gen_handshake(?FUNCTION_NAME, Call, Msg, State); error(_, _, _) -> @@ -493,10 +525,12 @@ hello(internal, #server_hello{extensions = Extensions} = Hello, [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]}; hello(internal, #client_hello{client_version = ClientVersion} = Hello, #state{connection_states = ConnectionStates0, - port = Port, session = #session{own_certificate = Cert} = Session0, - renegotiation = {Renegotiation, _}, - session_cache = Cache, - session_cache_cb = CacheCb, + static_env = #static_env{ + port = Port, + session_cache = Cache, + session_cache_cb = CacheCb}, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, + session = #session{own_certificate = Cert} = Session0, negotiated_protocol = CurrentProtocol, key_algorithm = KeyExAlg, ssl_options = SslOpts} = State) -> @@ -516,15 +550,15 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello, State#state{connection_states = ConnectionStates, negotiated_version = Version, hashsign_algorithm = HashSign, - client_hello_version = ClientVersion, + handshake_env = HsEnv#handshake_env{client_hello_version = ClientVersion}, session = Session, negotiated_protocol = Protocol}) end; hello(internal, #server_hello{} = Hello, #state{connection_states = ConnectionStates0, negotiated_version = ReqVersion, - role = client, - renegotiation = {Renegotiation, _}, + static_env = #static_env{role = client}, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, ssl_options = SslOptions} = State) -> case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of #alert{} = Alert -> @@ -580,22 +614,72 @@ connection({call, From}, {user_renegotiate, WriteState}, #state{connection_states = ConnectionStates} = State) -> {next_state, ?FUNCTION_NAME, State#state{connection_states = ConnectionStates#{current_write => WriteState}}, [{next_event,{call, From}, renegotiate}]}; +connection({call, From}, + {close, {Pid, _Timeout}}, + #state{terminated = closed} = State) -> + {next_state, downgrade, State#state{terminated = true, downgrade = {Pid, From}}, + [{next_event, internal, ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY)}]}; +connection({call, From}, + {close,{Pid, Timeout}}, + #state{connection_states = ConnectionStates, + protocol_specific = #{sender := Sender} + } = State0) -> + case tls_sender:downgrade(Sender, Timeout) of + {ok, Write} -> + %% User downgrades connection + %% When downgrading an TLS connection to a transport connection + %% we must recive the close alert from the peer before releasing the + %% transport socket. + State = send_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), + State0#state{connection_states = + ConnectionStates#{current_write => Write}}), + {next_state, downgrade, State#state{downgrade = {Pid, From}, + terminated = true}, [{timeout, Timeout, downgrade}]}; + {error, timeout} -> + {stop_and_reply, {shutdown, downgrade_fail}, [{reply, From, {error, timeout}}]} + end; connection(internal, #hello_request{}, - #state{role = client, - renegotiation = {Renegotiation, _}, - host = Host, port = Port, + #state{static_env = #static_env{role = client, + host = Host, + port = Port, + session_cache = Cache, + session_cache_cb = CacheCb}, + handshake_env = #handshake_env{renegotiation = {Renegotiation, peer}}, session = #session{own_certificate = Cert} = Session0, - session_cache = Cache, session_cache_cb = CacheCb, - ssl_options = SslOpts, + ssl_options = SslOpts, + protocol_specific = #{sender := Pid}, + connection_states = ConnectionStates} = State0) -> + try tls_sender:peer_renegotiate(Pid) of + {ok, Write} -> + Hello = tls_handshake:client_hello(Host, Port, ConnectionStates, SslOpts, + Cache, CacheCb, Renegotiation, Cert), + {State, Actions} = send_handshake(Hello, State0#state{connection_states = ConnectionStates#{current_write => Write}}), + next_event(hello, no_record, State#state{session = Session0#session{session_id + = Hello#client_hello.session_id}}, Actions) + catch + _:_ -> + {stop, {shutdown, sender_blocked}, State0} + end; +connection(internal, #hello_request{}, + #state{static_env = #static_env{role = client, + host = Host, + port = Port, + session_cache = Cache, + session_cache_cb = CacheCb}, + handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, + session = #session{own_certificate = Cert} = Session0, + ssl_options = SslOpts, connection_states = ConnectionStates} = State0) -> Hello = tls_handshake:client_hello(Host, Port, ConnectionStates, SslOpts, - Cache, CacheCb, Renegotiation, Cert), + Cache, CacheCb, Renegotiation, Cert), {State, Actions} = send_handshake(Hello, State0), next_event(hello, no_record, State#state{session = Session0#session{session_id = Hello#client_hello.session_id}}, Actions); connection(internal, #client_hello{} = Hello, - #state{role = server, allow_renegotiate = true, connection_states = CS, - %%protocol_cb = Connection, + #state{static_env = #static_env{role = server}, + handshake_env = HsEnv, + allow_renegotiate = true, + connection_states = CS, protocol_specific = #{sender := Sender} } = State) -> %% Mitigate Computational DoS attack @@ -607,16 +691,18 @@ connection(internal, #client_hello{} = Hello, {ok, Write} = tls_sender:renegotiate(Sender), next_event(hello, no_record, State#state{connection_states = CS#{current_write => Write}, allow_renegotiate = false, - renegotiation = {true, peer} + handshake_env = HsEnv#handshake_env{renegotiation = {true, peer}} }, [{next_event, internal, Hello}]); connection(internal, #client_hello{}, - #state{role = server, allow_renegotiate = false, - protocol_cb = Connection} = State0) -> + #state{static_env = #static_env{role = server, + protocol_cb = Connection}, + allow_renegotiate = false} = State0) -> Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION), send_alert_in_connection(Alert, State0), State = Connection:reinit_handshake_data(State0), next_event(?FUNCTION_NAME, no_record, State); + connection(Type, Event, State) -> ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE). @@ -624,19 +710,34 @@ connection(Type, Event, State) -> -spec downgrade(gen_statem:event_type(), term(), #state{}) -> gen_statem:state_function_result(). %%-------------------------------------------------------------------- +downgrade(internal, #alert{description = ?CLOSE_NOTIFY}, + #state{static_env = #static_env{transport_cb = Transport, + socket = Socket}, + downgrade = {Pid, From}} = State) -> + tls_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]), + Transport:controlling_process(Socket, Pid), + {stop_and_reply, {shutdown, downgrade},[{reply, From, {ok, Socket}}], State}; +downgrade(timeout, downgrade, #state{downgrade = {_, From}} = State) -> + {stop_and_reply, {shutdown, normal},[{reply, From, {error, timeout}}], State}; +downgrade(info, {CloseTag, Socket}, + #state{static_env = #static_env{socket = Socket, + close_tag = CloseTag}, downgrade = {_, From}} = + State) -> + {stop_and_reply, {shutdown, normal},[{reply, From, {error, CloseTag}}], State}; +downgrade(info, Info, State) -> + handle_info(Info, ?FUNCTION_NAME, State); downgrade(Type, Event, State) -> - ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE). - + ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE). %-------------------------------------------------------------------- %% gen_statem callbacks %%-------------------------------------------------------------------- callback_mode() -> state_functions. - -terminate( - {shutdown, sender_died, Reason}, _StateName, - #state{socket = Socket, transport_cb = Transport} = State) -> +terminate({shutdown, sender_died, Reason}, _StateName, + #state{static_env = #static_env{socket = Socket, + transport_cb = Transport}} + = State) -> ssl_connection:handle_trusted_certs_db(State), close(Reason, Socket, Transport, undefined, undefined); terminate(Reason, StateName, State) -> @@ -658,64 +759,62 @@ initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Trac erl_dist = IsErlDist} = SSLOptions, ConnectionStates = tls_record:init_connection_states(Role, BeastMitigation), - ErlDistData = erl_dist_data(IsErlDist), SessionCacheCb = case application:get_env(ssl, session_cb) of {ok, Cb} when is_atom(Cb) -> Cb; _ -> ssl_session_cache end, - InternalActiveN = case application:get_env(ssl, internal_active_n) of {ok, N} when is_integer(N) andalso (not IsErlDist) -> N; _ -> ?INTERNAL_ACTIVE_N end, - UserMonitor = erlang:monitor(process, User), - - #state{socket_options = SocketOptions, - ssl_options = SSLOptions, - session = #session{is_resumable = new}, - transport_cb = CbModule, - data_tag = DataTag, - close_tag = CloseTag, - error_tag = ErrorTag, - role = Role, - host = Host, - port = Port, - socket = Socket, - erl_dist_data = ErlDistData, - connection_states = ConnectionStates, - protocol_buffers = #protocol_buffers{}, - user_application = {UserMonitor, User}, - user_data_buffer = <<>>, - session_cache_cb = SessionCacheCb, - renegotiation = {false, first}, - allow_renegotiate = SSLOptions#ssl_options.client_renegotiation, - start_or_recv_from = undefined, - protocol_cb = ?MODULE, - tracker = Tracker, - flight_buffer = [], - protocol_specific = #{sender => Sender, - active_n => InternalActiveN, - active_n_toggle => true - } - }. - -erl_dist_data(true) -> - #{dist_handle => undefined, - dist_buffer => <<>>}; -erl_dist_data(false) -> - #{}. - -initialize_tls_sender(#state{role = Role, - socket = Socket, + InitStatEnv = #static_env{ + role = Role, + transport_cb = CbModule, + protocol_cb = ?MODULE, + data_tag = DataTag, + close_tag = CloseTag, + error_tag = ErrorTag, + host = Host, + port = Port, + socket = Socket, + session_cache_cb = SessionCacheCb, + tracker = Tracker + }, + #state{ + static_env = InitStatEnv, + handshake_env = #handshake_env{ + tls_handshake_history = ssl_handshake:init_handshake_history(), + renegotiation = {false, first} + }, + socket_options = SocketOptions, + ssl_options = SSLOptions, + session = #session{is_resumable = new}, + connection_states = ConnectionStates, + protocol_buffers = #protocol_buffers{}, + user_application = {UserMonitor, User}, + user_data_buffer = <<>>, + allow_renegotiate = SSLOptions#ssl_options.client_renegotiation, + start_or_recv_from = undefined, + flight_buffer = [], + protocol_specific = #{sender => Sender, + active_n => InternalActiveN, + active_n_toggle => true + } + }. + +initialize_tls_sender(#state{static_env = #static_env{ + role = Role, + transport_cb = Transport, + protocol_cb = Connection, + socket = Socket, + tracker = Tracker + }, socket_options = SockOpts, - tracker = Tracker, - protocol_cb = Connection, - transport_cb = Transport, negotiated_version = Version, ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}, connection_states = #{current_write := ConnectionWriteState}, @@ -748,10 +847,11 @@ next_tls_record(Data, StateName, #state{protocol_buffers = end. +acceptable_record_versions(StateName, #state{negotiated_version = Version}) when StateName =/= hello-> + Version; acceptable_record_versions(hello, _) -> - [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_VERSIONS]; -acceptable_record_versions(_, #state{negotiated_version = Version}) -> - [Version]. + [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_VERSIONS]. + handle_record_alert(Alert, _) -> Alert. @@ -762,21 +862,22 @@ tls_handshake_events(Packets) -> %% raw data from socket, upack records handle_info({Protocol, _, Data}, StateName, - #state{data_tag = Protocol - } = State0) -> + #state{static_env = #static_env{data_tag = Protocol}} = State0) -> case next_tls_record(Data, StateName, State0) of {Record, State} -> next_event(StateName, Record, State); #alert{} = Alert -> ssl_connection:handle_normal_shutdown(Alert, StateName, State0), - ssl_connection:stop({shutdown, own_alert}, State0) + {stop, {shutdown, own_alert}, State0} end; -handle_info({tcp_passive, Socket}, StateName, #state{socket = Socket, - protocol_specific = PS - } = State) -> - next_event(StateName, no_record, State#state{protocol_specific = PS#{active_n_toggle => true}}); +handle_info({tcp_passive, Socket}, StateName, + #state{static_env = #static_env{socket = Socket}, + protocol_specific = PS + } = State) -> + next_event(StateName, no_record, + State#state{protocol_specific = PS#{active_n_toggle => true}}); handle_info({CloseTag, Socket}, StateName, - #state{socket = Socket, close_tag = CloseTag, + #state{static_env = #static_env{socket = Socket, close_tag = CloseTag}, socket_options = #socket_options{active = Active}, protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs}, user_data_buffer = Buffer, @@ -802,7 +903,7 @@ handle_info({CloseTag, Socket}, StateName, end, ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State), - ssl_connection:stop({shutdown, transport_closed}, State); + {stop, {shutdown, transport_closed}, State}; true -> %% Fixes non-delivery of final TLS record in {active, once}. %% Basically allows the application the opportunity to set {active, once} again @@ -820,6 +921,13 @@ handle_alerts([], Result) -> Result; handle_alerts(_, {stop, _, _} = Stop) -> Stop; +handle_alerts([#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} | _Alerts], + {next_state, connection = StateName, #state{user_data_buffer = Buffer, + socket_options = #socket_options{active = false}, + protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs}} = + State}) when (Buffer =/= <<>>) orelse + (CTs =/= []) -> + {next_state, StateName, State#state{terminated = true}}; handle_alerts([Alert | Alerts], {next_state, StateName, State}) -> handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)); handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) -> diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl index 19a5eb0348..fbb81f56fe 100644 --- a/lib/ssl/src/tls_handshake.erl +++ b/lib/ssl/src/tls_handshake.erl @@ -30,6 +30,7 @@ -include("ssl_alert.hrl"). -include("ssl_internal.hrl"). -include("ssl_cipher.hrl"). +-include("ssl_api.hrl"). -include_lib("public_key/include/public_key.hrl"). %% Handshake handling @@ -47,7 +48,7 @@ %% Handshake handling %%==================================================================== %%-------------------------------------------------------------------- --spec client_hello(host(), inet:port_number(), ssl_record:connection_states(), +-spec client_hello(ssl:host(), inet:port_number(), ssl_record:connection_states(), #ssl_options{}, integer(), atom(), boolean(), der_cert()) -> #client_hello{}. %% @@ -81,13 +82,13 @@ client_hello(Host, Port, ConnectionStates, -spec hello(#server_hello{} | #client_hello{}, #ssl_options{}, ssl_record:connection_states() | {inet:port_number(), #session{}, db_handle(), atom(), ssl_record:connection_states(), - binary() | undefined, ssl_cipher_format:key_algo()}, + binary() | undefined, ssl:key_algo()}, boolean()) -> - {tls_record:tls_version(), session_id(), + {tls_record:tls_version(), ssl:session_id(), ssl_record:connection_states(), alpn | npn, binary() | undefined}| {tls_record:tls_version(), {resumed | new, #session{}}, ssl_record:connection_states(), binary() | undefined, - #hello_extensions{}, {ssl_cipher_format:hash(), ssl_cipher_format:sign_algo()} | + #hello_extensions{}, {ssl:hash(), ssl:sign_algo()} | undefined} | #alert{}. %% %% Description: Handles a received hello message @@ -223,8 +224,6 @@ handle_client_hello_extensions(Version, Type, Random, CipherSuites, HelloExt, Version, SslOpts, Session0, ConnectionStates0, Renegotiation) of - #alert{} = Alert -> - Alert; {Session, ConnectionStates, Protocol, ServerHelloExt} -> {Version, {Type, Session}, ConnectionStates, Protocol, ServerHelloExt, HashSign} @@ -235,14 +234,14 @@ handle_client_hello_extensions(Version, Type, Random, CipherSuites, handle_server_hello_extensions(Version, SessionId, Random, CipherSuite, Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation) -> - case ssl_handshake:handle_server_hello_extensions(tls_record, Random, CipherSuite, + try ssl_handshake:handle_server_hello_extensions(tls_record, Random, CipherSuite, Compression, HelloExt, Version, SslOpt, ConnectionStates0, - Renegotiation) of - #alert{} = Alert -> - Alert; + Renegotiation) of {ConnectionStates, ProtoExt, Protocol} -> {Version, SessionId, ConnectionStates, ProtoExt, Protocol} + catch throw:Alert -> + Alert end. %%-------------------------------------------------------------------- enc_handshake(#hello_request{}, _Version) -> diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl index cf0690f2a5..1776ec2627 100644 --- a/lib/ssl/src/tls_record.erl +++ b/lib/ssl/src/tls_record.erl @@ -75,26 +75,15 @@ init_connection_states(Role, BeastMitigation) -> pending_write => Pending}. %%-------------------------------------------------------------------- --spec get_tls_records(binary(), [tls_version()], binary()) -> {[binary()], binary()} | #alert{}. +-spec get_tls_records(binary(), [tls_version()] | tls_version(), binary()) -> {[binary()], binary()} | #alert{}. %% %% and returns it as a list of tls_compressed binaries also returns leftover %% Description: Given old buffer and new data from TCP, packs up a records %% data %%-------------------------------------------------------------------- -get_tls_records(Data, Versions, Buffer) -> - BinData = list_to_binary([Buffer, Data]), - case erlang:byte_size(BinData) of - N when N >= 3 -> - case assert_version(BinData, Versions) of - true -> - get_tls_records_aux(BinData, []); - false -> - ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) - end; - _ -> - get_tls_records_aux(BinData, []) - end. - +get_tls_records(Data, Version, Buffer) -> + get_tls_records_aux(Version, <<Buffer/binary, Data/binary>>, []). + %%==================================================================== %% Encoding %%==================================================================== @@ -395,44 +384,51 @@ initial_connection_state(ConnectionEnd, BeastMitigation) -> server_verify_data => undefined }. -assert_version(<<?BYTE(_), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>>, Versions) -> - is_acceptable_version({MajVer, MinVer}, Versions). - -get_tls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer), - ?UINT16(Length), Data:Length/binary, Rest/binary>>, - Acc) -> - get_tls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA, - version = {MajVer, MinVer}, - fragment = Data} | Acc]); -get_tls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer), - ?UINT16(Length), - Data:Length/binary, Rest/binary>>, Acc) -> - get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE, - version = {MajVer, MinVer}, +get_tls_records_aux({MajVer, MinVer} = Version, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer), + ?UINT16(Length), Data:Length/binary, Rest/binary>>, + Acc) when Type == ?APPLICATION_DATA; + Type == ?HANDSHAKE; + Type == ?ALERT; + Type == ?CHANGE_CIPHER_SPEC -> + get_tls_records_aux(Version, Rest, [#ssl_tls{type = Type, + version = Version, fragment = Data} | Acc]); -get_tls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer), - ?UINT16(Length), Data:Length/binary, - Rest/binary>>, Acc) -> - get_tls_records_aux(Rest, [#ssl_tls{type = ?ALERT, - version = {MajVer, MinVer}, - fragment = Data} | Acc]); -get_tls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer), - ?UINT16(Length), Data:Length/binary, Rest/binary>>, - Acc) -> - get_tls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC, - version = {MajVer, MinVer}, - fragment = Data} | Acc]); -get_tls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer), - ?UINT16(Length), _/binary>>, +get_tls_records_aux(Versions, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer), + ?UINT16(Length), Data:Length/binary, Rest/binary>>, + Acc) when is_list(Versions) andalso + ((Type == ?APPLICATION_DATA) + orelse + (Type == ?HANDSHAKE) + orelse + (Type == ?ALERT) + orelse + (Type == ?CHANGE_CIPHER_SPEC)) -> + case is_acceptable_version({MajVer, MinVer}, Versions) of + true -> + get_tls_records_aux(Versions, Rest, [#ssl_tls{type = Type, + version = {MajVer, MinVer}, + fragment = Data} | Acc]); + false -> + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) + end; +get_tls_records_aux(_, <<?BYTE(Type),?BYTE(_MajVer),?BYTE(_MinVer), + ?UINT16(Length), _:Length/binary, _Rest/binary>>, + _) when Type == ?APPLICATION_DATA; + Type == ?HANDSHAKE; + Type == ?ALERT; + Type == ?CHANGE_CIPHER_SPEC -> + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC); +get_tls_records_aux(_, <<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer), + ?UINT16(Length), _/binary>>, _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH -> ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW); -get_tls_records_aux(Data, Acc) -> +get_tls_records_aux(_, Data, Acc) -> case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of true -> {lists:reverse(Acc), Data}; false -> ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE) - end. + end. %%-------------------------------------------------------------------- encode_plain_text(Type, Version, Data, #{current_write := Write0} = ConnectionStates) -> {CipherFragment, Write1} = do_encode_plain_text(Type, Version, Data, Write0), diff --git a/lib/ssl/src/tls_sender.erl b/lib/ssl/src/tls_sender.erl index ee2b7be4f4..11fcc6def0 100644 --- a/lib/ssl/src/tls_sender.erl +++ b/lib/ssl/src/tls_sender.erl @@ -29,7 +29,7 @@ %% API -export([start/0, start/1, initialize/2, send_data/2, send_alert/2, - send_and_ack_alert/2, setopts/2, renegotiate/1, + send_and_ack_alert/2, setopts/2, renegotiate/1, peer_renegotiate/1, downgrade/2, update_connection_state/3, dist_tls_socket/1, dist_handshake_complete/3]). %% gen_statem callbacks @@ -118,6 +118,15 @@ setopts(Pid, Opts) -> renegotiate(Pid) -> %% Needs error handling for external API call(Pid, renegotiate). + +%%-------------------------------------------------------------------- +-spec peer_renegotiate(pid()) -> {ok, WriteState::map()} | {error, term()}. +%% Description: So TLS connection process can synchronize the +%% encryption state to be used when handshaking. +%%-------------------------------------------------------------------- +peer_renegotiate(Pid) -> + gen_statem:call(Pid, renegotiate, ?DEFAULT_TIMEOUT). + %%-------------------------------------------------------------------- -spec update_connection_state(pid(), WriteState::map(), tls_record:tls_version()) -> ok. %% Description: So TLS connection process can synchronize the @@ -125,6 +134,21 @@ renegotiate(Pid) -> %%-------------------------------------------------------------------- update_connection_state(Pid, NewState, Version) -> gen_statem:cast(Pid, {new_write, NewState, Version}). + +%%-------------------------------------------------------------------- +-spec downgrade(pid(), integer()) -> {ok, ssl_record:connection_state()} + | {error, timeout}. +%% Description: So TLS connection process can synchronize the +%% encryption state to be used when sending application data. +%%-------------------------------------------------------------------- +downgrade(Pid, Timeout) -> + try gen_statem:call(Pid, downgrade, Timeout) of + Result -> + Result + catch + _:_ -> + {error, timeout} + end. %%-------------------------------------------------------------------- -spec dist_handshake_complete(pid(), node(), term()) -> ok. %% Description: Erlang distribution callback @@ -239,6 +263,9 @@ connection({call, From}, {ack_alert, #alert{} = Alert}, StateData0) -> StateData = send_tls_alert(Alert, StateData0), {next_state, ?FUNCTION_NAME, StateData, [{reply,From,ok}]}; +connection({call, From}, downgrade, #data{connection_states = + #{current_write := Write}} = StateData) -> + {next_state, death_row, StateData, [{reply,From, {ok, Write}}]}; connection(internal, {application_packets, From, Data}, StateData) -> send_application_data(Data, From, ?FUNCTION_NAME, StateData); %% diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index 9dfb2eba53..a10f71a3de 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -29,7 +29,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Application version # ---------------------------------------------------- include ../vsn.mk -VSN=$(GS_VSN) +VSN=$(SSL_VSN) # ---------------------------------------------------- # Target Specs diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl index 8fe7c54549..7f3371da9a 100644 --- a/lib/ssl/test/make_certs.erl +++ b/lib/ssl/test/make_certs.erl @@ -189,6 +189,18 @@ gencrl(Root, CA, C, CrlHours) -> Env = [{"ROOTDIR", filename:absname(Root)}], cmd(Cmd, Env). +%% This function sets the number of seconds until the next CRL is due. +gencrl_sec(Root, CA, C, CrlSecs) -> + CACnfFile = filename:join([Root, CA, "ca.cnf"]), + CACRLFile = filename:join([Root, CA, "crl.pem"]), + Cmd = [C#config.openssl_cmd, " ca" + " -gencrl ", + " -crlsec ", integer_to_list(CrlSecs), + " -out ", CACRLFile, + " -config ", CACnfFile], + Env = [{"ROOTDIR", filename:absname(Root)}], + cmd(Cmd, Env). + can_generate_expired_crls(C) -> %% OpenSSL can generate CRLs with an expiration date in the past, %% if we pass a negative number for -crlhours. However, LibreSSL diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl index a5309e866b..ca8d0ec70c 100644 --- a/lib/ssl/test/ssl_ECC_SUITE.erl +++ b/lib/ssl/test/ssl_ECC_SUITE.erl @@ -212,53 +212,61 @@ client_ecdsa_server_ecdsa_with_raw_key(Config) when is_list(Config) -> ecc_default_order(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], - ecdhe_ecdsa, ecdhe_ecdsa, Config), + ecdhe_ecdsa, ecdhe_ecdsa, + Config, DefaultCurve), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), ECCOpts = [], - case ssl_test_lib:supported_eccs([{eccs, [sect571r1]}]) of - true -> ssl_test_lib:ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config); + case ssl_test_lib:supported_eccs([{eccs, [DefaultCurve]}]) of + true -> ssl_test_lib:ecc_test(DefaultCurve, COpts, SOpts, [], ECCOpts, Config); false -> {skip, "unsupported named curves"} end. ecc_default_order_custom_curves(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], - ecdhe_ecdsa, ecdhe_ecdsa, Config), + ecdhe_ecdsa, ecdhe_ecdsa, + Config, DefaultCurve), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{eccs, [secp256r1, sect571r1]}], + ECCOpts = [{eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of - true -> ssl_test_lib:ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config); + true -> ssl_test_lib:ecc_test(DefaultCurve, COpts, SOpts, [], ECCOpts, Config); false -> {skip, "unsupported named curves"} end. ecc_client_order(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], - ecdhe_ecdsa, ecdhe_ecdsa, Config), + ecdhe_ecdsa, ecdhe_ecdsa, + Config, DefaultCurve), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), ECCOpts = [{honor_ecc_order, false}], - case ssl_test_lib:supported_eccs([{eccs, [sect571r1]}]) of - true -> ssl_test_lib:ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config); + case ssl_test_lib:supported_eccs([{eccs, [DefaultCurve]}]) of + true -> ssl_test_lib:ecc_test(DefaultCurve, COpts, SOpts, [], ECCOpts, Config); false -> {skip, "unsupported named curves"} end. ecc_client_order_custom_curves(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], - ecdhe_ecdsa, ecdhe_ecdsa, Config), + ecdhe_ecdsa, ecdhe_ecdsa, + Config, DefaultCurve), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{honor_ecc_order, false}, {eccs, [secp256r1, sect571r1]}], + ECCOpts = [{honor_ecc_order, false}, {eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of - true -> ssl_test_lib:ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config); + true -> ssl_test_lib:ecc_test(DefaultCurve, COpts, SOpts, [], ECCOpts, Config); false -> {skip, "unsupported named curves"} end. @@ -274,12 +282,13 @@ ecc_unknown_curve(Config) -> client_ecdh_rsa_server_ecdhe_ecdsa_server_custom(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], ecdh_rsa, ecdhe_ecdsa, Config), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}], + ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config); false -> {skip, "unsupported named curves"} @@ -287,12 +296,13 @@ client_ecdh_rsa_server_ecdhe_ecdsa_server_custom(Config) -> client_ecdh_rsa_server_ecdhe_rsa_server_custom(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], ecdh_rsa, ecdhe_rsa, Config), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}], + ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config); @@ -301,12 +311,13 @@ client_ecdh_rsa_server_ecdhe_rsa_server_custom(Config) -> client_ecdhe_rsa_server_ecdhe_ecdsa_server_custom(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], ecdhe_rsa, ecdhe_ecdsa, Config), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}], + ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config); false -> {skip, "unsupported named curves"} @@ -314,19 +325,21 @@ client_ecdhe_rsa_server_ecdhe_ecdsa_server_custom(Config) -> client_ecdhe_rsa_server_ecdhe_rsa_server_custom(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], ecdhe_rsa, ecdhe_rsa, Config), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}], + ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config); false -> {skip, "unsupported named curves"} end. client_ecdhe_rsa_server_ecdh_rsa_server_custom(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, [[], [], [{extensions, Ext}]]}, {client_chain, Default}], @@ -334,8 +347,8 @@ client_ecdhe_rsa_server_ecdh_rsa_server_custom(Config) -> COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}], - Expected = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), %% The certificate curve + ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}], + Expected = secp256r1, %% The certificate curve case ssl_test_lib:supported_eccs(ECCOpts) of true -> ssl_test_lib:ecc_test(Expected, COpts, SOpts, [], ECCOpts, Config); @@ -344,12 +357,13 @@ client_ecdhe_rsa_server_ecdh_rsa_server_custom(Config) -> client_ecdhe_ecdsa_server_ecdhe_ecdsa_server_custom(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], ecdhe_ecdsa, ecdhe_ecdsa, Config), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}], + ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config); false -> {skip, "unsupported named curves"} @@ -357,12 +371,13 @@ client_ecdhe_ecdsa_server_ecdhe_ecdsa_server_custom(Config) -> client_ecdhe_ecdsa_server_ecdhe_rsa_server_custom(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], ecdhe_ecdsa, ecdhe_rsa, Config), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}], + ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config); false -> {skip, "unsupported named curves"} @@ -370,12 +385,13 @@ client_ecdhe_ecdsa_server_ecdhe_rsa_server_custom(Config) -> client_ecdhe_ecdsa_server_ecdhe_ecdsa_client_custom(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], ecdhe_ecdsa, ecdhe_ecdsa, Config), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{eccs, [secp256r1, sect571r1]}], + ECCOpts = [{eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config); false -> {skip, "unsupported named curves"} @@ -383,12 +399,13 @@ client_ecdhe_ecdsa_server_ecdhe_ecdsa_client_custom(Config) -> client_ecdhe_rsa_server_ecdhe_ecdsa_client_custom(Config) -> Default = ssl_test_lib:default_cert_chain_conf(), + DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default}, {client_chain, Default}], ecdhe_rsa, ecdhe_ecdsa, Config), COpts = ssl_test_lib:ssl_options(COpts0, Config), SOpts = ssl_test_lib:ssl_options(SOpts0, Config), - ECCOpts = [{eccs, [secp256r1, sect571r1]}], + ECCOpts = [{eccs, [secp256r1, DefaultCurve]}], case ssl_test_lib:supported_eccs(ECCOpts) of true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config); false -> {skip, "unsupported named curves"} diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl index 04c4b257d9..dfc780479e 100644 --- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl @@ -153,41 +153,41 @@ protocols_must_be_a_binary_list(Config) when is_list(Config) -> empty_client(Config) when is_list(Config) -> run_failing_handshake(Config, - [{alpn_advertised_protocols, []}], - [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}], - {error,{tls_alert,"no application protocol"}}). + [{alpn_advertised_protocols, []}], + [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}], + no_application_protocol). %-------------------------------------------------------------------------------- empty_server(Config) when is_list(Config) -> run_failing_handshake(Config, - [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], - [{alpn_preferred_protocols, []}], - {error,{tls_alert,"no application protocol"}}). + [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], + [{alpn_preferred_protocols, []}], + no_application_protocol). %-------------------------------------------------------------------------------- empty_client_empty_server(Config) when is_list(Config) -> run_failing_handshake(Config, - [{alpn_advertised_protocols, []}], - [{alpn_preferred_protocols, []}], - {error,{tls_alert,"no application protocol"}}). + [{alpn_advertised_protocols, []}], + [{alpn_preferred_protocols, []}], + no_application_protocol). %-------------------------------------------------------------------------------- no_matching_protocol(Config) when is_list(Config) -> run_failing_handshake(Config, - [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], - [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}], - {error,{tls_alert,"no application protocol"}}). + [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], + [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}], + no_application_protocol). %-------------------------------------------------------------------------------- client_alpn_and_server_alpn(Config) when is_list(Config) -> run_handshake(Config, - [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], - [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). + [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}], + [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). %-------------------------------------------------------------------------------- @@ -262,52 +262,12 @@ client_renegotiate(Config) when is_list(Config) -> %-------------------------------------------------------------------------------- session_reused(Config) when is_list(Config)-> - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), ClientOpts = [{alpn_advertised_protocols, [<<"http/1.0">>]}] ++ ClientOpts0, ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, ServerOpts}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result_msg, []}}, - {options, ClientOpts}]), - - SessionInfo = - receive - {Server, Info} -> - Info - end, - - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - - %% Make sure session is registered - ct:sleep(?SLEEP), - - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - - receive - {Client1, SessionInfo} -> - ok; - {Client1, Other} -> - ct:fail(Other) - end, - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client), - ssl_test_lib:close(Client1). - + ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). %-------------------------------------------------------------------------------- alpn_not_supported_client(Config) when is_list(Config) -> @@ -337,7 +297,7 @@ alpn_not_supported_server(Config) when is_list(Config)-> %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- -run_failing_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedResult) -> +run_failing_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedAlert) -> ClientOpts = ClientExtraOpts ++ ssl_test_lib:ssl_options(client_rsa_opts, Config), ServerOpts = ServerExtraOpts ++ ssl_test_lib:ssl_options(server_rsa_opts, Config), @@ -353,8 +313,7 @@ run_failing_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedResult) {from, self()}, {mfa, {?MODULE, placeholder, []}}, {options, ClientOpts}]), - ssl_test_lib:check_result(Server, ExpectedResult, - Client, ExpectedResult). + ssl_test_lib:check_client_alert(Server, Client, ExpectedAlert). run_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> Data = "hello world", diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 9633800da5..3b65291002 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -654,8 +654,8 @@ new_options_in_accept(Config) when is_list(Config) -> handshake_continue() -> [{doc, "Test API function ssl:handshake_continue/3"}]. handshake_continue(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, @@ -702,19 +702,12 @@ hello_client_cancel(Config) when is_list(Config) -> {from, self()}, {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)}, {continue_options, cancel}]), - receive - {Server, {error, {tls_alert, "user canceled"}}} -> - ok; - {Server, {error, closed}} -> - ct:pal("Did not receive the ALERT"), - ok - end. - + ssl_test_lib:check_server_alert(Server, user_canceled). %%-------------------------------------------------------------------- hello_server_cancel() -> [{doc, "Test API function ssl:handshake_cancel/1 on the server side"}]. hello_server_cancel(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, @@ -756,8 +749,8 @@ prf(Config) when is_list(Config) -> secret_connection_info() -> [{doc,"Test the API function ssl:connection_information/2"}]. secret_connection_info(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, @@ -838,42 +831,30 @@ controlling_process(Config) when is_list(Config) -> ClientMsg = "Server hello", ServerMsg = "Client hello", - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - controlling_process_result, [self(), - ServerMsg]}}, - {options, ServerOpts}]), + Server = ssl_test_lib:start_server([ + {node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + controlling_process_result, [self(), + ServerMsg]}}, + {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, + {Client, CSocket} = ssl_test_lib:start_client([return_socket, + {node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, {mfa, {?MODULE, controlling_process_result, [self(), ClientMsg]}}, {options, ClientOpts}]), - + ct:log("Testcase ~p, Client ~p Server ~p ~n", - [self(), Client, Server]), + [self(), Client, Server]), - receive - {ssl, _, "S"} -> - receive_s_rizzo_duong_beast(); - {ssl, _, ServerMsg} -> - receive - {ssl, _, ClientMsg} -> - ok - end; - {ssl, _, "C"} -> - receive_c_rizzo_duong_beast(); - {ssl, _, ClientMsg} -> - receive - {ssl, _, ServerMsg} -> - ok - end; - Unexpected -> - ct:fail(Unexpected) - end, + ServerMsg = ssl_test_lib:active_recv(CSocket, length(ServerMsg)), + %% We do not have the TLS server socket but all messages form the client + %% socket are now read, so ramining are form the server socket + ClientMsg = ssl_active_recv(length(ClientMsg)), ssl_test_lib:close(Server), ssl_test_lib:close(Client). @@ -1195,9 +1176,8 @@ fallback(Config) when is_list(Config) -> [{fallback, true}, {versions, ['tlsv1']} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, {error,{tls_alert,"inappropriate fallback"}}, - Client, {error,{tls_alert,"inappropriate fallback"}}). + ssl_test_lib:check_server_alert(Server, Client, inappropriate_fallback). + %%-------------------------------------------------------------------- cipher_format() -> @@ -1458,8 +1438,8 @@ cipher_suites_mix() -> cipher_suites_mix(Config) when is_list(Config) -> CipherSuites = [{dhe_rsa,aes_128_cbc,sha256,sha256}, {dhe_rsa,aes_128_cbc,sha}], - ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2118,15 +2098,21 @@ tls_downgrade(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, tls_downgrade_result, []}}, + {mfa, {?MODULE, tls_downgrade_result, [self()]}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, tls_downgrade_result, []}}, + {mfa, {?MODULE, tls_downgrade_result, [self()]}}, {options, [{active, false} |ClientOpts]}]), + + ssl_test_lib:check_result(Server, ready, Client, ready), + + Server ! go, + Client ! go, + ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). @@ -2364,8 +2350,8 @@ invalid_options() -> [{doc,"Test what happens when we give invalid options"}]. invalid_options(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Check = fun(Client, Server, {versions, [sslv2, sslv3]} = Option) -> @@ -2380,27 +2366,28 @@ invalid_options(Config) when is_list(Config) -> {error, {options, Option}}) end, - TestOpts = [{versions, [sslv2, sslv3]}, - {verify, 4}, - {verify_fun, function}, - {fail_if_no_peer_cert, 0}, - {verify_client_once, 1}, - {depth, four}, - {certfile, 'cert.pem'}, - {keyfile,'key.pem' }, - {password, foo}, - {cacertfile, ""}, - {dhfile,'dh.pem' }, - {ciphers, [{foo, bar, sha, ignore}]}, - {reuse_session, foo}, - {reuse_sessions, 0}, - {renegotiate_at, "10"}, - {mode, depech}, - {packet, 8.0}, - {packet_size, "2"}, - {header, a}, - {active, trice}, - {key, 'key.pem' }], + TestOpts = + [{versions, [sslv2, sslv3]}, + {verify, 4}, + {verify_fun, function}, + {fail_if_no_peer_cert, 0}, + {verify_client_once, 1}, + {depth, four}, + {certfile, 'cert.pem'}, + {keyfile,'key.pem' }, + {password, foo}, + {cacertfile, ""}, + {dhfile,'dh.pem' }, + {ciphers, [{foo, bar, sha, ignore}]}, + {reuse_session, foo}, + {reuse_sessions, 0}, + {renegotiate_at, "10"}, + {mode, depech}, + {packet, 8.0}, + {packet_size, "2"}, + {header, a}, + {active, trice}, + {key, 'key.pem' }], [begin Server = @@ -2656,8 +2643,7 @@ default_reject_anonymous(Config) when is_list(Config) -> [{ciphers,[CipherSuite]} | ClientOpts]}]), - ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}}, - Client, {error, {tls_alert, "insufficient security"}}). + ssl_test_lib:check_server_alert(Server, Client, insufficient_security). %%-------------------------------------------------------------------- ciphers_ecdsa_signed_certs() -> @@ -2693,175 +2679,69 @@ ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) -> reuse_session() -> [{doc,"Test reuse of sessions (short handshake)"}]. reuse_session(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), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, - - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - - %% Make sure session is registered - ct:sleep(?SLEEP), - - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - receive - {Client1, SessionInfo} -> - ok; - {Client1, Other} -> - ct:log("Expected: ~p, Unexpected: ~p~n", - [SessionInfo, Other]), - ct:fail(session_not_reused) - end, - - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - - Client2 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, [{reuse_sessions, false} - | ClientOpts]}]), - receive - {Client2, SessionInfo} -> - ct:fail( - session_reused_when_session_reuse_disabled_by_client); - {Client2, _} -> - ok - end, - - ssl_test_lib:close(Server), - - Server1 = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, [{reuse_sessions, false} | ServerOpts]}]), - - Port1 = ssl_test_lib:inet_port(Server1), - Client3 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port1}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - - SessionInfo1 = - receive - {Server1, Info1} -> - Info1 - end, - - Server1 ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - %% Make sure session is registered - ct:sleep(?SLEEP), - - Client4 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port1}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - - receive - {Client4, SessionInfo1} -> - ct:fail( - session_reused_when_session_reuse_disabled_by_server); - {Client4, _Other} -> - ct:log("OTHER: ~p ~n", [_Other]), - ok - end, - - ssl_test_lib:close(Server1), - ssl_test_lib:close(Client0), - ssl_test_lib:close(Client1), - ssl_test_lib:close(Client2), - ssl_test_lib:close(Client3), - ssl_test_lib:close(Client4). - + ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). %%-------------------------------------------------------------------- reuse_session_expired() -> [{doc,"Test sessions is not reused when it has expired"}]. reuse_session_expired(Config) when is_list(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = - ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + + Server0 = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client0 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, - - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, + {mfa, {ssl_test_lib, no_result, []}}, + {tcp_options, [{active, false}]}, + {options, ServerOpts}]), + Port0 = ssl_test_lib:inet_port(Server0), - %% Make sure session is registered - ct:sleep(?SLEEP), - - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), + Client0 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port0}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]), + Server0 ! listen, + + Client1 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port0}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, ClientOpts}]), + + SID = receive + {Client0, Id0} -> + Id0 + end, + receive - {Client1, SessionInfo} -> - ok; - {Client1, Other} -> - ct:log("Expected: ~p, Unexpected: ~p~n", - [SessionInfo, Other]), - ct:fail(session_not_reused) + {Client1, SID} -> + ok + after ?SLEEP -> + ct:fail(session_not_reused) end, - Server ! listen, - + Server0 ! listen, + %% Make sure session is unregistered due to expiration - ct:sleep((?EXPIRE+1)), - [{session_id, Id} |_] = SessionInfo, + ct:sleep((?EXPIRE*2)), - make_sure_expired(Hostname, Port, Id), + make_sure_expired(Hostname, Port0, SID), Client2 = ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, + {port, Port0}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, {from, self()}, {options, ClientOpts}]), receive - {Client2, SessionInfo} -> + {Client2, SID} -> ct:fail(session_reused_when_session_expired); {Client2, _} -> ok end, process_flag(trap_exit, false), - ssl_test_lib:close(Server), + ssl_test_lib:close(Server0), ssl_test_lib:close(Client0), ssl_test_lib:close(Client1), ssl_test_lib:close(Client2). @@ -2870,16 +2750,16 @@ make_sure_expired(Host, Port, Id) -> {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), [_, _,_, _, Prop] = StatusInfo, State = ssl_test_lib:state(Prop), - Cache = element(2, State), + ClientCache = element(2, State), - case ssl_session_cache:lookup(Cache, {{Host, Port}, Id}) of + case ssl_session_cache:lookup(ClientCache, {{Host, Port}, Id}) of undefined -> - ok; + ok; #session{is_resumable = false} -> - ok; + ok; _ -> ct:sleep(?SLEEP), - make_sure_expired(Host, Port, Id) + make_sure_expired(Host, Port, Id) end. %%-------------------------------------------------------------------- @@ -3615,8 +3495,7 @@ no_common_signature_algs(Config) when is_list(Config) -> {options, [{signature_algs, [{sha384, rsa}]} | ClientOpts]}]), - ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}}, - Client, {error, {tls_alert, "insufficient security"}}). + ssl_test_lib:check_server_alert(Server, Client, insufficient_security). %%-------------------------------------------------------------------- @@ -3980,8 +3859,8 @@ tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) -> {status, _, _, StatusInfo} = sys:get_status(Pid), [_, _,_, _, Prop] = StatusInfo, State = ssl_test_lib:state(Prop), - Socket = element(11, State), - + StaticEnv = element(2, State), + Socket = element(10, StaticEnv), %% Fake tcp error Pid ! {tcp_error, Socket, etimedout}, @@ -4131,6 +4010,8 @@ rizzo(Config) when is_list(Config) -> {cipher, fun(rc4_128) -> false; + (chacha20_poly1305) -> + false; (_) -> true end}]), @@ -4173,6 +4054,9 @@ rizzo_one_n_minus_one(Config) when is_list(Config) -> {cipher, fun(rc4_128) -> false; + %% TODO: remove this clause when chacha is fixed! + (chacha20_poly1305) -> + false; (_) -> true end}]), @@ -4314,8 +4198,7 @@ tls_versions_option(Config) when is_list(Config) -> {Server, _} -> ok end, - - ssl_test_lib:check_result(ErrClient, {error, {tls_alert, "protocol version"}}). + ssl_test_lib:check_client_alert(ErrClient, protocol_version). %%-------------------------------------------------------------------- @@ -4490,8 +4373,8 @@ tcp_send_recv_result(Socket) -> ok. basic_verify_test_no_close(Config) -> - ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -4634,19 +4517,24 @@ recv_close(Socket) -> send_recv_result_active_rizzo(Socket) -> ssl:send(Socket, "Hello world"), - receive - {ssl, Socket, "H"} -> - receive - {ssl, Socket, "ello world"} -> - ok - end - end. + "Hello world" = ssl_test_lib:active_recv(Socket, 11), + ok. send_recv_result_active_no_rizzo(Socket) -> ssl:send(Socket, "Hello world"), + "Hello world" = ssl_test_lib:active_recv(Socket, 11), + ok. + + +ssl_active_recv(N) -> + ssl_active_recv(N, []). + +ssl_active_recv(0, Acc) -> + Acc; +ssl_active_recv(N, Acc) -> receive - {ssl, Socket, "Hello world"} -> - ok + {ssl, _, Bytes} -> + ssl_active_recv(N-length(Bytes), Acc ++ Bytes) end. result_ok(_Socket) -> @@ -4670,16 +4558,7 @@ renegotiate_reuse_session(Socket, Data) -> renegotiate(Socket, Data). renegotiate_immediately(Socket) -> - receive - {ssl, Socket, "Hello world"} -> - ok; - %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast - {ssl, Socket, "H"} -> - receive - {ssl, Socket, "ello world"} -> - ok - end - end, + _ = ssl_test_lib:active_recv(Socket, 11), ok = ssl:renegotiate(Socket), {error, renegotiation_rejected} = ssl:renegotiate(Socket), ct:sleep(?RENEGOTIATION_DISABLE_TIME + ?SLEEP), @@ -4689,17 +4568,7 @@ renegotiate_immediately(Socket) -> ok. renegotiate_rejected(Socket) -> - receive - {ssl, Socket, "Hello world"} -> - ok; - %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast - {ssl, Socket, "H"} -> - - receive - {ssl, Socket, "ello world"} -> - ok - end - end, + _ = ssl_test_lib:active_recv(Socket, 11), {error, renegotiation_rejected} = ssl:renegotiate(Socket), {error, renegotiation_rejected} = ssl:renegotiate(Socket), ct:sleep(?RENEGOTIATION_DISABLE_TIME +1), @@ -4874,17 +4743,11 @@ session_loop(Sess) -> erlang_ssl_receive(Socket, Data) -> - receive - {ssl, Socket, Data} -> - io:format("Received ~p~n",[Data]), - ok; - {ssl, Socket, Byte} when length(Byte) == 1 -> %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast - io:format("Received ~p~n",[Byte]), - erlang_ssl_receive(Socket, tl(Data)); - Other -> - ct:fail({unexpected_message, Other}) - after timer:seconds(?SEC_RENEGOTIATION_TIMEOUT) * test_server:timetrap_scale_factor() -> - ct:fail({did_not_get, Data}) + case ssl_test_lib:active_recv(Socket, length(Data)) of + Data -> + ok; + Other -> + ct:fail({{expected, Data}, {got, Other}}) end. receive_msg(_) -> @@ -4901,28 +4764,6 @@ controlling_process_result(Socket, Pid, Msg) -> ssl:send(Socket, Msg), no_result_msg. -receive_s_rizzo_duong_beast() -> - receive - {ssl, _, "erver hello"} -> - receive - {ssl, _, "C"} -> - receive - {ssl, _, "lient hello"} -> - ok - end - end - end. -receive_c_rizzo_duong_beast() -> - receive - {ssl, _, "lient hello"} -> - receive - {ssl, _, "S"} -> - receive - {ssl, _, "erver hello"} -> - ok - end - end - end. controller_dies_result(_Socket, _Pid, _Msg) -> receive Result -> Result end. @@ -5008,16 +4849,16 @@ run_suites(Ciphers, Config, Type) -> {ClientOpts, ServerOpts} = case Type of rsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), [{ciphers, Ciphers} | - ssl_test_lib:ssl_options(server_verification_opts, Config)]}; + ssl_test_lib:ssl_options(server_rsa_opts, Config)]}; dsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_dsa_verify_opts, Config), [{ciphers, Ciphers} | ssl_test_lib:ssl_options(server_dsa_opts, Config)]}; anonymous -> %% No certs in opts! - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), [{ciphers, Ciphers} | ssl_test_lib:ssl_options([], Config)]}; psk -> @@ -5039,46 +4880,50 @@ run_suites(Ciphers, Config, Type) -> ssl_test_lib:ssl_options(server_psk_anon_hint, Config)]}; srp -> {ssl_test_lib:ssl_options(client_srp, Config), - ssl_test_lib:ssl_options(server_srp, Config)}; + [{ciphers, Ciphers} | + ssl_test_lib:ssl_options(server_srp, Config)]}; srp_anon -> {ssl_test_lib:ssl_options(client_srp, Config), - ssl_test_lib:ssl_options(server_srp_anon, Config)}; + [{ciphers, Ciphers} | + ssl_test_lib:ssl_options(server_srp_anon, Config)]}; srp_dsa -> {ssl_test_lib:ssl_options(client_srp_dsa, Config), - ssl_test_lib:ssl_options(server_srp_dsa, Config)}; + [{ciphers, Ciphers} | + ssl_test_lib:ssl_options(server_srp_dsa, Config)]}; ecdsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_ecdsa_opts, Config), [{ciphers, Ciphers} | ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]}; ecdh_rsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), - ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)}; + {ssl_test_lib:ssl_options(client_ecdh_rsa_opts, Config), + [{ciphers, Ciphers} | + ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]}; rc4_rsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), [{ciphers, Ciphers} | - ssl_test_lib:ssl_options(server_verification_opts, Config)]}; + ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]}; rc4_ecdh_rsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_ecdh_rsa_opts, Config), [{ciphers, Ciphers} | ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]}; rc4_ecdsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), [{ciphers, Ciphers} | ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]}; des_dhe_rsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), [{ciphers, Ciphers} | ssl_test_lib:ssl_options(server_verification_opts, Config)]}; des_rsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), [{ciphers, Ciphers} | - ssl_test_lib:ssl_options(server_verification_opts, Config)]}; + ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]}; chacha_rsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), [{ciphers, Ciphers} | - ssl_test_lib:ssl_options(server_verification_opts, Config)]}; + ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]}; chacha_ecdsa -> - {ssl_test_lib:ssl_options(client_verification_opts, Config), + {ssl_test_lib:ssl_options(client_ecdsa_opts, Config), [{ciphers, Ciphers} | ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]} end, @@ -5176,23 +5021,28 @@ connect_dist_c(S) -> {ok, Test} = ssl:recv(S, 0, 10000), ok. -tls_downgrade_result(Socket) -> +tls_downgrade_result(Socket, Pid) -> ok = ssl_test_lib:send_recv_result(Socket), + Pid ! {self(), ready}, + receive + go -> + ok + end, case ssl:close(Socket, {self(), 10000}) of {ok, TCPSocket} -> - inet:setopts(TCPSocket, [{active, true}]), + inet:setopts(TCPSocket, [{active, true}]), gen_tcp:send(TCPSocket, "Downgraded"), - receive - {tcp, TCPSocket, <<"Downgraded">>} -> - ok; - {tcp_closed, TCPSocket} -> - ct:pal("Peer timed out, downgrade aborted"), - ok; - Other -> - {error, Other} - end; + receive + {tcp, TCPSocket, <<"Downgraded">>} -> + ok; + {tcp_closed, TCPSocket} -> + ct:fail("Peer timed out, downgrade aborted"), + ok; + Other -> + {error, Other} + end; {error, timeout} -> - ct:pal("Timed out, downgrade aborted"), + ct:fail("Timed out, downgrade aborted"), ok; Fail -> {error, Fail} diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl index 588ca153a9..c0a5367a57 100644 --- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -298,15 +298,8 @@ server_require_peer_cert_fail(Config) when is_list(Config) -> {host, Hostname}, {from, self()}, {options, [{active, Active} | BadClientOpts]}]), - receive - {Server, {error, {tls_alert, "handshake failure"}}} -> - receive - {Client, {error, {tls_alert, "handshake failure"}}} -> - ok; - {Client, {error, closed}} -> - ok - end - end. + + ssl_test_lib:check_server_alert(Server, Client, handshake_failure). %%-------------------------------------------------------------------- server_require_peer_cert_empty_ok() -> @@ -365,15 +358,8 @@ server_require_peer_cert_partial_chain(Config) when is_list(Config) -> {options, [{active, Active}, {cacerts, [RootCA]} | proplists:delete(cacertfile, ClientOpts)]}]), - receive - {Server, {error, {tls_alert, "unknown ca"}}} -> - receive - {Client, {error, {tls_alert, "unknown ca"}}} -> - ok; - {Client, {error, closed}} -> - ok - end - end. + ssl_test_lib:check_server_alert(Server, Client, unknown_ca). + %%-------------------------------------------------------------------- server_require_peer_cert_allow_partial_chain() -> [{doc, "Server trusts intermediat CA and accepts a partial chain. (partial_chain option)"}]. @@ -446,17 +432,7 @@ server_require_peer_cert_do_not_allow_partial_chain(Config) when is_list(Config) {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - - receive - {Server, {error, {tls_alert, "unknown ca"}}} -> - receive - {Client, {error, {tls_alert, "unknown ca"}}} -> - ok; - {Client, {error, closed}} -> - ok - end - end. - + ssl_test_lib:check_server_alert(Server, Client, unknown_ca). %%-------------------------------------------------------------------- server_require_peer_cert_partial_chain_fun_fail() -> [{doc, "If parial_chain fun crashes, treat it as if it returned unkown_ca"}]. @@ -487,16 +463,7 @@ server_require_peer_cert_partial_chain_fun_fail(Config) when is_list(Config) -> {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - - receive - {Server, {error, {tls_alert, "unknown ca"}}} -> - receive - {Client, {error, {tls_alert, "unknown ca"}}} -> - ok; - {Client, {error, closed}} -> - ok - end - end. + ssl_test_lib:check_server_alert(Server, Client, unknown_ca). %%-------------------------------------------------------------------- verify_fun_always_run_client() -> @@ -535,14 +502,8 @@ verify_fun_always_run_client(Config) when is_list(Config) -> [{verify, verify_peer}, {verify_fun, FunAndState} | ClientOpts]}]), - %% Server error may be {tls_alert,"handshake failure"} or closed depending on timing - %% this is not a bug it is a circumstance of how tcp works! - receive - {Server, ServerError} -> - ct:log("Server Error ~p~n", [ServerError]) - end, - ssl_test_lib:check_result(Client, {error, {tls_alert, "handshake failure"}}). + ssl_test_lib:check_client_alert(Server, Client, handshake_failure). %%-------------------------------------------------------------------- verify_fun_always_run_server() -> @@ -581,16 +542,8 @@ verify_fun_always_run_server(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts}]), - - %% Client error may be {tls_alert, "handshake failure" } or closed depending on timing - %% this is not a bug it is a circumstance of how tcp works! - receive - {Client, ClientError} -> - ct:log("Client Error ~p~n", [ClientError]) - end, - - ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}). - + + ssl_test_lib:check_client_alert(Server, Client, handshake_failure). %%-------------------------------------------------------------------- cert_expired() -> @@ -620,8 +573,7 @@ cert_expired(Config) when is_list(Config) -> {from, self()}, {options, [{verify, verify_peer}, {active, Active} | ClientOpts]}]), - ssl_test_lib:check_result(Server, {error, {tls_alert, "certificate expired"}}, - Client, {error, {tls_alert, "certificate expired"}}). + ssl_test_lib:check_client_alert(Server, Client, certificate_expired). two_digits_str(N) when N < 10 -> lists:flatten(io_lib:format("0~p", [N])); @@ -727,12 +679,8 @@ critical_extension_verify_server(Config) when is_list(Config) -> {options, [{verify, verify_none}, {active, Active} | ClientOpts]}]), %% This certificate has a critical extension that we don't - %% understand. Therefore, verification should fail. - - ssl_test_lib:check_result(Server, {error, {tls_alert, "unsupported certificate"}}, - Client, {error, {tls_alert, "unsupported certificate"}}), - - ssl_test_lib:close(Server). + %% understand. Therefore, verification should fail. + ssl_test_lib:check_server_alert(Server, Client, unsupported_certificate). %%-------------------------------------------------------------------- critical_extension_verify_client() -> @@ -763,12 +711,7 @@ critical_extension_verify_client(Config) when is_list(Config) -> {mfa, {ssl_test_lib, ReceiveFunction, []}}, {options, [{verify, verify_peer}, {active, Active} | ClientOpts]}]), - %% This certificate has a critical extension that we don't - %% understand. Therefore, verification should fail. - ssl_test_lib:check_result(Server, {error, {tls_alert, "unsupported certificate"}}, - Client, {error, {tls_alert, "unsupported certificate"}}), - - ssl_test_lib:close(Server). + ssl_test_lib:check_client_alert(Server, Client, unsupported_certificate). %%-------------------------------------------------------------------- critical_extension_verify_none() -> @@ -908,10 +851,7 @@ invalid_signature_server(Config) when is_list(Config) -> {host, Hostname}, {from, self()}, {options, [{verify, verify_peer} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, {error, {tls_alert, "unknown ca"}}, - Client, {error, {tls_alert, "unknown ca"}}). - + ssl_test_lib:check_server_alert(Server, Client, unknown_ca). %%-------------------------------------------------------------------- invalid_signature_client() -> @@ -946,9 +886,7 @@ invalid_signature_client(Config) when is_list(Config) -> {from, self()}, {options, NewClientOpts}]), - ssl_test_lib:check_result(Server, {error, {tls_alert, "unknown ca"}}, - Client, {error, {tls_alert, "unknown ca"}}). - + ssl_test_lib:check_client_alert(Server, Client, unknown_ca). %%-------------------------------------------------------------------- @@ -1034,16 +972,7 @@ unknown_server_ca_fail(Config) when is_list(Config) -> [{verify, verify_peer}, {verify_fun, FunAndState} | ClientOpts]}]), - receive - {Client, {error, {tls_alert, "unknown ca"}}} -> - receive - {Server, {error, {tls_alert, "unknown ca"}}} -> - ok; - {Server, {error, closed}} -> - ok - end - end. - + ssl_test_lib:check_client_alert(Server, Client, unknown_ca). %%-------------------------------------------------------------------- unknown_server_ca_accept_verify_none() -> @@ -1193,11 +1122,7 @@ customize_hostname_check(Config) when is_list(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {options, ClientOpts} ]), - ssl_test_lib:check_result(Client1, {error, {tls_alert, "handshake failure"}}, - Server, {error, {tls_alert, "handshake failure"}}), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + ssl_test_lib:check_client_alert(Server, Client1, handshake_failure). incomplete_chain() -> [{doc,"Test option verify_peer"}]. diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl index 23c5eaf84d..b2fd3874a8 100644 --- a/lib/ssl/test/ssl_crl_SUITE.erl +++ b/lib/ssl/test/ssl_crl_SUITE.erl @@ -238,7 +238,7 @@ crl_verify_revoked(Config) when is_list(Config) -> end, crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, - "certificate revoked"). + certificate_revoked). crl_verify_no_crl() -> [{doc,"Verify a simple CRL chain when the CRL is missing"}]. @@ -277,10 +277,10 @@ crl_verify_no_crl(Config) when is_list(Config) -> %% The error "revocation status undetermined" gets turned %% into "bad certificate". crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, - "bad certificate"); + bad_certificate); peer -> crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, - "bad certificate"); + bad_certificate); best_effort -> %% In "best effort" mode, we consider the certificate not %% to be revoked if we can't find the appropriate CRL. @@ -341,7 +341,7 @@ crl_hash_dir_collision(Config) when is_list(Config) -> %% First certificate revoked; first fails, second succeeds. crl_verify_error(Hostname, ServerNode, ServerOpts1, ClientNode, ClientOpts, - "certificate revoked"), + certificate_revoked), crl_verify_valid(Hostname, ServerNode, ServerOpts2, ClientNode, ClientOpts), make_certs:revoke(PrivDir, CA2, "collision-client-2", CertsConfig), @@ -352,9 +352,9 @@ crl_hash_dir_collision(Config) when is_list(Config) -> %% Second certificate revoked; both fail. crl_verify_error(Hostname, ServerNode, ServerOpts1, ClientNode, ClientOpts, - "certificate revoked"), + certificate_revoked), crl_verify_error(Hostname, ServerNode, ServerOpts2, ClientNode, ClientOpts, - "certificate revoked"), + certificate_revoked), ok. @@ -383,8 +383,11 @@ crl_hash_dir_expired(Config) when is_list(Config) -> {verify, verify_peer}], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - %% First make a CRL that expired yesterday. - make_certs:gencrl(PrivDir, CA, CertsConfig, -24), + %% First make a CRL that will expire in one second. + make_certs:gencrl_sec(PrivDir, CA, CertsConfig, 1), + %% Sleep until the next CRL is due + ct:sleep({seconds, 1}), + CrlDir = filename:join(PrivDir, "crls"), populate_crl_hash_dir(PrivDir, CrlDir, [{CA, "1627b4b0"}], @@ -397,10 +400,10 @@ crl_hash_dir_expired(Config) when is_list(Config) -> %% The error "revocation status undetermined" gets turned %% into "bad certificate". crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, - "bad certificate"); + bad_certificate); peer -> crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, - "bad certificate"); + bad_certificate); best_effort -> %% In "best effort" mode, we consider the certificate not %% to be revoked if we can't find the appropriate CRL. @@ -448,11 +451,8 @@ crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, Expec {host, Hostname}, {from, self()}, {options, ClientOpts}]), - receive - {Server, AlertOrClose} -> - ct:pal("Server Alert or Close ~p", [AlertOrClose]) - end, - ssl_test_lib:check_result(Client, {error, {tls_alert, ExpectedAlert}}). + + ssl_test_lib:check_client_alert(Server, Client, ExpectedAlert). %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl index b8b9989d30..1fa6029963 100644 --- a/lib/ssl/test/ssl_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_handshake_SUITE.erl @@ -25,6 +25,7 @@ -compile(export_all). -include_lib("common_test/include/ct.hrl"). +-include("ssl_handshake.hrl"). -include("ssl_internal.hrl"). -include("tls_handshake.hrl"). -include_lib("public_key/include/public_key.hrl"). @@ -41,7 +42,8 @@ all() -> [decode_hello_handshake, decode_empty_server_sni_correctly, select_proper_tls_1_2_rsa_default_hashsign, ignore_hassign_extension_pre_tls_1_2, - unorded_chain]. + unorded_chain, + encode_decode_srp]. %%-------------------------------------------------------------------- init_per_suite(Config) -> @@ -192,6 +194,31 @@ unorded_chain(Config) when is_list(Config) -> {ok, _, OrderedChain} = ssl_certificate:certificate_chain(PeerCert, ets:new(foo, []), ExtractedCerts, UnordedChain). +encode_decode_srp(_Config) -> + Exts = #hello_extensions{ + srp = #srp{username = <<"foo">>}, + sni = #sni{hostname = "bar"}, + renegotiation_info = undefined, + signature_algs = undefined, + alpn = undefined, + next_protocol_negotiation = undefined, + ec_point_formats = undefined, + elliptic_curves = undefined + }, + EncodedExts = <<0,20, % Length + 0,0, % SNI extension + 0,8, % Length + 0,6, % ServerNameLength + 0, % NameType (host_name) + 0,3, % HostNameLength + 98,97,114, % hostname = "bar" + 0,12, % SRP extension + 0,4, % Length + 3, % srp_I length + 102,111,111>>, % username = "foo" + EncodedExts = ssl_handshake:encode_hello_extensions(Exts), + Exts = ssl_handshake:decode_hello_extensions({client, EncodedExts}). + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl index 1c7d6b5f9f..878e983bb9 100644 --- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl @@ -64,13 +64,12 @@ next_protocol_not_supported() -> npn_not_supported_server ]. -init_per_suite(Config) -> +init_per_suite(Config0) -> catch crypto:stop(), try crypto:start() of ok -> ssl_test_lib:clean_start(), - {ok, _} = make_certs:all(proplists:get_value(data_dir, Config), - proplists:get_value(priv_dir, Config)), + Config = ssl_test_lib:make_rsa_cert(Config0), ssl_test_lib:cert_options(Config) catch _:_ -> {skip, "Crypto did not start"} @@ -196,10 +195,10 @@ client_negotiate_server_does_not_support(Config) when is_list(Config) -> renegotiate_from_client_after_npn_handshake(Config) when is_list(Config) -> Data = "hello world", - ClientOpts0 = ssl_test_lib:ssl_options(client_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), ClientOpts = [{client_preferred_next_protocols, {client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0, - ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), ServerOpts = [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, ExpectedProtocol = {ok, <<"http/1.0">>}, @@ -221,7 +220,7 @@ renegotiate_from_client_after_npn_handshake(Config) when is_list(Config) -> %-------------------------------------------------------------------------------- npn_not_supported_client(Config) when is_list(Config) -> - ClientOpts0 = ssl_test_lib:ssl_options(client_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), PrefProtocols = {client_preferred_next_protocols, {client, [<<"http/1.0">>], <<"http/1.1">>}}, ClientOpts = [PrefProtocols] ++ ClientOpts0, @@ -236,7 +235,7 @@ npn_not_supported_client(Config) when is_list(Config) -> %-------------------------------------------------------------------------------- npn_not_supported_server(Config) when is_list(Config)-> - ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), AdvProtocols = {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, ServerOpts = [AdvProtocols] ++ ServerOpts0, @@ -244,63 +243,24 @@ npn_not_supported_server(Config) when is_list(Config)-> %-------------------------------------------------------------------------------- npn_handshake_session_reused(Config) when is_list(Config)-> - ClientOpts0 = ssl_test_lib:ssl_options(client_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), ClientOpts = [{client_preferred_next_protocols, {client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0, - ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), ServerOpts =[{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0, - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {options, ServerOpts}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, no_result_msg, []}}, - {options, ClientOpts}]), - - SessionInfo = - receive - {Server, Info} -> - Info - end, - - Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, - - %% Make sure session is registered - ct:sleep(?SLEEP), - - Client1 = - ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, - {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), - - receive - {Client1, SessionInfo} -> - ok; - {Client1, Other} -> - ct:fail(Other) - end, + ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). - ssl_test_lib:close(Server), - ssl_test_lib:close(Client), - ssl_test_lib:close(Client1). - %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> Data = "hello world", - ClientOpts0 = ssl_test_lib:ssl_options(client_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), ClientOpts = ClientExtraOpts ++ ClientOpts0, - ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), ServerOpts = ServerExtraOpts ++ ServerOpts0, {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 9af1ae0e3f..6d26b2df33 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -2122,26 +2122,13 @@ active_once_packet(Socket, Data, N) -> active_once_packet(Socket, Data, N-1). active_raw(Socket, Data, N) -> - active_raw(Socket, Data, N, []). - -active_raw(_Socket, _, 0, _) -> + active_raw(Socket, (length(Data) * N)). +active_raw(_Socket, 0) -> ok; -active_raw(Socket, Data, N, Acc) -> +active_raw(Socket, N) -> receive - {ssl, Socket, Byte} when length(Byte) == 1 -> - receive - {ssl, Socket, _} -> - active_raw(Socket, Data, N -1) - end; - {ssl, Socket, Data} -> - active_raw(Socket, Data, N-1, []); - {ssl, Socket, Other} -> - case Acc ++ Other of - Data -> - active_raw(Socket, Data, N-1, []); - NewAcc -> - active_raw(Socket, Data, NewAcc) - end + {ssl, Socket, Bytes} -> + active_raw(Socket, N-length(Bytes)) end. active_packet(Socket, _, 0) -> diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl index 1f9b6a5772..27b9c258a0 100644 --- a/lib/ssl/test/ssl_payload_SUITE.erl +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -64,7 +64,8 @@ payload_tests() -> server_echos_active_huge, client_echos_passive_huge, client_echos_active_once_huge, - client_echos_active_huge]. + client_echos_active_huge, + client_active_once_server_close]. init_per_suite(Config) -> catch crypto:stop(), @@ -397,6 +398,23 @@ client_echos_active_huge(Config) when is_list(Config) -> client_echos_active( Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname). + +%%-------------------------------------------------------------------- +client_active_once_server_close() -> + [{doc, "Server sends 500000 bytes and immediately after closes the connection" + "Make sure client recives all data if possible"}]. + +client_active_once_server_close(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_active_once_server_close( + Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname). + + + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- @@ -541,42 +559,57 @@ client_echos_active( ssl_test_lib:close(Server), ssl_test_lib:close(Client). +client_active_once_server_close( + Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) -> + Length = byte_size(Data), + Server = + ssl_test_lib:start_server( + [{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_close, [Data]}}, + {options, [{active, once}, {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, {ssl_test_lib, active_once_recv, [Length]}}, + {options,[{active, once}, {mode, binary} | ClientOpts]}]), + %% + ssl_test_lib:check_result(Server, ok, Client, ok). + +send(_Socket, _Data, 0, _) -> + ok; +send(Socket, Data, Count, RecvEcho) -> + ok = ssl:send(Socket, Data), + RecvEcho(), + send(Socket, Data, Count - 1, RecvEcho). -send(Socket, Data, Count, Verify) -> - send(Socket, Data, Count, <<>>, Verify). -%% -send(_Socket, _Data, 0, Acc, _Verify) -> - Acc; -send(Socket, Data, Count, Acc, Verify) -> +send_close(Socket, Data) -> ok = ssl:send(Socket, Data), - NewAcc = Verify(Acc), - send(Socket, Data, Count - 1, NewAcc, Verify). + ssl:close(Socket). - sender(Socket, Data) -> ct:log("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]), - <<>> = - send( - Socket, Data, 100, - fun(Acc) -> verify_recv(Socket, Data, Acc) end), - ok. + send(Socket, Data, 100, + fun() -> + ssl_test_lib:recv_disregard(Socket, byte_size(Data)) + end). sender_active_once(Socket, Data) -> ct:log("Sender active once: ~p~n", [ssl:getopts(Socket, [active])]), - <<>> = - send( - Socket, Data, 100, - fun(Acc) -> verify_active_once(Socket, Data, Acc) end), - ok. + send(Socket, Data, 100, + fun() -> + ssl_test_lib:active_once_disregard(Socket, byte_size(Data)) + end). sender_active(Socket, Data) -> ct:log("Sender active: ~p~n", [ssl:getopts(Socket, [active])]), - <<>> = - send( - Socket, Data, 100, - fun(Acc) -> verify_active(Socket, Data, Acc) end), - ok. - + send(Socket, Data, 100, + fun() -> + ssl_test_lib:active_disregard(Socket, byte_size(Data)) + end). echoer(Socket, Size) -> ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]), @@ -592,99 +625,32 @@ echoer_active(Socket, Size) -> %% Receive Size bytes +echo_recv(_Socket, 0) -> + ok; echo_recv(Socket, Size) -> {ok, Data} = ssl:recv(Socket, 0), ok = ssl:send(Socket, Data), - NewSize = Size - byte_size(Data), - if - 0 < NewSize -> - echo_recv(Socket, NewSize); - 0 == NewSize -> - ok - end. - -%% Verify that received data is SentData, return any superflous data -verify_recv(Socket, SentData, Acc) -> - {ok, NewData} = ssl:recv(Socket, 0), - SentSize = byte_size(SentData), - NewAcc = <<Acc/binary, NewData/binary>>, - NewSize = byte_size(NewAcc), - if - SentSize < NewSize -> - {SentData,Rest} = split_binary(NewAcc, SentSize), - Rest; - NewSize < SentSize -> - verify_recv(Socket, SentData, NewAcc); - true -> - SentData = NewAcc, - <<>> - end. + echo_recv(Socket, Size - byte_size(Data)). %% Receive Size bytes +echo_active_once(_Socket, 0) -> + ok; echo_active_once(Socket, Size) -> receive {ssl, Socket, Data} -> ok = ssl:send(Socket, Data), NewSize = Size - byte_size(Data), ssl:setopts(Socket, [{active, once}]), - if - 0 < NewSize -> - echo_active_once(Socket, NewSize); - 0 == NewSize -> - ok - end + echo_active_once(Socket, NewSize) end. -%% Verify that received data is SentData, return any superflous data -verify_active_once(Socket, SentData, Acc) -> - receive - {ssl, Socket, Data} -> - SentSize = byte_size(SentData), - NewAcc = <<Acc/binary, Data/binary>>, - NewSize = byte_size(NewAcc), - ssl:setopts(Socket, [{active, once}]), - if - SentSize < NewSize -> - {SentData,Rest} = split_binary(NewAcc, SentSize), - Rest; - NewSize < SentSize -> - verify_active_once(Socket, SentData, NewAcc); - true -> - SentData = NewAcc, - <<>> - end - end. - - %% Receive Size bytes +echo_active(_Socket, 0) -> + ok; echo_active(Socket, Size) -> receive {ssl, Socket, Data} -> ok = ssl:send(Socket, Data), - NewSize = Size - byte_size(Data), - if - 0 < NewSize -> - echo_active(Socket, NewSize); - 0 == NewSize -> - ok - end - end. - -%% Verify that received data is SentData, return any superflous data -verify_active(Socket, SentData, Acc) -> - receive - {ssl, Socket, Data} -> - SentSize = byte_size(SentData), - NewAcc = <<Acc/binary, Data/binary>>, - NewSize = byte_size(NewAcc), - if - SentSize < NewSize -> - {SentData,Rest} = split_binary(NewAcc, SentSize), - Rest; - NewSize < SentSize -> - verify_active(Socket, SentData, NewAcc); - true -> - SentData = NewAcc, - <<>> - end - end. + echo_active(Socket, Size - byte_size(Data)) + end. + diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl index 25d2cb300d..6f11e2bbe8 100644 --- a/lib/ssl/test/ssl_pem_cache_SUITE.erl +++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl @@ -44,11 +44,8 @@ init_per_suite(Config0) -> try crypto:start() of ok -> ssl_test_lib:clean_start(), - %% make rsa certs using oppenssl - {ok, _} = make_certs:all(proplists:get_value(data_dir, Config0), - proplists:get_value(priv_dir, Config0)), - Config1 = ssl_test_lib:make_dsa_cert(Config0), - ssl_test_lib:cert_options(Config1) + %% make rsa certs + ssl_test_lib:make_rsa_cert(Config0) catch _:_ -> {skip, "Crypto did not start"} end. @@ -86,8 +83,8 @@ pem_cleanup() -> [{doc, "Test pem cache invalidate mechanism"}]. pem_cleanup(Config)when is_list(Config) -> process_flag(trap_exit, true), - ClientOpts = proplists:get_value(client_verification_opts, Config), - ServerOpts = proplists:get_value(server_verification_opts, Config), + ClientOpts = proplists:get_value(client_rsa_verify_opts, Config), + ServerOpts = proplists:get_value(server_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = @@ -118,8 +115,8 @@ invalid_insert() -> invalid_insert(Config)when is_list(Config) -> process_flag(trap_exit, true), - ClientOpts = proplists:get_value(client_verification_opts, Config), - ServerOpts = proplists:get_value(server_verification_opts, Config), + ClientOpts = proplists:get_value(client_rsa_verify_opts, Config), + ServerOpts = proplists:get_value(server_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), BadClientOpts = [{cacertfile, "tmp/does_not_exist.pem"} | proplists:delete(cacertfile, ClientOpts)], Server = diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index a0fab58b9d..7f33fe3204 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -48,7 +48,8 @@ all() -> session_cache_process_list, session_cache_process_mnesia, client_unique_session, - max_table_size + max_table_size, + save_specific_session ]. groups() -> @@ -60,10 +61,7 @@ init_per_suite(Config0) -> ok -> ssl_test_lib:clean_start(), %% make rsa certs using - {ok, _} = make_certs:all(proplists:get_value(data_dir, Config0), - proplists:get_value(priv_dir, Config0)), - Config = ssl_test_lib:make_dsa_cert(Config0), - ssl_test_lib:cert_options(Config) + ssl_test_lib:make_rsa_cert(Config0) catch _:_ -> {skip, "Crypto did not start"} end. @@ -97,7 +95,10 @@ init_per_testcase(session_cleanup, Config) -> init_per_testcase(client_unique_session, Config) -> ct:timetrap({seconds, 40}), Config; - +init_per_testcase(save_specific_session, Config) -> + ssl_test_lib:clean_start(), + ct:timetrap({seconds, 5}), + Config; init_per_testcase(max_table_size, Config) -> ssl:stop(), application:load(ssl), @@ -141,7 +142,7 @@ end_per_testcase(max_table_size, Config) -> end_per_testcase(default_action, Config); end_per_testcase(Case, Config) when Case == session_cache_process_list; Case == session_cache_process_mnesia -> - ets:delete(ssl_test), + catch ets:delete(ssl_test), Config; end_per_testcase(_, Config) -> Config. @@ -154,8 +155,8 @@ client_unique_session() -> "sets up many connections"}]. client_unique_session(Config) when is_list(Config) -> process_flag(trap_exit, true), - ClientOpts = proplists:get_value(client_opts, Config), - ServerOpts = proplists:get_value(server_opts, Config), + ClientOpts = proplists:get_value(client_rsa_verify_opts, Config), + ServerOpts = proplists:get_value(server_rsa_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, @@ -164,8 +165,7 @@ client_unique_session(Config) when is_list(Config) -> {tcp_options, [{active, false}]}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - LastClient = clients_start(Server, - ClientNode, Hostname, Port, ClientOpts, client_unique_session, 20), + LastClient = clients_start(Server, ClientNode, Hostname, Port, ClientOpts, 20), receive {LastClient, {ok, _}} -> ok @@ -185,8 +185,8 @@ session_cleanup() -> "does not grow and grow ..."}]. session_cleanup(Config) when is_list(Config) -> process_flag(trap_exit, true), - ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), - ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = @@ -254,13 +254,75 @@ session_cache_process_mnesia(Config) when is_list(Config) -> session_cache_process(mnesia,Config). %%-------------------------------------------------------------------- +save_specific_session() -> + [{doc, "Test that we can save a specific client session" + }]. +save_specific_session(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ClientOpts = proplists:get_value(client_rsa_verify_opts, Config), + ServerOpts = proplists:get_value(server_rsa_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {tcp_options, [{active, false}]}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client1 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, ClientOpts}]), + Server ! listen, + + Client2 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]), + SessionID1 = + receive + {Client1, S1} -> + S1 + end, + + SessionID2 = + receive + {Client2, S2} -> + S2 + end, + + true = SessionID1 =/= SessionID2, + + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + ClientCache = element(2, State), + 2 = ssl_session_cache:size(ClientCache), + + Server ! listen, + + Client3 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, [{reuse_session, SessionID2} | ClientOpts]}]), + receive + {Client3, SessionID2} -> + ok; + {Client3, SessionID3}-> + ct:fail({got, SessionID3, expected, SessionID2}); + Other -> + ct:fail({got,Other}) + end. + +%%-------------------------------------------------------------------- max_table_size() -> [{doc,"Test max limit on session table"}]. max_table_size(Config) when is_list(Config) -> process_flag(trap_exit, true), - ClientOpts = proplists:get_value(client_verification_opts, Config), - ServerOpts = proplists:get_value(server_verification_opts, Config), + ClientOpts = proplists:get_value(client_rsa_verify_opts, Config), + ServerOpts = proplists:get_value(server_rsa_verify_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, @@ -270,7 +332,7 @@ max_table_size(Config) when is_list(Config) -> {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), LastClient = clients_start(Server, - ClientNode, Hostname, Port, ClientOpts, max_table_size, 20), + ClientNode, Hostname, Port, ClientOpts, 20), receive {LastClient, {ok, _}} -> ok @@ -426,25 +488,27 @@ session_loop(Sess) -> %%-------------------------------------------------------------------- session_cache_process(_Type,Config) when is_list(Config) -> - ssl_basic_SUITE:reuse_session(Config). + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config). -clients_start(_Server, ClientNode, Hostname, Port, ClientOpts, Test, 0) -> +clients_start(_Server, ClientNode, Hostname, Port, ClientOpts, 0) -> %% Make sure session is registered ct:sleep(?SLEEP * 2), ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {mfa, {?MODULE, connection_info_result, []}}, - {from, self()}, {options, test_copts(Test, 0, ClientOpts)}]); -clients_start(Server, ClientNode, Hostname, Port, ClientOpts, Test, N) -> + {from, self()}, {options, ClientOpts}]); +clients_start(Server, ClientNode, Hostname, Port, ClientOpts, N) -> spawn_link(ssl_test_lib, start_client, [[{node, ClientNode}, {port, Port}, {host, Hostname}, {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, test_copts(Test, N, ClientOpts)}]]), + {from, self()}, {options, ClientOpts}]]), Server ! listen, wait_for_server(), - clients_start(Server, ClientNode, Hostname, Port, ClientOpts, Test, N-1). + clients_start(Server, ClientNode, Hostname, Port, ClientOpts, N-1). connection_info_result(Socket) -> ssl:connection_information(Socket, [protocol, cipher_suite]). @@ -481,21 +545,3 @@ get_delay_timers() -> wait_for_server() -> ct:sleep(100). - - -test_copts(_, 0, ClientOpts) -> - ClientOpts; -test_copts(max_table_size, N, ClientOpts) -> - Version = tls_record:highest_protocol_version([]), - CipherSuites = %%lists:map(fun(X) -> ssl_cipher_format:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), -[ Y|| Y = {Alg,_, _, _} <- lists:map(fun(X) -> ssl_cipher_format:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), Alg =/= ecdhe_ecdsa, Alg =/= ecdh_ecdsa, Alg =/= ecdh_rsa, Alg =/= ecdhe_rsa, Alg =/= dhe_dss, Alg =/= dss], - case length(CipherSuites) of - M when M >= N -> - Cipher = lists:nth(N, CipherSuites), - ct:pal("~p",[Cipher]), - [{ciphers, [Cipher]} | ClientOpts]; - _ -> - ClientOpts - end; -test_copts(_, _, ClientOpts) -> - ClientOpts. diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl index 251b6a2639..7629d75100 100644 --- a/lib/ssl/test/ssl_sni_SUITE.erl +++ b/lib/ssl/test/ssl_sni_SUITE.erl @@ -236,8 +236,8 @@ dns_name_reuse(Config) -> {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, [{verify, verify_peer} | ClientConf]}]), - ssl_test_lib:check_result(Client1, {error, {tls_alert, "handshake failure"}}), - ssl_test_lib:close(Client0). + ssl_test_lib:check_client_alert(Client1, handshake_failure). + %%-------------------------------------------------------------------- %% Internal Functions ------------------------------------------------ %%-------------------------------------------------------------------- @@ -370,8 +370,8 @@ unsuccessfull_connect(ServerOptions, ClientOptions, Hostname0, Config) -> {from, self()}, {options, ClientOptions}]), - ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}, - Client, {error, {tls_alert, "handshake failure"}}). + ssl_test_lib:check_server_alert(Server, Client, handshake_failure). + host_name(undefined, Hostname) -> Hostname; host_name(Hostname, _) -> diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index a8d62d6c4e..c6a4a45dce 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -30,6 +30,7 @@ -record(sslsocket, { fd = nil, pid = nil}). -define(SLEEP, 1000). +-define(DEFAULT_CURVE, secp256r1). %% For now always run locally run_where(_) -> @@ -437,6 +438,37 @@ check_result(Pid, Msg) -> {got, Unexpected}}, ct:fail(Reason) end. +check_server_alert(Pid, Alert) -> + receive + {Pid, {error, {tls_alert, {Alert, _}}}} -> + ok + end. +check_server_alert(Server, Client, Alert) -> + receive + {Server, {error, {tls_alert, {Alert, _}}}} -> + receive + {Client, {error, {tls_alert, {Alert, _}}}} -> + ok; + {Client, {error, closed}} -> + ok + end + end. +check_client_alert(Pid, Alert) -> + receive + {Pid, {error, {tls_alert, {Alert, _}}}} -> + ok + end. +check_client_alert(Server, Client, Alert) -> + receive + {Client, {error, {tls_alert, {Alert, _}}}} -> + receive + {Server, {error, {tls_alert, {Alert, _}}}} -> + ok; + {Server, {error, closed}} -> + ok + end + end. + wait_for_result(Server, ServerMsg, Client, ClientMsg) -> receive @@ -523,7 +555,7 @@ cert_options(Config) -> {client_verification_opts, [{cacertfile, ServerCaCertFile}, {certfile, ClientCertFile}, {keyfile, ClientKeyFile}, - {ssl_imp, new}]}, + {verify, verify_peer}]}, {client_verification_opts_digital_signature_only, [{cacertfile, ServerCaCertFile}, {certfile, ClientCertFileDigitalSignatureOnly}, {keyfile, ClientKeyFile}, @@ -618,9 +650,12 @@ make_rsa_cert_chains(UserConf, Config, Suffix) -> }. make_ec_cert_chains(UserConf, ClientChainType, ServerChainType, Config) -> + make_ec_cert_chains(UserConf, ClientChainType, ServerChainType, Config, ?DEFAULT_CURVE). +%% +make_ec_cert_chains(UserConf, ClientChainType, ServerChainType, Config, Curve) -> ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()), ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()), - CertChainConf = gen_conf(ClientChainType, ServerChainType, ClientChain, ServerChain), + CertChainConf = gen_conf(ClientChainType, ServerChainType, ClientChain, ServerChain, Curve), ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(ClientChainType)]), ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(ServerChainType)]), GenCertData = public_key:pkix_test_data(CertChainConf), @@ -635,7 +670,11 @@ default_cert_chain_conf() -> %% Use only default options [[],[],[]]. -gen_conf(mix, mix, UserClient, UserServer) -> + +gen_conf(ClientChainType, ServerChainType, UserClient, UserServer) -> + gen_conf(ClientChainType, ServerChainType, UserClient, UserServer, ?DEFAULT_CURVE). +%% +gen_conf(mix, mix, UserClient, UserServer, _) -> ClientTag = conf_tag("client"), ServerTag = conf_tag("server"), @@ -646,12 +685,12 @@ gen_conf(mix, mix, UserClient, UserServer) -> ServerConf = merge_chain_spec(UserServer, DefaultServer, []), new_format([{ClientTag, ClientConf}, {ServerTag, ServerConf}]); -gen_conf(ClientChainType, ServerChainType, UserClient, UserServer) -> +gen_conf(ClientChainType, ServerChainType, UserClient, UserServer, Curve) -> ClientTag = conf_tag("client"), ServerTag = conf_tag("server"), - DefaultClient = chain_spec(client, ClientChainType), - DefaultServer = chain_spec(server, ServerChainType), + DefaultClient = chain_spec(client, ClientChainType, Curve), + DefaultServer = chain_spec(server, ServerChainType, Curve), ClientConf = merge_chain_spec(UserClient, DefaultClient, []), ServerConf = merge_chain_spec(UserServer, DefaultServer, []), @@ -673,43 +712,43 @@ proplist_to_map([Head | Rest]) -> conf_tag(Role) -> list_to_atom(Role ++ "_chain"). -chain_spec(_Role, ecdh_rsa) -> +chain_spec(_Role, ecdh_rsa, Curve) -> Digest = {digest, appropriate_sha(crypto:supports())}, - CurveOid = hd(tls_v1:ecc_curves(0)), + CurveOid = pubkey_cert_records:namedCurves(Curve), [[Digest, {key, {namedCurve, CurveOid}}], [Digest, {key, hardcode_rsa_key(1)}], [Digest, {key, {namedCurve, CurveOid}}]]; -chain_spec(_Role, ecdhe_ecdsa) -> +chain_spec(_Role, ecdhe_ecdsa, Curve) -> Digest = {digest, appropriate_sha(crypto:supports())}, - CurveOid = hd(tls_v1:ecc_curves(0)), + CurveOid = pubkey_cert_records:namedCurves(Curve), [[Digest, {key, {namedCurve, CurveOid}}], [Digest, {key, {namedCurve, CurveOid}}], [Digest, {key, {namedCurve, CurveOid}}]]; -chain_spec(_Role, ecdh_ecdsa) -> +chain_spec(_Role, ecdh_ecdsa, Curve) -> Digest = {digest, appropriate_sha(crypto:supports())}, - CurveOid = hd(tls_v1:ecc_curves(0)), + CurveOid = pubkey_cert_records:namedCurves(Curve), [[Digest, {key, {namedCurve, CurveOid}}], [Digest, {key, {namedCurve, CurveOid}}], [Digest, {key, {namedCurve, CurveOid}}]]; -chain_spec(_Role, ecdhe_rsa) -> +chain_spec(_Role, ecdhe_rsa, _) -> Digest = {digest, appropriate_sha(crypto:supports())}, [[Digest, {key, hardcode_rsa_key(1)}], [Digest, {key, hardcode_rsa_key(2)}], [Digest, {key, hardcode_rsa_key(3)}]]; -chain_spec(_Role, ecdsa) -> +chain_spec(_Role, ecdsa, Curve) -> Digest = {digest, appropriate_sha(crypto:supports())}, - CurveOid = hd(tls_v1:ecc_curves(0)), + CurveOid = pubkey_cert_records:namedCurves(Curve), [[Digest, {key, {namedCurve, CurveOid}}], [Digest, {key, {namedCurve, CurveOid}}], [Digest, {key, {namedCurve, CurveOid}}]]; -chain_spec(_Role, rsa) -> +chain_spec(_Role, rsa, _) -> Digest = {digest, appropriate_sha(crypto:supports())}, [[Digest, {key, hardcode_rsa_key(1)}], [Digest, {key, hardcode_rsa_key(2)}], [Digest, {key, hardcode_rsa_key(3)}]]; -chain_spec(_Role, dsa) -> +chain_spec(_Role, dsa, _) -> Digest = {digest, appropriate_sha(crypto:supports())}, [[Digest, {key, hardcode_dsa_key(1)}], [Digest, {key, hardcode_dsa_key(2)}], @@ -742,7 +781,7 @@ merge_spec(User, Default, [Conf | Rest], Acc) -> make_mix_cert(Config) -> Ext = x509_test:extensions([{key_usage, [digitalSignature]}]), Digest = {digest, appropriate_sha(crypto:supports())}, - CurveOid = hd(tls_v1:ecc_curves(0)), + CurveOid = pubkey_cert_records:namedCurves(?DEFAULT_CURVE), Mix = proplists:get_value(mix, Config, peer_ecc), ClientChainType =ServerChainType = mix, {ClientChain, ServerChain} = mix(Mix, Digest, CurveOid, Ext), @@ -825,7 +864,8 @@ make_rsa_cert(Config) -> Config end. appropriate_sha(CryptoSupport) -> - case proplists:get_bool(sha256, CryptoSupport) of + Hashes = proplists:get_value(hashs, CryptoSupport), + case lists:member(sha256, Hashes) of true -> sha256; false -> @@ -1064,8 +1104,7 @@ ecc_test(Expect, COpts, SOpts, CECCOpts, SECCOpts, Config) -> ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) -> {Server, Port} = start_server_ecc_error(erlang, SOpts, SECCOpts, Config), Client = start_client_ecc_error(erlang, Port, COpts, CECCOpts, Config), - Error = {error, {tls_alert, "insufficient security"}}, - check_result(Server, Error, Client, Error). + check_server_alert(Server, Client, insufficient_security). start_client(openssl, Port, ClientOpts, Config) -> Cert = proplists:get_value(certfile, ClientOpts), @@ -1073,11 +1112,11 @@ start_client(openssl, Port, ClientOpts, Config) -> CA = proplists:get_value(cacertfile, ClientOpts), Version = ssl_test_lib:protocol_version(Config), Exe = "openssl", - Args = ["s_client", "-verify", "2", "-port", integer_to_list(Port), + Args0 = ["s_client", "-verify", "2", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version), "-cert", Cert, "-CAfile", CA, "-key", Key, "-host","localhost", "-msg", "-debug"], - + Args = maybe_force_ipv4(Args0), OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), true = port_command(OpenSslPort, "Hello world"), OpenSslPort; @@ -1091,6 +1130,18 @@ start_client(erlang, Port, ClientOpts, Config) -> {mfa, {ssl_test_lib, check_key_exchange_send_active, [KeyEx]}}, {options, [{verify, verify_peer} | ClientOpts]}]). +%% Workaround for running tests on machines where openssl +%% s_client would use an IPv6 address with localhost. As +%% this test suite and the ssl application is not prepared +%% for that we have to force s_client to use IPv4 if +%% OpenSSL supports IPv6. +maybe_force_ipv4(Args0) -> + case is_ipv6_supported() of + true -> + Args0 ++ ["-4"]; + false -> + Args0 + end. start_client_ecc(erlang, Port, ClientOpts, Expect, ECCOpts, Config) -> {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), @@ -1461,19 +1512,10 @@ cipher_result(Socket, Result) -> %% Importante to send two packets here %% to properly test "cipher state" handling ssl:send(Socket, "Hello\n"), - receive - {ssl, Socket, "H"} -> - ssl:send(Socket, " world\n"), - receive_rizzo_duong_beast(); - {ssl, Socket, "Hello\n"} -> - ssl:send(Socket, " world\n"), - receive - {ssl, Socket, " world\n"} -> - ok - end; - Other -> - {unexpected, Other} - end. + "Hello\n" = active_recv(Socket, length( "Hello\n")), + ssl:send(Socket, " world\n"), + " world\n" = active_recv(Socket, length(" world\n")), + ok. session_info_result(Socket) -> {ok, Info} = ssl:connection_information(Socket, [session_id, cipher_suite]), @@ -1592,34 +1634,81 @@ v_1_2_check(ecdh_rsa, ecdh_ecdsa) -> v_1_2_check(_, _) -> false. -send_recv_result_active(Socket) -> - ssl:send(Socket, "Hello world"), - receive - {ssl, Socket, "H"} -> - receive - {ssl, Socket, "ello world"} -> - ok - end; - {ssl, Socket, "Hello world"} -> - ok - end. - send_recv_result(Socket) -> - ssl:send(Socket, "Hello world"), - {ok,"Hello world"} = ssl:recv(Socket, 11), + Data = "Hello world", + ssl:send(Socket, Data), + {ok, Data} = ssl:recv(Socket, length(Data)), + ok. + +send_recv_result_active(Socket) -> + Data = "Hello world", + ssl:send(Socket, Data), + Data = active_recv(Socket, length(Data)), ok. send_recv_result_active_once(Socket) -> - ssl:send(Socket, "Hello world"), - receive - {ssl, Socket, "H"} -> - ssl:setopts(Socket, [{active, once}]), - receive - {ssl, Socket, "ello world"} -> - ok - end; - {ssl, Socket, "Hello world"} -> - ok + Data = "Hello world", + ssl:send(Socket, Data), + active_once_recv_list(Socket, length(Data)). + +active_recv(Socket, N) -> + active_recv(Socket, N, []). + +active_recv(_Socket, 0, Acc) -> + Acc; +active_recv(Socket, N, Acc) -> + receive + {ssl, Socket, Bytes} -> + active_recv(Socket, N-length(Bytes), Acc ++ Bytes) + end. + +active_once_recv(_Socket, 0) -> + ok; +active_once_recv(Socket, N) -> + receive + {ssl, Socket, Bytes} -> + ssl:setopts(Socket, [{active, once}]), + active_once_recv(Socket, N-byte_size(Bytes)) + end. + +active_once_recv_list(_Socket, 0) -> + ok; +active_once_recv_list(Socket, N) -> + receive + {ssl, Socket, Bytes} -> + ssl:setopts(Socket, [{active, once}]), + active_once_recv_list(Socket, N-length(Bytes)) + end. +recv_disregard(_Socket, 0) -> + ok; +recv_disregard(Socket, N) -> + {ok, Bytes} = ssl:recv(Socket, 0), + recv_disregard(Socket, N-byte_size(Bytes)). + +active_disregard(_Socket, 0) -> + ok; +active_disregard(Socket, N) -> + receive + {ssl, Socket, Bytes} -> + active_disregard(Socket, N-byte_size(Bytes)) + end. +active_once_disregard(_Socket, 0) -> + ok; +active_once_disregard(Socket, N) -> + receive + {ssl, Socket, Bytes} -> + ssl:setopts(Socket, [{active, once}]), + active_once_disregard(Socket, N-byte_size(Bytes)) + end. + +is_ipv6_supported() -> + case os:cmd("openssl version") of + "OpenSSL 0.9.8" ++ _ -> % Does not support IPv6 + false; + "OpenSSL 1.0" ++ _ -> % Does not support IPv6 + false; + _ -> + true end. is_sane_ecc(openssl) -> @@ -2159,3 +2248,98 @@ server_msg(Server, ServerMsg) -> Unexpected -> ct:fail(Unexpected) end. + +session_id(Socket) -> + {ok, [{session_id, ID}]} = ssl:connection_information(Socket, [session_id]), + ID. + +reuse_session(ClientOpts, ServerOpts, Config) -> + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server0 = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {tcp_options, [{active, false}]}, + {options, ServerOpts}]), + Port0 = ssl_test_lib:inet_port(Server0), + + Client0 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port0}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]), + Server0 ! listen, + + Client1 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port0}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, ClientOpts}]), + + SID = receive + {Client0, Id0} -> + Id0 + end, + + receive + {Client1, SID} -> + ok + after ?SLEEP -> + ct:fail(session_not_reused) + end, + + Server0 ! listen, + + Client2 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port0}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, [{reuse_sessions, false} + | ClientOpts]}]), + receive + {Client2, SID} -> + ct:fail(session_reused_when_session_reuse_disabled_by_client); + {Client2, _} -> + ok + end, + + ssl_test_lib:close(Server0), + ssl_test_lib:close(Client0), + ssl_test_lib:close(Client1), + ssl_test_lib:close(Client2), + + Server1 = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {tcp_options, [{active, false}]}, + {options, [{reuse_sessions, false} |ServerOpts]}]), + Port1 = ssl_test_lib:inet_port(Server1), + + Client3 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port1}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]), + SID1 = receive + {Client3, Id3} -> + Id3 + end, + + Server1 ! listen, + + Client4 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port1}, {host, Hostname}, + {mfa, {ssl_test_lib, session_id, []}}, + {from, self()}, {options, ClientOpts}]), + + receive + {Client4, SID1} -> + ct:fail(session_reused_when_session_reuse_disabled_by_server); + {Client4, _} -> + ok + end, + + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client3), + ssl_test_lib:close(Client4). + diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 5a38f5f9c1..df84411b6d 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -91,6 +91,7 @@ all_versions_tests() -> erlang_server_openssl_client_anon_with_cert, erlang_server_openssl_client_reuse_session, erlang_client_openssl_server_renegotiate, + erlang_client_openssl_server_renegotiate_after_client_data, erlang_client_openssl_server_nowrap_seqnum, erlang_server_openssl_client_nowrap_seqnum, erlang_client_openssl_server_no_server_ca_cert, @@ -259,8 +260,9 @@ special_init(TestCase, Config) when Config; special_init(TestCase, Config) when TestCase == erlang_client_openssl_server_renegotiate; - TestCase == erlang_client_openssl_server_nowrap_seqnum; - TestCase == erlang_server_openssl_client_nowrap_seqnum + TestCase == erlang_client_openssl_server_nowrap_seqnum; + TestCase == erlang_server_openssl_client_nowrap_seqnum; + TestCase == erlang_client_openssl_server_renegotiate_after_client_data -> {ok, Version} = application:get_env(ssl, protocol_version), check_sane_openssl_renegotaite(Config, Version); @@ -760,8 +762,8 @@ erlang_client_openssl_server_renegotiate() -> [{doc,"Test erlang client when openssl server issuses a renegotiate"}]. erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), @@ -770,12 +772,14 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(node()), CertFile = proplists:get_value(certfile, ServerOpts), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = ssl_test_lib:protocol_version(Config), Exe = "openssl", Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, "-cert", CertFile, "-key", KeyFile, "-msg"], OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), @@ -800,6 +804,53 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. +%%-------------------------------------------------------------------- +erlang_client_openssl_server_renegotiate_after_client_data() -> + [{doc,"Test erlang client when openssl server issuses a renegotiate after reading client data"}]. +erlang_client_openssl_server_renegotiate_after_client_data(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + ErlData = "From erlang to openssl", + OpenSslData = "From openssl to erlang", + + Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + Version = ssl_test_lib:protocol_version(Config), + + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, + "-cert", CertFile, "-key", KeyFile, "-msg"], + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + + ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_wait_send, [[ErlData, OpenSslData]]}}, + {options, ClientOpts}]), + + true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE), + ct:sleep(?SLEEP), + true = port_command(OpensslPort, OpenSslData), + + ssl_test_lib:check_result(Client, ok), + + %% Clean close down! Server needs to be closed first !! + ssl_test_lib:close_port(OpensslPort), + ssl_test_lib:close(Client), + process_flag(trap_exit, false), + ok. %%-------------------------------------------------------------------- @@ -810,7 +861,7 @@ erlang_client_openssl_server_nowrap_seqnum() -> " to lower treashold substantially."}]. erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) -> process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), @@ -819,12 +870,14 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) -> N = 10, Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = ssl_test_lib:protocol_version(Config), Exe = "openssl", Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, "-cert", CertFile, "-key", KeyFile, "-msg"], OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), @@ -853,7 +906,7 @@ erlang_server_openssl_client_nowrap_seqnum() -> " to lower treashold substantially."}]. erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) -> process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -1196,7 +1249,7 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]), ssl_test_lib:consume_port_exit(OpenSslPort), - ssl_test_lib:check_result(Server, {error, {tls_alert, "bad record mac"}}), + ssl_test_lib:check_server_alert(Server, bad_record_mac), process_flag(trap_exit, false). %%-------------------------------------------------------------------- @@ -1602,8 +1655,8 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) -> process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), ClientOpts = ErlangClientOpts ++ ClientOpts0, {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), @@ -1611,6 +1664,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens Data = "From openssl to erlang", Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = ssl_test_lib:protocol_version(Config), @@ -1620,10 +1674,12 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens [] -> ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, "-cert", CertFile,"-key", KeyFile]; [Opt, Value] -> ["s_server", Opt, Value, "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, "-cert", CertFile,"-key", KeyFile] end, @@ -1648,8 +1704,8 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callback) -> process_flag(trap_exit, true), - ServerOpts = proplists:get_value(server_rsa_opts, Config), - ClientOpts0 = proplists:get_value(client_rsa_opts, Config), + ServerOpts = proplists:get_value(server_rsa_verify_opts, Config), + ClientOpts0 = proplists:get_value(client_rsa_verify_opts, Config), ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]} | ClientOpts0], {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), @@ -1657,12 +1713,14 @@ start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callba Data = "From openssl to erlang", Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = ssl_test_lib:protocol_version(Config), Exe = "openssl", Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, "-cert", CertFile, "-key", KeyFile], OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)), @@ -1780,8 +1838,8 @@ start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Ca start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callback) -> process_flag(trap_exit, true), - ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config), - ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), ClientOpts = [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}} | ClientOpts0], {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), @@ -1789,6 +1847,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac Data = "From openssl to erlang", Port = ssl_test_lib:inet_port(node()), + CaCertFile = proplists:get_value(cacertfile, ServerOpts), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = ssl_test_lib:protocol_version(Config), @@ -1796,6 +1855,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac Exe = "openssl", Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-CAfile", CaCertFile, "-cert", CertFile, "-key", KeyFile], OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), @@ -1886,6 +1946,11 @@ erlang_ssl_receive(Socket, Data) -> ct:log("Connection info: ~p~n", [ssl:connection_information(Socket)]), receive + {ssl, Socket, "R\n"} -> + %% Swallow s_client renegotiation command. + %% openssl s_client connected commands can appear on + %% server side with some openssl versions. + erlang_ssl_receive(Socket,Data); {ssl, Socket, Data} -> io:format("Received ~p~n",[Data]), %% open_ssl server sometimes hangs waiting in blocking read @@ -1924,6 +1989,12 @@ server_sent_garbage(Socket) -> {error, closed} == ssl:send(Socket, "data") end. + +send_wait_send(Socket, [ErlData, OpenSslData]) -> + ssl:send(Socket, ErlData), + ct:sleep(?SLEEP), + ssl:send(Socket, ErlData), + erlang_ssl_receive(Socket, OpenSslData). check_openssl_sni_support(Config) -> HelpText = os:cmd("openssl s_client --help"), diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 75d959accf..3527062a8a 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 9.1 +SSL_VSN = 9.1.2 diff --git a/lib/stdlib/doc/src/array.xml b/lib/stdlib/doc/src/array.xml index db0ab42372..aa1577a067 100644 --- a/lib/stdlib/doc/src/array.xml +++ b/lib/stdlib/doc/src/array.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>array.xml</file> </header> - <module>array</module> + <module since="">array</module> <modulesummary>Functional, extendible arrays.</modulesummary> <description> <p>Functional, extendible arrays. Arrays can have fixed size, or can grow @@ -137,7 +137,7 @@ A3 = array:fix(A2).</pre> <funcs> <func> - <name name="default" arity="1"/> + <name name="default" arity="1" since=""/> <fsummary>Get the value used for uninitialized entries.</fsummary> <desc><marker id="default-1"/> <p>Gets the value used for uninitialized entries.</p> @@ -146,7 +146,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="fix" arity="1"/> + <name name="fix" arity="1" since=""/> <fsummary>Fix the array size.</fsummary> <desc><marker id="fix-1"/> <p>Fixes the array size. This prevents it from growing automatically @@ -157,7 +157,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="foldl" arity="3"/> + <name name="foldl" arity="3" since=""/> <fsummary>Fold the array elements using the specified function and initial accumulator value.</fsummary> <desc><marker id="foldl-3"/> @@ -172,7 +172,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="foldr" arity="3"/> + <name name="foldr" arity="3" since=""/> <fsummary>Fold the array elements right-to-left using the specified function and initial accumulator value.</fsummary> <desc><marker id="foldr-3"/> @@ -186,7 +186,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="from_list" arity="1"/> + <name name="from_list" arity="1" since=""/> <fsummary>Equivalent to <c>from_list(List, undefined)</c>.</fsummary> <desc><marker id="from_list-1"/> <p>Equivalent to @@ -195,7 +195,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="from_list" arity="2"/> + <name name="from_list" arity="2" since=""/> <fsummary>Convert a list to an extendible array.</fsummary> <desc><marker id="from_list-2"/> <p>Converts a list to an extendible array. <c><anno>Default</anno></c> @@ -208,7 +208,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="from_orddict" arity="1"/> + <name name="from_orddict" arity="1" since=""/> <fsummary>Equivalent to <c>from_orddict(Orddict, undefined)</c>. </fsummary> <desc><marker id="from_orddict-1"/> @@ -218,7 +218,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="from_orddict" arity="2"/> + <name name="from_orddict" arity="2" since=""/> <fsummary>Convert an ordered list of pairs <c>{Index, Value}</c> to a corresponding extendible array.</fsummary> <desc><marker id="from_orddict-2"/> @@ -234,7 +234,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="get" arity="2"/> + <name name="get" arity="2" since=""/> <fsummary>Get the value of entry <c>I</c>.</fsummary> <desc><marker id="get-2"/> <p>Gets the value of entry <c><anno>I</anno></c>. If @@ -249,7 +249,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="is_array" arity="1"/> + <name name="is_array" arity="1" since=""/> <fsummary>Returns <c>true</c> if <c>X</c> is an array, otherwise <c>false</c>.</fsummary> <desc><marker id="is_array-1"/> @@ -261,7 +261,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="is_fix" arity="1"/> + <name name="is_fix" arity="1" since=""/> <fsummary>Check if the array has fixed size.</fsummary> <desc><marker id="is_fix-1"/> <p>Checks if the array has fixed size. Returns <c>true</c> if the array @@ -271,7 +271,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="map" arity="2"/> + <name name="map" arity="2" since=""/> <fsummary>Map the specified function onto each array element.</fsummary> <desc><marker id="map-2"/> <p>Maps the specified function onto each array element. The elements are @@ -285,7 +285,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="new" arity="0"/> + <name name="new" arity="0" since=""/> <fsummary>Create a new, extendible array with initial size zero. </fsummary> <desc><marker id="new-0"/> @@ -296,7 +296,7 @@ A3 = array:fix(A2).</pre> </func> <func> - <name name="new" arity="1"/> + <name name="new" arity="1" since=""/> <fsummary>Create a new array according to the specified options. </fsummary> <desc><marker id="new-1"/> @@ -346,7 +346,7 @@ array:new([{size,10},{fixed,false},{default,-1}])</pre> </func> <func> - <name name="new" arity="2"/> + <name name="new" arity="2" since=""/> <fsummary>Create a new array according to the specified size and options. </fsummary> <desc><marker id="new-2"/> @@ -370,7 +370,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="relax" arity="1"/> + <name name="relax" arity="1" since=""/> <fsummary>Make the array resizable.</fsummary> <desc><marker id="relax-1"/> <p>Makes the array resizable. (Reverses the effects of @@ -380,7 +380,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="reset" arity="2"/> + <name name="reset" arity="2" since=""/> <fsummary>Reset entry <c>I</c> to the default value for the array. </fsummary> <desc><marker id="reset-2"/> @@ -399,7 +399,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="resize" arity="1"/> + <name name="resize" arity="1" since=""/> <fsummary>Change the array size to that reported by <c>sparse_size/1</c>. </fsummary> <desc><marker id="resize-1"/> @@ -413,7 +413,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="resize" arity="2"/> + <name name="resize" arity="2" since=""/> <fsummary>Change the array size.</fsummary> <desc><marker id="resize-2"/> <p>Change the array size. If <c><anno>Size</anno></c> is not a @@ -424,7 +424,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="set" arity="3"/> + <name name="set" arity="3" since=""/> <fsummary>Set entry <c>I</c> of the array to <c>Value</c>.</fsummary> <desc><marker id="set-3"/> <p>Sets entry <c><anno>I</anno></c> of the array to @@ -441,7 +441,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="size" arity="1"/> + <name name="size" arity="1" since=""/> <fsummary>Get the number of entries in the array.</fsummary> <desc><marker id="size-1"/> <p>Gets the number of entries in the array. Entries are numbered from @@ -454,7 +454,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="sparse_foldl" arity="3"/> + <name name="sparse_foldl" arity="3" since=""/> <fsummary>Fold the array elements using the specified function and initial accumulator value, skipping default-valued entries.</fsummary> <desc><marker id="sparse_foldl-3"/> @@ -469,7 +469,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="sparse_foldr" arity="3"/> + <name name="sparse_foldr" arity="3" since=""/> <fsummary>Fold the array elements right-to-left using the specified function and initial accumulator value, skipping default-valued entries.</fsummary> @@ -485,7 +485,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="sparse_map" arity="2"/> + <name name="sparse_map" arity="2" since=""/> <fsummary>Map the specified function onto each array element, skipping default-valued entries.</fsummary> <desc><marker id="sparse_map-2"/> @@ -498,7 +498,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="sparse_size" arity="1"/> + <name name="sparse_size" arity="1" since=""/> <fsummary>Get the number of entries in the array up until the last non-default-valued entry.</fsummary> <desc><marker id="sparse_size-1"/> @@ -512,7 +512,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="sparse_to_list" arity="1"/> + <name name="sparse_to_list" arity="1" since=""/> <fsummary>Convert the array to a list, skipping default-valued entries. </fsummary> <desc><marker id="sparse_to_list-1"/> @@ -522,7 +522,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="sparse_to_orddict" arity="1"/> + <name name="sparse_to_orddict" arity="1" since=""/> <fsummary>Convert the array to an ordered list of pairs <c>{Index, Value}</c>, skipping default-valued entries.</fsummary> <desc><marker id="sparse_to_orddict-1"/> @@ -534,7 +534,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="to_list" arity="1"/> + <name name="to_list" arity="1" since=""/> <fsummary>Convert the array to a list.</fsummary> <desc><marker id="to_list-1"/> <p>Converts the array to a list.</p> @@ -545,7 +545,7 @@ array:new(100, {default,0})</pre> </func> <func> - <name name="to_orddict" arity="1"/> + <name name="to_orddict" arity="1" since=""/> <fsummary>Convert the array to an ordered list of pairs <c>{Index, Value}</c>.</fsummary> <desc><marker id="to_orddict-1"/> diff --git a/lib/stdlib/doc/src/base64.xml b/lib/stdlib/doc/src/base64.xml index cfa1ecc006..479072ba4f 100644 --- a/lib/stdlib/doc/src/base64.xml +++ b/lib/stdlib/doc/src/base64.xml @@ -29,7 +29,7 @@ <rev></rev> <file>base64.xml</file> </header> - <module>base64</module> + <module since="">base64</module> <modulesummary>Provides base64 encode and decode, see RFC 2045.</modulesummary> <description> @@ -51,10 +51,10 @@ <funcs> <func> - <name name="decode" arity="1"/> - <name name="decode_to_string" arity="1"/> - <name name="mime_decode" arity="1"/> - <name name="mime_decode_to_string" arity="1"/> + <name name="decode" arity="1" since=""/> + <name name="decode_to_string" arity="1" since=""/> + <name name="mime_decode" arity="1" since=""/> + <name name="mime_decode_to_string" arity="1" since=""/> <fsummary>Decode a base64 encoded string to data.</fsummary> <type variable="Base64" name_i="1"/> <type variable="Data" name_i="1"/> @@ -69,8 +69,8 @@ </func> <func> - <name name="encode" arity="1"/> - <name name="encode_to_string" arity="1"/> + <name name="encode" arity="1" since=""/> + <name name="encode_to_string" arity="1" since=""/> <fsummary>Encode data into base64.</fsummary> <type variable="Data"/> <type variable="Base64" name_i="1"/> diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml index 213170df7f..8bb4cf9101 100644 --- a/lib/stdlib/doc/src/beam_lib.xml +++ b/lib/stdlib/doc/src/beam_lib.xml @@ -28,7 +28,7 @@ <date>1999-10-30</date> <rev>PA1</rev> </header> - <module>beam_lib</module> + <module since="">beam_lib</module> <modulesummary>An interface to the BEAM file format.</modulesummary> <description> <p>This module provides an interface to files created by @@ -267,7 +267,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code> <funcs> <func> - <name name="all_chunks" arity="1"/> + <name name="all_chunks" arity="1" since="OTP 18.2"/> <fsummary>Read all chunks from a BEAM file or binary</fsummary> <desc> <p>Reads chunk data for all chunks.</p> @@ -275,7 +275,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code> </func> <func> - <name name="build_module" arity="1"/> + <name name="build_module" arity="1" since="OTP 18.2"/> <fsummary>Create a BEAM module from a list of chunks.</fsummary> <desc> <p>Builds a BEAM module (as a binary) from a list of chunks.</p> @@ -283,7 +283,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code> </func> <func> - <name name="chunks" arity="2"/> + <name name="chunks" arity="2" since=""/> <fsummary>Read selected chunks from a BEAM file or binary.</fsummary> <desc> <p>Reads chunk data for selected chunks references. The order of @@ -293,7 +293,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code> </func> <func> - <name name="chunks" arity="3"/> + <name name="chunks" arity="3" since=""/> <fsummary>Read selected chunks from a BEAM file or binary.</fsummary> <desc> <p>Reads chunk data for selected chunks references. The order of @@ -312,7 +312,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code> </func> <func> - <name name="clear_crypto_key_fun" arity="0"/> + <name name="clear_crypto_key_fun" arity="0" since=""/> <fsummary>Unregister the current crypto key fun.</fsummary> <desc> <p>Unregisters the crypto key fun and terminates the process @@ -327,7 +327,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code> </func> <func> - <name name="cmp" arity="2"/> + <name name="cmp" arity="2" since=""/> <fsummary>Compare two BEAM files.</fsummary> <type name="cmp_rsn"/> <desc> @@ -341,7 +341,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code> </func> <func> - <name name="cmp_dirs" arity="2"/> + <name name="cmp_dirs" arity="2" since=""/> <fsummary>Compare the BEAM files in two directories.</fsummary> <desc> <p>Compares the BEAM files in @@ -359,7 +359,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code> </func> <func> - <name name="crypto_key_fun" arity="1"/> + <name name="crypto_key_fun" arity="1" since=""/> <fsummary>Register a fun that provides a crypto key.</fsummary> <type name="crypto_fun"/> <type name="crypto_fun_arg"/> @@ -398,7 +398,7 @@ CryptoKeyFun(clear) -> term()</code> </func> <func> - <name name="diff_dirs" arity="2"/> + <name name="diff_dirs" arity="2" since=""/> <fsummary>Compare the BEAM files in two directories.</fsummary> <desc> <p>Compares the BEAM files in two directories as @@ -409,7 +409,7 @@ CryptoKeyFun(clear) -> term()</code> </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Return an English description of a BEAM read error reply. </fsummary> <desc> @@ -422,7 +422,7 @@ CryptoKeyFun(clear) -> term()</code> </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since=""/> <fsummary>Information about a BEAM file.</fsummary> <desc> <p>Returns a list containing some information about a BEAM file @@ -449,7 +449,7 @@ CryptoKeyFun(clear) -> term()</code> </func> <func> - <name name="md5" arity="1"/> + <name name="md5" arity="1" since=""/> <fsummary>Read the module version of the BEAM file.</fsummary> <desc> <p>Calculates an MD5 redundancy check for the code of the module @@ -458,7 +458,7 @@ CryptoKeyFun(clear) -> term()</code> </func> <func> - <name name="strip" arity="1"/> + <name name="strip" arity="1" since=""/> <fsummary>Remove chunks not needed by the loader from a BEAM file. </fsummary> <desc> @@ -470,7 +470,7 @@ CryptoKeyFun(clear) -> term()</code> </func> <func> - <name name="strip_files" arity="1"/> + <name name="strip_files" arity="1" since=""/> <fsummary>Removes chunks not needed by the loader from BEAM files. </fsummary> <desc> @@ -483,7 +483,7 @@ CryptoKeyFun(clear) -> term()</code> </func> <func> - <name name="strip_release" arity="1"/> + <name name="strip_release" arity="1" since=""/> <fsummary>Remove chunks not needed by the loader from all BEAM files of a release.</fsummary> <desc> @@ -497,7 +497,7 @@ CryptoKeyFun(clear) -> term()</code> </func> <func> - <name name="version" arity="1"/> + <name name="version" arity="1" since=""/> <fsummary>Read the module version of the BEAM file.</fsummary> <desc> <p>Returns the module version or versions. A version is defined by diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml index 6a86d6c7ba..f3d4edd30f 100644 --- a/lib/stdlib/doc/src/binary.xml +++ b/lib/stdlib/doc/src/binary.xml @@ -34,7 +34,7 @@ <rev>A</rev> <file>binary.xml</file> </header> - <module>binary</module> + <module since="OTP R14B">binary</module> <modulesummary>Library for handling binary data.</modulesummary> <description> @@ -79,7 +79,7 @@ <funcs> <func> - <name name="at" arity="2"/> + <name name="at" arity="2" since="OTP R14B"/> <fsummary>Return the byte at a specific position in a binary.</fsummary> <desc> <p>Returns the byte at position <c><anno>Pos</anno></c> (zero-based) in @@ -90,7 +90,7 @@ </func> <func> - <name name="bin_to_list" arity="1"/> + <name name="bin_to_list" arity="1" since="OTP R14B"/> <fsummary>Convert a binary to a list of integers.</fsummary> <desc> <p>Same as <c>bin_to_list(<anno>Subject</anno>, {0,byte_size(<anno>Subject</anno>)})</c>.</p> @@ -98,7 +98,7 @@ </func> <func> - <name name="bin_to_list" arity="2"/> + <name name="bin_to_list" arity="2" since="OTP R14B"/> <fsummary>Convert a binary to a list of integers.</fsummary> <desc> <p>Converts <c><anno>Subject</anno></c> to a list of <c>byte()</c>s, each @@ -118,7 +118,7 @@ </func> <func> - <name name="bin_to_list" arity="3"/> + <name name="bin_to_list" arity="3" since="OTP R14B"/> <fsummary>Convert a binary to a list of integers.</fsummary> <desc> <p>Same as<c> bin_to_list(<anno>Subject</anno>, {<anno>Pos</anno>, <anno>Len</anno>})</c>.</p> @@ -126,7 +126,7 @@ </func> <func> - <name name="compile_pattern" arity="1"/> + <name name="compile_pattern" arity="1" since="OTP R14B"/> <fsummary>Precompile a binary search pattern.</fsummary> <desc> <p>Builds an internal structure representing a compilation of a @@ -158,7 +158,7 @@ </func> <func> - <name name="copy" arity="1"/> + <name name="copy" arity="1" since="OTP R14B"/> <fsummary>Create a duplicate of a binary.</fsummary> <desc> <p>Same as <c>copy(<anno>Subject</anno>, 1)</c>.</p> @@ -166,7 +166,7 @@ </func> <func> - <name name="copy" arity="2"/> + <name name="copy" arity="2" since="OTP R14B"/> <fsummary>Duplicate a binary <c>N</c> times and create a new.</fsummary> <desc> <p>Creates a binary with the content of <c><anno>Subject</anno></c> @@ -193,7 +193,7 @@ </func> <func> - <name name="decode_unsigned" arity="1"/> + <name name="decode_unsigned" arity="1" since="OTP R14B"/> <fsummary>Decode a whole binary into an integer of arbitrary size. </fsummary> <desc> @@ -202,7 +202,7 @@ </func> <func> - <name name="decode_unsigned" arity="2"/> + <name name="decode_unsigned" arity="2" since="OTP R14B"/> <fsummary>Decode a whole binary into an integer of arbitrary size. </fsummary> <desc> @@ -219,7 +219,7 @@ </func> <func> - <name name="encode_unsigned" arity="1"/> + <name name="encode_unsigned" arity="1" since="OTP R14B"/> <fsummary>Encode an unsigned integer into the minimal binary.</fsummary> <desc> <p>Same as <c>encode_unsigned(<anno>Unsigned</anno>, big)</c>.</p> @@ -227,7 +227,7 @@ </func> <func> - <name name="encode_unsigned" arity="2"/> + <name name="encode_unsigned" arity="2" since="OTP R14B"/> <fsummary>Encode an unsigned integer into the minimal binary.</fsummary> <desc> <p>Converts a positive integer to the smallest possible @@ -243,7 +243,7 @@ </func> <func> - <name name="first" arity="1"/> + <name name="first" arity="1" since="OTP R14B"/> <fsummary>Return the first byte of a binary.</fsummary> <desc> <p>Returns the first byte of binary <c><anno>Subject</anno></c> as an @@ -253,7 +253,7 @@ </func> <func> - <name name="last" arity="1"/> + <name name="last" arity="1" since="OTP R14B"/> <fsummary>Return the last byte of a binary.</fsummary> <desc> <p>Returns the last byte of binary <c><anno>Subject</anno></c> as an @@ -263,7 +263,7 @@ </func> <func> - <name name="list_to_bin" arity="1"/> + <name name="list_to_bin" arity="1" since="OTP R14B"/> <fsummary>Convert a list of integers and binaries to a binary.</fsummary> <desc> <p>Works exactly as @@ -273,7 +273,7 @@ </func> <func> - <name name="longest_common_prefix" arity="1"/> + <name name="longest_common_prefix" arity="1" since="OTP R14B"/> <fsummary>Return length of longest common prefix for a set of binaries. </fsummary> <desc> @@ -294,7 +294,7 @@ </func> <func> - <name name="longest_common_suffix" arity="1"/> + <name name="longest_common_suffix" arity="1" since="OTP R14B"/> <fsummary>Return length of longest common suffix for a set of binaries. </fsummary> <desc> @@ -315,7 +315,7 @@ </func> <func> - <name name="match" arity="2"/> + <name name="match" arity="2" since="OTP R14B"/> <fsummary>Search for the first match of a pattern in a binary.</fsummary> <desc> <p>Same as <c>match(<anno>Subject</anno>, <anno>Pattern</anno>, [])</c>. @@ -324,7 +324,7 @@ </func> <func> - <name name="match" arity="3"/> + <name name="match" arity="3" since="OTP R14B"/> <fsummary>Search for the first match of a pattern in a binary.</fsummary> <type name="part"/> <desc> @@ -372,7 +372,7 @@ </func> <func> - <name name="matches" arity="2"/> + <name name="matches" arity="2" since="OTP R14B"/> <fsummary>Search for all matches of a pattern in a binary.</fsummary> <desc> <p>Same as <c>matches(<anno>Subject</anno>, <anno>Pattern</anno>, [])</c>. @@ -381,7 +381,7 @@ </func> <func> - <name name="matches" arity="3"/> + <name name="matches" arity="3" since="OTP R14B"/> <fsummary>Search for all matches of a pattern in a binary.</fsummary> <type name="part"/> <desc> @@ -425,7 +425,7 @@ </func> <func> - <name name="part" arity="2"/> + <name name="part" arity="2" since="OTP R14B"/> <fsummary>Extract a part of a binary.</fsummary> <desc> <p>Extracts the part of binary <c><anno>Subject</anno></c> described by @@ -453,7 +453,7 @@ </func> <func> - <name name="part" arity="3"/> + <name name="part" arity="3" since="OTP R14B"/> <fsummary>Extract a part of a binary.</fsummary> <desc> <p>Same as <c>part(<anno>Subject</anno>, {<anno>Pos</anno>, @@ -462,7 +462,7 @@ </func> <func> - <name name="referenced_byte_size" arity="1"/> + <name name="referenced_byte_size" arity="1" since="OTP R14B"/> <fsummary>Determine the size of the binary pointed out by a subbinary. </fsummary> <desc> @@ -525,7 +525,7 @@ store(Binary, GBSet) -> </func> <func> - <name name="replace" arity="3"/> + <name name="replace" arity="3" since="OTP R14B"/> <fsummary>Replace bytes in a binary according to a pattern.</fsummary> <desc> <p>Same as <c>replace(<anno>Subject</anno>, <anno>Pattern</anno>, <anno>Replacement</anno>,[])</c>.</p> @@ -533,7 +533,7 @@ store(Binary, GBSet) -> </func> <func> - <name name="replace" arity="4"/> + <name name="replace" arity="4" since="OTP R14B"/> <fsummary>Replace bytes in a binary according to a pattern.</fsummary> <type_desc variable="OnePos">An integer() =< byte_size(<anno>Replacement</anno>) </type_desc> @@ -575,7 +575,7 @@ store(Binary, GBSet) -> </func> <func> - <name name="split" arity="2"/> + <name name="split" arity="2" since="OTP R14B"/> <fsummary>Split a binary according to a pattern.</fsummary> <desc> <p>Same as <c>split(<anno>Subject</anno>, <anno>Pattern</anno>, @@ -584,7 +584,7 @@ store(Binary, GBSet) -> </func> <func> - <name name="split" arity="3"/> + <name name="split" arity="3" since="OTP R14B"/> <fsummary>Split a binary according to a pattern.</fsummary> <desc> <p>Splits <c><anno>Subject</anno></c> into a list of binaries based on diff --git a/lib/stdlib/doc/src/c.xml b/lib/stdlib/doc/src/c.xml index b6cb6f5aae..29edc373c7 100644 --- a/lib/stdlib/doc/src/c.xml +++ b/lib/stdlib/doc/src/c.xml @@ -28,7 +28,7 @@ <date>1996-10-30</date> <rev>B</rev> </header> - <module>c</module> + <module since="">c</module> <modulesummary>Command interface module.</modulesummary> <description> <p>This module enables users to enter the short form of @@ -41,7 +41,7 @@ <funcs> <func> - <name name="bt" arity="1"/> + <name name="bt" arity="1" since=""/> <fsummary>Stack backtrace for a process.</fsummary> <desc> <p>Stack backtrace for a process. Equivalent to @@ -50,9 +50,9 @@ </func> <func> - <name name="c" arity="1"/> - <name name="c" arity="2"/> - <name name="c" arity="3"/> + <name name="c" arity="1" since=""/> + <name name="c" arity="2" since=""/> + <name name="c" arity="3" since="OTP 20.0"/> <fsummary>Compile and load a file or module.</fsummary> <desc> <p>Compiles and then purges and loads the code for a module. @@ -80,7 +80,7 @@ </func> <func> - <name name="cd" arity="1"/> + <name name="cd" arity="1" since=""/> <fsummary>Change working directory.</fsummary> <desc> <p>Changes working directory to <c><anno>Dir</anno></c>, which can be a @@ -94,7 +94,7 @@ </func> <func> - <name name="erlangrc" arity="1"/> + <name name="erlangrc" arity="1" since="OTP 21.0"/> <fsummary>Load an erlang resource file.</fsummary> <desc> <p>Search <c>PathList</c> and load <c>.erlang</c> resource file if @@ -103,7 +103,7 @@ </func> <func> - <name name="flush" arity="0"/> + <name name="flush" arity="0" since=""/> <fsummary>Flush any messages sent to the shell.</fsummary> <desc> <p>Flushes any messages sent to the shell.</p> @@ -111,7 +111,7 @@ </func> <func> - <name name="help" arity="0"/> + <name name="help" arity="0" since=""/> <fsummary>Help information.</fsummary> <desc> <p>Displays help information: all valid shell internal commands, @@ -120,8 +120,8 @@ </func> <func> - <name name="i" arity="0"/> - <name name="ni" arity="0"/> + <name name="i" arity="0" since=""/> + <name name="ni" arity="0" since=""/> <fsummary>System information.</fsummary> <desc> <p><c>i/0</c> displays system information, listing @@ -131,7 +131,7 @@ </func> <func> - <name name="i" arity="3"/> + <name name="i" arity="3" since=""/> <fsummary>Information about pid <X.Y.Z>.</fsummary> <desc> <p>Displays information about a process, Equivalent to @@ -141,7 +141,7 @@ </func> <func> - <name name="l" arity="1"/> + <name name="l" arity="1" since=""/> <fsummary>Load or reload a module.</fsummary> <desc> <p>Purges and loads, or reloads, a module by calling @@ -154,7 +154,7 @@ </func> <func> - <name>lc(Files) -> ok</name> + <name since="">lc(Files) -> ok</name> <fsummary>Compile a list of files.</fsummary> <type> <v>Files = [File]</v> @@ -171,7 +171,7 @@ </func> <func> - <name name="lm" arity="0"/> + <name name="lm" arity="0" since="OTP 20.0"/> <fsummary>Loads all modified modules.</fsummary> <desc> <p>Reloads all currently loaded modules that have changed on disk (see <c>mm()</c>). @@ -180,7 +180,7 @@ </func> <func> - <name name="ls" arity="0"/> + <name name="ls" arity="0" since=""/> <fsummary>List files in the current directory.</fsummary> <desc> <p>Lists files in the current directory.</p> @@ -188,7 +188,7 @@ </func> <func> - <name name="ls" arity="1"/> + <name name="ls" arity="1" since=""/> <fsummary>List files in a directory or a single file.</fsummary> <desc> <p>Lists files in directory <c><anno>Dir</anno></c> or, if <c>Dir</c> @@ -197,7 +197,7 @@ </func> <func> - <name name="m" arity="0"/> + <name name="m" arity="0" since=""/> <fsummary>Which modules are loaded.</fsummary> <desc> <p>Displays information about the loaded modules, including @@ -206,7 +206,7 @@ </func> <func> - <name name="m" arity="1"/> + <name name="m" arity="1" since=""/> <fsummary>Information about a module.</fsummary> <desc> <p>Displays information about <c><anno>Module</anno></c>.</p> @@ -214,7 +214,7 @@ </func> <func> - <name name="mm" arity="0"/> + <name name="mm" arity="0" since="OTP 20.0"/> <fsummary>Lists all modified modules.</fsummary> <desc> <p>Lists all modified modules. Shorthand for @@ -223,7 +223,7 @@ </func> <func> - <name name="memory" arity="0"/> + <name name="memory" arity="0" since=""/> <fsummary>Memory allocation information.</fsummary> <desc> <p>Memory allocation information. Equivalent to @@ -232,8 +232,8 @@ </func> <func> - <name name="memory" arity="1" clause_i="1"/> - <name name="memory" arity="1" clause_i="2"/> + <name name="memory" arity="1" clause_i="1" since=""/> + <name name="memory" arity="1" clause_i="2" since=""/> <fsummary>Memory allocation information.</fsummary> <desc> <p>Memory allocation information. Equivalent to @@ -242,8 +242,8 @@ </func> <func> - <name name="nc" arity="1"/> - <name name="nc" arity="2"/> + <name name="nc" arity="1" since=""/> + <name name="nc" arity="2" since=""/> <fsummary>Compile and load code in a file on all nodes.</fsummary> <desc> <p>Compiles and then loads the code for a file on all nodes. @@ -255,7 +255,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w </func> <func> - <name name="nl" arity="1"/> + <name name="nl" arity="1" since=""/> <fsummary>Load module on all nodes.</fsummary> <desc> <p>Loads <c><anno>Module</anno></c> on all nodes.</p> @@ -263,7 +263,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w </func> <func> - <name name="pid" arity="3"/> + <name name="pid" arity="3" since=""/> <fsummary>Convert <c>X,Y,Z</c> to a pid.</fsummary> <desc> <p>Converts <c><anno>X</anno></c>, <c><anno>Y</anno></c>, @@ -273,7 +273,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w </func> <func> - <name name="pwd" arity="0"/> + <name name="pwd" arity="0" since=""/> <fsummary>Print working directory.</fsummary> <desc> <p>Prints the name of the working directory.</p> @@ -281,7 +281,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w </func> <func> - <name name="q" arity="0"/> + <name name="q" arity="0" since=""/> <fsummary>Quit - shorthand for <c>init:stop()</c>.</fsummary> <desc> <p>This function is shorthand for <c>init:stop()</c>, that is, @@ -290,8 +290,8 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w </func> <func> - <name name="regs" arity="0"/> - <name name="nregs" arity="0"/> + <name name="regs" arity="0" since=""/> + <name name="nregs" arity="0" since=""/> <fsummary>Information about registered processes.</fsummary> <desc> <p><c>regs/0</c> displays information about all registered @@ -301,7 +301,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w </func> <func> - <name name="uptime" arity="0"/> + <name name="uptime" arity="0" since="OTP 18.0"/> <fsummary>Print node uptime.</fsummary> <desc> <p>Prints the node uptime (as specified by @@ -310,7 +310,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w </func> <func> - <name>xm(ModSpec) -> void()</name> + <name since="">xm(ModSpec) -> void()</name> <fsummary>Cross-reference check a module.</fsummary> <type> <v>ModSpec = Module | Filename</v> @@ -325,7 +325,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w </func> <func> - <name>y(File) -> YeccRet</name> + <name since="">y(File) -> YeccRet</name> <fsummary>Generate an LALR-1 parser.</fsummary> <type> <v>File = name()</v> @@ -344,7 +344,7 @@ yecc:file(File)</code> </func> <func> - <name>y(File, Options) -> YeccRet</name> + <name since="">y(File, Options) -> YeccRet</name> <fsummary>Generate an LALR-1 parser.</fsummary> <type> <v>File = name()</v> diff --git a/lib/stdlib/doc/src/calendar.xml b/lib/stdlib/doc/src/calendar.xml index 5aee635c38..518a085c89 100644 --- a/lib/stdlib/doc/src/calendar.xml +++ b/lib/stdlib/doc/src/calendar.xml @@ -28,7 +28,7 @@ <date>1996-11-05</date> <rev>B</rev> </header> - <module>calendar</module> + <module since="">calendar</module> <modulesummary>Local and universal time, day of the week, date and time conversions.</modulesummary> <description> @@ -128,8 +128,8 @@ <funcs> <func> - <name name="date_to_gregorian_days" arity="1"/> - <name name="date_to_gregorian_days" arity="3"/> + <name name="date_to_gregorian_days" arity="1" since=""/> + <name name="date_to_gregorian_days" arity="3" since=""/> <fsummary>Compute the number of days from year 0 up to the specified date.</fsummary> <type variable="Date" name_i="1"/> @@ -143,7 +143,7 @@ </func> <func> - <name name="datetime_to_gregorian_seconds" arity="1"/> + <name name="datetime_to_gregorian_seconds" arity="1" since=""/> <fsummary>Compute the number of seconds from year 0 up to the specified date and time.</fsummary> <desc> @@ -153,8 +153,8 @@ </func> <func> - <name name="day_of_the_week" arity="1"/> - <name name="day_of_the_week" arity="3"/> + <name name="day_of_the_week" arity="1" since=""/> + <name name="day_of_the_week" arity="3" since=""/> <fsummary>Compute the day of the week.</fsummary> <type variable="Date" name_i="1"/> <type variable="Year"/> @@ -169,7 +169,7 @@ </func> <func> - <name name="gregorian_days_to_date" arity="1"/> + <name name="gregorian_days_to_date" arity="1" since=""/> <fsummary>Compute the date from the number of gregorian days.</fsummary> <desc> <p>Computes the date from the specified number of gregorian days.</p> @@ -177,7 +177,7 @@ </func> <func> - <name name="gregorian_seconds_to_datetime" arity="1"/> + <name name="gregorian_seconds_to_datetime" arity="1" since=""/> <fsummary>Compute the date and time from the number of gregorian seconds. </fsummary> <desc> @@ -187,7 +187,7 @@ </func> <func> - <name name="is_leap_year" arity="1"/> + <name name="is_leap_year" arity="1" since=""/> <fsummary>Check if the year is a leap year.</fsummary> <desc> <p>Checks if the specified year is a leap year.</p> @@ -195,7 +195,7 @@ </func> <func> - <name name="iso_week_number" arity="0"/> + <name name="iso_week_number" arity="0" since="OTP R14B02"/> <fsummary>Compute the ISO week number for the actual date.</fsummary> <desc> <p>Returns tuple <c>{Year, WeekNum}</c> representing @@ -206,7 +206,7 @@ </func> <func> - <name name="iso_week_number" arity="1"/> + <name name="iso_week_number" arity="1" since="OTP R14B02"/> <fsummary>Compute the ISO week number for the specified date.</fsummary> <desc> <p>Returns tuple <c>{Year, WeekNum}</c> representing @@ -215,7 +215,7 @@ </func> <func> - <name name="last_day_of_the_month" arity="2"/> + <name name="last_day_of_the_month" arity="2" since=""/> <fsummary>Compute the number of days in a month.</fsummary> <desc> <p>Computes the number of days in a month.</p> @@ -223,7 +223,7 @@ </func> <func> - <name name="local_time" arity="0"/> + <name name="local_time" arity="0" since=""/> <fsummary>Compute local time.</fsummary> <desc> <p>Returns the local time reported by @@ -232,7 +232,7 @@ </func> <func> - <name name="local_time_to_universal_time" arity="1"/> + <name name="local_time_to_universal_time" arity="1" since=""/> <fsummary>Convert from local time to universal time (deprecated). </fsummary> <desc> @@ -253,7 +253,7 @@ </func> <func> - <name name="local_time_to_universal_time_dst" arity="1"/> + <name name="local_time_to_universal_time_dst" arity="1" since=""/> <fsummary>Convert from local time to universal time(s).</fsummary> <desc> <p>Converts from local time to Universal Coordinated Time (UTC). @@ -285,7 +285,7 @@ </func> <func> - <name name="now_to_datetime" arity="1"/> + <name name="now_to_datetime" arity="1" since=""/> <fsummary>Convert now to date and time.</fsummary> <desc> <p>Returns Universal Coordinated Time (UTC) @@ -296,7 +296,7 @@ </func> <func> - <name name="now_to_local_time" arity="1"/> + <name name="now_to_local_time" arity="1" since=""/> <fsummary>Convert now to local date and time.</fsummary> <desc> <p>Returns local date and time converted from the return value from @@ -306,7 +306,7 @@ </func> <func> - <name name="now_to_universal_time" arity="1"/> + <name name="now_to_universal_time" arity="1" since=""/> <fsummary>Convert now to date and time.</fsummary> <desc> <p>Returns Universal Coordinated Time (UTC) @@ -317,8 +317,8 @@ </func> <func> - <name name="rfc3339_to_system_time" arity="1"/> - <name name="rfc3339_to_system_time" arity="2"/> + <name name="rfc3339_to_system_time" arity="1" since="OTP 21.0"/> + <name name="rfc3339_to_system_time" arity="2" since="OTP 21.0"/> <fsummary>Convert from RFC 3339 timestamp to system time.</fsummary> <type name="rfc3339_string"/> <type name="rfc3339_time_unit"/> @@ -343,7 +343,7 @@ </func> <func> - <name name="seconds_to_daystime" arity="1"/> + <name name="seconds_to_daystime" arity="1" since=""/> <fsummary>Compute days and time from seconds.</fsummary> <desc> <p>Converts a specified number of seconds into days, hours, minutes, @@ -354,7 +354,7 @@ </func> <func> - <name name="seconds_to_time" arity="1"/> + <name name="seconds_to_time" arity="1" since=""/> <fsummary>Compute time from seconds.</fsummary> <type name="secs_per_day"/> <desc> @@ -365,7 +365,7 @@ </func> <func> - <name name="system_time_to_local_time" arity="2"/> + <name name="system_time_to_local_time" arity="2" since="OTP 21.0"/> <fsummary>Convert system time to local date and time.</fsummary> <desc> <p>Converts a specified system time into local date and time.</p> @@ -373,8 +373,8 @@ </func> <func> - <name name="system_time_to_rfc3339" arity="1"/> - <name name="system_time_to_rfc3339" arity="2"/> + <name name="system_time_to_rfc3339" arity="1" since="OTP 21.0"/> + <name name="system_time_to_rfc3339" arity="2" since="OTP 21.0"/> <fsummary>Convert from system to RFC 3339 timestamp.</fsummary> <type name="offset"/> <type name="rfc3339_string"/> @@ -426,7 +426,7 @@ </func> <func> - <name name="system_time_to_universal_time" arity="2"/> + <name name="system_time_to_universal_time" arity="2" since="OTP 21.0"/> <fsummary>Convert system time to universal date and time.</fsummary> <desc> <p>Converts a specified system time into universal date and time.</p> @@ -434,7 +434,7 @@ </func> <func> - <name name="time_difference" arity="2"/> + <name name="time_difference" arity="2" since=""/> <fsummary>Compute the difference between two times (deprecated). </fsummary> <desc> @@ -449,7 +449,7 @@ </func> <func> - <name name="time_to_seconds" arity="1"/> + <name name="time_to_seconds" arity="1" since=""/> <fsummary>Compute the number of seconds since midnight up to the specified time.</fsummary> <type name="secs_per_day"/> @@ -460,7 +460,7 @@ </func> <func> - <name name="universal_time" arity="0"/> + <name name="universal_time" arity="0" since=""/> <fsummary>Compute universal time.</fsummary> <desc> <p>Returns the Universal Coordinated Time (UTC) @@ -470,7 +470,7 @@ </func> <func> - <name name="universal_time_to_local_time" arity="1"/> + <name name="universal_time_to_local_time" arity="1" since=""/> <fsummary>Convert from universal time to local time.</fsummary> <desc> <p>Converts from Universal Coordinated Time (UTC) to local time. @@ -480,8 +480,8 @@ </func> <func> - <name name="valid_date" arity="1"/> - <name name="valid_date" arity="3"/> + <name name="valid_date" arity="1" since=""/> + <name name="valid_date" arity="3" since=""/> <fsummary>Check if a date is valid</fsummary> <type variable="Date" name_i="1"/> <type variable="Year"/> diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml index eb6e32aecf..8e4e002000 100644 --- a/lib/stdlib/doc/src/dets.xml +++ b/lib/stdlib/doc/src/dets.xml @@ -32,7 +32,7 @@ <rev>B</rev> <file>dets.xml</file> </header> - <module>dets</module> + <module since="">dets</module> <modulesummary>A disk-based term storage.</modulesummary> <description> <p>This module provides a term storage on file. The @@ -188,7 +188,7 @@ <funcs> <func> - <name name="all" arity="0"/> + <name name="all" arity="0" since=""/> <fsummary>Return a list of the names of all open Dets tables on this node.</fsummary> <desc> @@ -197,7 +197,7 @@ </func> <func> - <name name="bchunk" arity="2"/> + <name name="bchunk" arity="2" since=""/> <fsummary>Return a chunk of objects stored in a Dets table. </fsummary> <desc> @@ -227,7 +227,7 @@ </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a Dets table.</fsummary> <desc> <p>Closes a table. Only processes that have opened a table are @@ -239,7 +239,7 @@ </func> <func> - <name name="delete" arity="2"/> + <name name="delete" arity="2" since=""/> <fsummary>Delete all objects with a specified key from a Dets table.</fsummary> <desc> @@ -249,7 +249,7 @@ </func> <func> - <name name="delete_all_objects" arity="1"/> + <name name="delete_all_objects" arity="1" since=""/> <fsummary>Delete all objects from a Dets table.</fsummary> <desc> <p>Deletes all objects from a table in almost constant time. @@ -259,7 +259,7 @@ </func> <func> - <name name="delete_object" arity="2"/> + <name name="delete_object" arity="2" since=""/> <fsummary>Delete a specified object from a Dets table.</fsummary> <desc> <p>Deletes all instances of a specified object from a table. If a @@ -270,7 +270,7 @@ </func> <func> - <name name="first" arity="1"/> + <name name="first" arity="1" since=""/> <fsummary>Return the first key stored in a Dets table.</fsummary> <desc> <p>Returns the first key stored in table <c><anno>Name</anno></c> @@ -295,8 +295,8 @@ </func> <func> - <name name="foldl" arity="3"/> - <name name="foldr" arity="3"/> + <name name="foldl" arity="3" since=""/> + <name name="foldr" arity="3" since=""/> <fsummary>Fold a function over a Dets table.</fsummary> <desc> <p>Calls <c><anno>Function</anno></c> on successive elements of @@ -309,7 +309,7 @@ </func> <func> - <name name="from_ets" arity="2"/> + <name name="from_ets" arity="2" since=""/> <fsummary>Replace the objects of a Dets table with the objects of an ETS table.</fsummary> <desc> @@ -322,7 +322,7 @@ </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since=""/> <fsummary>Return information about a Dets table.</fsummary> <desc> <p>Returns information about table <c><anno>Name</anno></c> @@ -354,7 +354,7 @@ </func> <func> - <name name="info" arity="2"/> + <name name="info" arity="2" since=""/> <fsummary>Return the information associated with a specified item for a Dets table.</fsummary> <desc> @@ -455,8 +455,8 @@ </func> <func> - <name name="init_table" arity="2"/> - <name name="init_table" arity="3"/> + <name name="init_table" arity="2" since=""/> + <name name="init_table" arity="3" since=""/> <fsummary>Replace all objects of a Dets table.</fsummary> <desc> <p>Replaces the existing objects of table <c><anno>Name</anno></c> @@ -516,7 +516,7 @@ </func> <func> - <name name="insert" arity="2"/> + <name name="insert" arity="2" since=""/> <fsummary>Insert one or more objects into a Dets table.</fsummary> <desc> <p>Inserts one or more objects into the table <c><anno>Name</anno></c>. @@ -527,7 +527,7 @@ </func> <func> - <name name="insert_new" arity="2"/> + <name name="insert_new" arity="2" since=""/> <fsummary>Insert one or more objects into a Dets table.</fsummary> <desc> <p>Inserts one or more objects into table <c><anno>Name</anno></c>. @@ -539,7 +539,7 @@ </func> <func> - <name name="is_compatible_bchunk_format" arity="2"/> + <name name="is_compatible_bchunk_format" arity="2" since=""/> <fsummary>Test compatibility of chunk data of a table.</fsummary> <desc> <p>Returns <c>true</c> if it would be possible to initialize @@ -554,7 +554,7 @@ </func> <func> - <name name="is_dets_file" arity="1"/> + <name name="is_dets_file" arity="1" since=""/> <fsummary>Test for a Dets table.</fsummary> <desc> <p>Returns <c>true</c> if file <c><anno>Filename</anno></c> @@ -563,7 +563,7 @@ </func> <func> - <name name="lookup" arity="2"/> + <name name="lookup" arity="2" since=""/> <fsummary>Return all objects with a specified key stored in a Dets table.</fsummary> <desc> @@ -590,7 +590,7 @@ ok </func> <func> - <name name="match" arity="1"/> + <name name="match" arity="1" since=""/> <fsummary>Match a chunk of objects stored in a Dets table and return a list of variable bindings.</fsummary> <desc> @@ -606,7 +606,7 @@ ok </func> <func> - <name name="match" arity="2"/> + <name name="match" arity="2" since=""/> <fsummary>Match the objects stored in a Dets table and return a list of variable bindings.</fsummary> <desc> @@ -622,7 +622,7 @@ ok </func> <func> - <name name="match" arity="3"/> + <name name="match" arity="3" since=""/> <fsummary>Match the first chunk of objects stored in a Dets table and return a list of variable bindings.</fsummary> <desc> @@ -654,7 +654,7 @@ ok </func> <func> - <name name="match_delete" arity="2"/> + <name name="match_delete" arity="2" since=""/> <fsummary>Delete all objects that match a given pattern from a Dets table.</fsummary> <desc> @@ -667,7 +667,7 @@ ok </func> <func> - <name name="match_object" arity="1"/> + <name name="match_object" arity="1" since=""/> <fsummary>Match a chunk of objects stored in a Dets table and return a list of objects.</fsummary> <desc> @@ -683,7 +683,7 @@ ok </func> <func> - <name name="match_object" arity="2"/> + <name name="match_object" arity="2" since=""/> <fsummary>Match the objects stored in a Dets table and return a list of objects.</fsummary> <desc> @@ -702,7 +702,7 @@ ok </func> <func> - <name name="match_object" arity="3"/> + <name name="match_object" arity="3" since=""/> <fsummary>Match the first chunk of objects stored in a Dets table and return a list of objects.</fsummary> <desc> @@ -735,7 +735,7 @@ ok </func> <func> - <name name="member" arity="2"/> + <name name="member" arity="2" since=""/> <fsummary>Test for occurrence of a key in a Dets table.</fsummary> <desc> <p>Works like <seealso marker="#lookup/2"><c>lookup/2</c></seealso>, @@ -746,7 +746,7 @@ ok </func> <func> - <name name="next" arity="2"/> + <name name="next" arity="2" since=""/> <fsummary>Return the next key in a Dets table.</fsummary> <desc> <p>Returns either the key following <c><anno>Key1</anno></c> in table @@ -760,7 +760,7 @@ ok </func> <func> - <name name="open_file" arity="1"/> + <name name="open_file" arity="1" since=""/> <fsummary>Open an existing Dets table.</fsummary> <desc> <p>Opens an existing table. If the table is not properly closed, @@ -770,7 +770,7 @@ ok </func> <func> - <name name="open_file" arity="2"/> + <name name="open_file" arity="2" since=""/> <fsummary>Open a Dets table.</fsummary> <desc> <p>Opens a table. An empty Dets table is created if no file @@ -872,7 +872,7 @@ ok </func> <func> - <name name="pid2name" arity="1"/> + <name name="pid2name" arity="1" since=""/> <fsummary>Return the name of the Dets table handled by a pid.</fsummary> <desc> <p>Returns the table name given the pid of a process @@ -883,7 +883,7 @@ ok </func> <func> - <name name="repair_continuation" arity="2"/> + <name name="repair_continuation" arity="2" since=""/> <fsummary>Repair a continuation from <c>select/1</c> or <c>select/3</c>. </fsummary> <desc> @@ -917,7 +917,7 @@ ok </func> <func> - <name name="safe_fixtable" arity="2"/> + <name name="safe_fixtable" arity="2" since=""/> <fsummary>Fix a Dets table for safe traversal.</fsummary> <desc> <p>If <c><anno>Fix</anno></c> is <c>true</c>, table @@ -945,7 +945,7 @@ ok </func> <func> - <name name="select" arity="1"/> + <name name="select" arity="1" since=""/> <fsummary>Apply a match specification to some objects stored in a Dets table.</fsummary> <desc> @@ -962,7 +962,7 @@ ok </func> <func> - <name name="select" arity="2"/> + <name name="select" arity="2" since=""/> <fsummary>Apply a match specification to all objects stored in a Dets table.</fsummary> <desc> @@ -984,7 +984,7 @@ ok </func> <func> - <name name="select" arity="3"/> + <name name="select" arity="3" since=""/> <fsummary>Apply a match specification to the first chunk of objects stored in a Dets table.</fsummary> <desc> @@ -1019,7 +1019,7 @@ ok </func> <func> - <name name="select_delete" arity="2"/> + <name name="select_delete" arity="2" since=""/> <fsummary>Delete all objects that match a given pattern from a Dets table.</fsummary> <desc> @@ -1036,7 +1036,7 @@ ok </func> <func> - <name name="slot" arity="2"/> + <name name="slot" arity="2" since=""/> <fsummary>Return the list of objects associated with a slot of a Dets table.</fsummary> <desc> @@ -1049,7 +1049,7 @@ ok </func> <func> - <name name="sync" arity="1"/> + <name name="sync" arity="1" since=""/> <fsummary>Ensure that all updates made to a Dets table are written to disk.</fsummary> <desc> @@ -1064,8 +1064,8 @@ ok </func> <func> - <name name="table" arity="1"/> - <name name="table" arity="2"/> + <name name="table" arity="1" since=""/> + <name name="table" arity="2" since=""/> <fsummary>Return a QLC query handle.</fsummary> <desc> <p>Returns a Query List @@ -1140,7 +1140,7 @@ true</pre> </func> <func> - <name name="to_ets" arity="2"/> + <name name="to_ets" arity="2" since=""/> <fsummary>Insert all objects of a Dets table into an ETS table.</fsummary> <desc> @@ -1153,7 +1153,7 @@ true</pre> </func> <func> - <name name="traverse" arity="2"/> + <name name="traverse" arity="2" since=""/> <fsummary>Apply a function to all or some objects stored in a Dets table.</fsummary> <desc> @@ -1192,7 +1192,7 @@ fun(X) -> {continue, X} end.</pre> </func> <func> - <name name="update_counter" arity="3"/> + <name name="update_counter" arity="3" since=""/> <fsummary>Update a counter object stored in a Dets table. </fsummary> <desc> diff --git a/lib/stdlib/doc/src/dict.xml b/lib/stdlib/doc/src/dict.xml index c229a18721..95a98cef12 100644 --- a/lib/stdlib/doc/src/dict.xml +++ b/lib/stdlib/doc/src/dict.xml @@ -28,7 +28,7 @@ <date>1997-01-15</date> <rev>B</rev> </header> - <module>dict</module> + <module since="">dict</module> <modulesummary>Key-value dictionary.</modulesummary> <description> <p>This module provides a <c>Key</c>-<c>Value</c> dictionary. @@ -55,7 +55,7 @@ <funcs> <func> - <name name="append" arity="3"/> + <name name="append" arity="3" since=""/> <fsummary>Append a value to keys in a dictionary.</fsummary> <desc> <p>Appends a new <c><anno>Value</anno></c> to the current list @@ -65,7 +65,7 @@ </func> <func> - <name name="append_list" arity="3"/> + <name name="append_list" arity="3" since=""/> <fsummary>Append new values to keys in a dictionary.</fsummary> <desc> <p>Appends a list of values <c><anno>ValList</anno></c> to @@ -77,7 +77,7 @@ </func> <func> - <name name="erase" arity="2"/> + <name name="erase" arity="2" since=""/> <fsummary>Erase a key from a dictionary.</fsummary> <desc> <p>Erases all items with a given key from a dictionary.</p> @@ -85,7 +85,7 @@ </func> <func> - <name name="fetch" arity="2"/> + <name name="fetch" arity="2" since=""/> <fsummary>Look up values in a dictionary.</fsummary> <desc> <p>Returns the value associated with <c><anno>Key</anno></c> @@ -98,7 +98,7 @@ </func> <func> - <name name="fetch_keys" arity="1"/> + <name name="fetch_keys" arity="1" since=""/> <fsummary>Return all keys in a dictionary.</fsummary> <desc> <p>Returns a list of all keys in dictionary <c>Dict</c>.</p> @@ -106,7 +106,7 @@ </func> <func> - <name name="take" arity="2"/> + <name name="take" arity="2" since="OTP 20.0"/> <fsummary>Return value and new dictionary without element with this value.</fsummary> <desc> <p>This function returns value from dictionary and a @@ -116,7 +116,7 @@ </func> <func> - <name name="filter" arity="2"/> + <name name="filter" arity="2" since=""/> <fsummary>Select elements that satisfy a predicate.</fsummary> <desc> <p><c><anno>Dict2</anno></c> is a dictionary of all keys and values in @@ -127,7 +127,7 @@ </func> <func> - <name name="find" arity="2"/> + <name name="find" arity="2" since=""/> <fsummary>Search for a key in a dictionary.</fsummary> <desc> <p>Searches for a key in dictionary <c>Dict</c>. Returns @@ -139,7 +139,7 @@ </func> <func> - <name name="fold" arity="3"/> + <name name="fold" arity="3" since=""/> <fsummary>Fold a function over a dictionary.</fsummary> <desc> <p>Calls <c><anno>Fun</anno></c> on successive keys and values of @@ -153,7 +153,7 @@ </func> <func> - <name name="from_list" arity="1"/> + <name name="from_list" arity="1" since=""/> <fsummary>Convert a list of pairs to a dictionary.</fsummary> <desc> <p>Converts the <c><anno>Key</anno></c>-<c><anno>Value</anno></c> list @@ -162,7 +162,7 @@ </func> <func> - <name name="is_empty" arity="1"/> + <name name="is_empty" arity="1" since="OTP 17.0"/> <fsummary>Return <c>true</c> if the dictionary is empty.</fsummary> <desc> <p>Returns <c>true</c> if dictionary <c><anno>Dict</anno></c> has no @@ -171,7 +171,7 @@ </func> <func> - <name name="is_key" arity="2"/> + <name name="is_key" arity="2" since=""/> <fsummary>Test if a key is in a dictionary.</fsummary> <desc> <p>Tests if <c><anno>Key</anno></c> is contained in @@ -180,7 +180,7 @@ </func> <func> - <name name="map" arity="2"/> + <name name="map" arity="2" since=""/> <fsummary>Map a function over a dictionary.</fsummary> <desc> <p>Calls <c><anno>Fun</anno></c> on successive keys and values @@ -190,7 +190,7 @@ </func> <func> - <name name="merge" arity="3"/> + <name name="merge" arity="3" since=""/> <fsummary>Merge two dictionaries.</fsummary> <desc> <p>Merges two dictionaries, <c><anno>Dict1</anno></c> and @@ -209,7 +209,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="new" arity="0"/> + <name name="new" arity="0" since=""/> <fsummary>Create a dictionary.</fsummary> <desc> <p>Creates a new dictionary.</p> @@ -217,7 +217,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="size" arity="1"/> + <name name="size" arity="1" since=""/> <fsummary>Return the number of elements in a dictionary.</fsummary> <desc> <p>Returns the number of elements in dictionary @@ -226,7 +226,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="store" arity="3"/> + <name name="store" arity="3" since=""/> <fsummary>Store a value in a dictionary.</fsummary> <desc> <p>Stores a <c><anno>Key</anno></c>-<c><anno>Value</anno></c> pair in @@ -237,7 +237,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="to_list" arity="1"/> + <name name="to_list" arity="1" since=""/> <fsummary>Convert a dictionary to a list of pairs.</fsummary> <desc> <p>Converts dictionary <c>Dict</c> to a list representation.</p> @@ -245,7 +245,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="update" arity="3"/> + <name name="update" arity="3" since=""/> <fsummary>Update a value in a dictionary.</fsummary> <desc> <p>Updates a value in a dictionary by calling <c><anno>Fun</anno></c> on @@ -255,7 +255,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="update" arity="4"/> + <name name="update" arity="4" since=""/> <fsummary>Update a value in a dictionary.</fsummary> <desc> <p>Updates a value in a dictionary by calling <c><anno>Fun</anno></c> on @@ -269,7 +269,7 @@ append(Key, Val, D) -> </func> <func> - <name name="update_counter" arity="3"/> + <name name="update_counter" arity="3" since=""/> <fsummary>Increment a value in a dictionary.</fsummary> <desc> <p>Adds <c><anno>Increment</anno></c> to the value associated with diff --git a/lib/stdlib/doc/src/digraph.xml b/lib/stdlib/doc/src/digraph.xml index a5252b443b..cf2c0844c9 100644 --- a/lib/stdlib/doc/src/digraph.xml +++ b/lib/stdlib/doc/src/digraph.xml @@ -32,7 +32,7 @@ <rev>C</rev> <file>digraph.xml</file> </header> - <module>digraph</module> + <module since="">digraph</module> <modulesummary>Directed graphs.</modulesummary> <description> <p>This module provides a version of labeled @@ -144,9 +144,9 @@ <funcs> <func> - <name name="add_edge" arity="3"/> - <name name="add_edge" arity="4"/> - <name name="add_edge" arity="5"/> + <name name="add_edge" arity="3" since=""/> + <name name="add_edge" arity="4" since=""/> + <name name="add_edge" arity="5" since=""/> <fsummary>Add an edge to a digraph.</fsummary> <type name="add_edge_err_rsn"/> <desc> @@ -183,9 +183,9 @@ </func> <func> - <name name="add_vertex" arity="1"/> - <name name="add_vertex" arity="2"/> - <name name="add_vertex" arity="3"/> + <name name="add_vertex" arity="1" since=""/> + <name name="add_vertex" arity="2" since=""/> + <name name="add_vertex" arity="3" since=""/> <fsummary>Add or modify a vertex of a digraph.</fsummary> <desc> <p><c>add_vertex/3</c> creates (or modifies) vertex @@ -204,7 +204,7 @@ </func> <func> - <name name="del_edge" arity="2"/> + <name name="del_edge" arity="2" since=""/> <fsummary>Delete an edge from a digraph.</fsummary> <desc> <p>Deletes edge <c><anno>E</anno></c> from digraph @@ -213,7 +213,7 @@ </func> <func> - <name name="del_edges" arity="2"/> + <name name="del_edges" arity="2" since=""/> <fsummary>Delete edges from a digraph.</fsummary> <desc> <p>Deletes the edges in list <c><anno>Edges</anno></c> from digraph @@ -222,7 +222,7 @@ </func> <func> - <name name="del_path" arity="3"/> + <name name="del_path" arity="3" since=""/> <fsummary>Delete paths from a digraph.</fsummary> <desc> <p>Deletes edges from digraph <c><anno>G</anno></c> until there are no @@ -252,7 +252,7 @@ </func> <func> - <name name="del_vertex" arity="2"/> + <name name="del_vertex" arity="2" since=""/> <fsummary>Delete a vertex from a digraph.</fsummary> <desc> <p>Deletes vertex <c><anno>V</anno></c> from digraph @@ -265,7 +265,7 @@ </func> <func> - <name name="del_vertices" arity="2"/> + <name name="del_vertices" arity="2" since=""/> <fsummary>Delete vertices from a digraph.</fsummary> <desc> <p>Deletes the vertices in list <c><anno>Vertices</anno></c> from @@ -274,7 +274,7 @@ </func> <func> - <name name="delete" arity="1"/> + <name name="delete" arity="1" since=""/> <fsummary>Delete a digraph.</fsummary> <desc> <p>Deletes digraph <c><anno>G</anno></c>. This call is important @@ -285,7 +285,7 @@ </func> <func> - <name name="edge" arity="2"/> + <name name="edge" arity="2" since=""/> <fsummary>Return the vertices and the label of an edge of a digraph. </fsummary> <desc> @@ -303,7 +303,7 @@ </func> <func> - <name name="edges" arity="1"/> + <name name="edges" arity="1" since=""/> <fsummary>Return all edges of a digraph.</fsummary> <desc> <p>Returns a list of all edges of digraph <c><anno>G</anno></c>, in @@ -312,7 +312,7 @@ </func> <func> - <name name="edges" arity="2"/> + <name name="edges" arity="2" since=""/> <fsummary>Return the edges emanating from or incident on a vertex of a digraph.</fsummary> <desc> @@ -324,7 +324,7 @@ </func> <func> - <name name="get_cycle" arity="2"/> + <name name="get_cycle" arity="2" since=""/> <fsummary>Find one cycle in a digraph.</fsummary> <desc> <p>If a <seealso marker="#simple_cycle">simple cycle</seealso> of @@ -341,7 +341,7 @@ </func> <func> - <name name="get_path" arity="3"/> + <name name="get_path" arity="3" since=""/> <fsummary>Find one path in a digraph.</fsummary> <desc> <p>Tries to find @@ -357,7 +357,7 @@ </func> <func> - <name name="get_short_cycle" arity="2"/> + <name name="get_short_cycle" arity="2" since=""/> <fsummary>Find one short cycle in a digraph.</fsummary> <desc> <p>Tries to find an as short as possible @@ -375,7 +375,7 @@ </func> <func> - <name name="get_short_path" arity="3"/> + <name name="get_short_path" arity="3" since=""/> <fsummary>Find one short path in a digraph.</fsummary> <desc> <p>Tries to find an as short as possible @@ -392,7 +392,7 @@ </func> <func> - <name name="in_degree" arity="2"/> + <name name="in_degree" arity="2" since=""/> <fsummary>Return the in-degree of a vertex of a digraph.</fsummary> <desc> <p>Returns the <seealso marker="#in_degree">in-degree</seealso> of @@ -401,7 +401,7 @@ </func> <func> - <name name="in_edges" arity="2"/> + <name name="in_edges" arity="2" since=""/> <fsummary>Return all edges incident on a vertex of a digraph.</fsummary> <desc> <p>Returns a list of all @@ -412,7 +412,7 @@ </func> <func> - <name name="in_neighbours" arity="2"/> + <name name="in_neighbours" arity="2" since=""/> <fsummary>Return all in-neighbors of a vertex of a digraph.</fsummary> <desc> <p>Returns a list of @@ -423,7 +423,7 @@ </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since=""/> <fsummary>Return information about a digraph.</fsummary> <type name="d_cyclicity"/> <type name="d_protection"/> @@ -453,7 +453,7 @@ </func> <func> - <name name="new" arity="0"/> + <name name="new" arity="0" since=""/> <fsummary>Return a protected empty digraph, where cycles are allowed. </fsummary> <desc> @@ -462,7 +462,7 @@ </func> <func> - <name name="new" arity="1"/> + <name name="new" arity="1" since=""/> <fsummary>Create a new empty digraph.</fsummary> <type variable="Type"/> <type name="d_type"/> @@ -492,7 +492,7 @@ </func> <func> - <name name="no_edges" arity="1"/> + <name name="no_edges" arity="1" since=""/> <fsummary>Return the number of edges of a digraph.</fsummary> <desc> <p>Returns the number of edges of digraph <c><anno>G</anno></c>.</p> @@ -500,7 +500,7 @@ </func> <func> - <name name="no_vertices" arity="1"/> + <name name="no_vertices" arity="1" since=""/> <fsummary>Return the number of vertices of a digraph.</fsummary> <desc> <p>Returns the number of vertices of digraph <c><anno>G</anno></c>.</p> @@ -508,7 +508,7 @@ </func> <func> - <name name="out_degree" arity="2"/> + <name name="out_degree" arity="2" since=""/> <fsummary>Return the out-degree of a vertex of a digraph.</fsummary> <desc> <p>Returns the <seealso marker="#out_degree">out-degree</seealso> of @@ -517,7 +517,7 @@ </func> <func> - <name name="out_edges" arity="2"/> + <name name="out_edges" arity="2" since=""/> <fsummary>Return all edges emanating from a vertex of a digraph. </fsummary> <desc> @@ -529,7 +529,7 @@ </func> <func> - <name name="out_neighbours" arity="2"/> + <name name="out_neighbours" arity="2" since=""/> <fsummary>Return all out-neighbors of a vertex of a digraph.</fsummary> <desc> <p>Returns a list of @@ -540,7 +540,7 @@ </func> <func> - <name name="vertex" arity="2"/> + <name name="vertex" arity="2" since=""/> <fsummary>Return the label of a vertex of a digraph.</fsummary> <desc> <p>Returns <c>{<anno>V</anno>, <anno>Label</anno>}</c>, @@ -553,7 +553,7 @@ </func> <func> - <name name="vertices" arity="1"/> + <name name="vertices" arity="1" since=""/> <fsummary>Return all vertices of a digraph.</fsummary> <desc> <p>Returns a list of all vertices of digraph <c><anno>G</anno></c>, in diff --git a/lib/stdlib/doc/src/digraph_utils.xml b/lib/stdlib/doc/src/digraph_utils.xml index cb316e5b93..13b0aaad9e 100644 --- a/lib/stdlib/doc/src/digraph_utils.xml +++ b/lib/stdlib/doc/src/digraph_utils.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>digraph_utils.xml</file> </header> - <module>digraph_utils</module> + <module since="">digraph_utils</module> <modulesummary>Algorithms for directed graphs.</modulesummary> <description> <p>This module provides algorithms based on depth-first traversal of @@ -154,7 +154,7 @@ <funcs> <func> - <name name="arborescence_root" arity="1"/> + <name name="arborescence_root" arity="1" since=""/> <fsummary>Check if a digraph is an arborescence.</fsummary> <desc> <p>Returns <c>{yes, <anno>Root</anno>}</c> if <c><anno>Root</anno></c> @@ -164,7 +164,7 @@ </func> <func> - <name name="components" arity="1"/> + <name name="components" arity="1" since=""/> <fsummary>Return the components of a digraph.</fsummary> <desc> <p>Returns a list @@ -177,7 +177,7 @@ </func> <func> - <name name="condensation" arity="1"/> + <name name="condensation" arity="1" since=""/> <fsummary>Return a condensed graph of a digraph.</fsummary> <desc> <p>Creates a digraph where the vertices are @@ -202,7 +202,7 @@ </func> <func> - <name name="cyclic_strong_components" arity="1"/> + <name name="cyclic_strong_components" arity="1" since=""/> <fsummary>Return the cyclic strong components of a digraph.</fsummary> <desc> <p>Returns a list of <seealso marker="#strong_components">strongly @@ -218,7 +218,7 @@ </func> <func> - <name name="is_acyclic" arity="1"/> + <name name="is_acyclic" arity="1" since=""/> <fsummary>Check if a digraph is acyclic.</fsummary> <desc> <p>Returns <c>true</c> if and only if digraph @@ -228,7 +228,7 @@ </func> <func> - <name name="is_arborescence" arity="1"/> + <name name="is_arborescence" arity="1" since=""/> <fsummary>Check if a digraph is an arborescence.</fsummary> <desc> <p>Returns <c>true</c> if and only if digraph @@ -238,7 +238,7 @@ </func> <func> - <name name="is_tree" arity="1"/> + <name name="is_tree" arity="1" since=""/> <fsummary>Check if a digraph is a tree.</fsummary> <desc> <p>Returns <c>true</c> if and only if digraph @@ -248,7 +248,7 @@ </func> <func> - <name name="loop_vertices" arity="1"/> + <name name="loop_vertices" arity="1" since=""/> <fsummary>Return the vertices of a digraph included in some loop. </fsummary> <desc> @@ -258,7 +258,7 @@ </func> <func> - <name name="postorder" arity="1"/> + <name name="postorder" arity="1" since=""/> <fsummary>Return the vertices of a digraph in postorder.</fsummary> <desc> <p>Returns all vertices of digraph <c><anno>Digraph</anno></c>. @@ -273,7 +273,7 @@ </func> <func> - <name name="preorder" arity="1"/> + <name name="preorder" arity="1" since=""/> <fsummary>Return the vertices of a digraph in preorder.</fsummary> <desc> <p>Returns all vertices of digraph <c><anno>Digraph</anno></c>. @@ -285,7 +285,7 @@ </func> <func> - <name name="reachable" arity="2"/> + <name name="reachable" arity="2" since=""/> <fsummary>Return the vertices reachable from some vertices of a digraph. </fsummary> <desc> @@ -300,7 +300,7 @@ </func> <func> - <name name="reachable_neighbours" arity="2"/> + <name name="reachable_neighbours" arity="2" since=""/> <fsummary>Return the neighbors reachable from some vertices of a digraph.</fsummary> <desc> @@ -316,7 +316,7 @@ </func> <func> - <name name="reaching" arity="2"/> + <name name="reaching" arity="2" since=""/> <fsummary>Return the vertices that reach some vertices of a digraph. </fsummary> <desc> @@ -330,7 +330,7 @@ </func> <func> - <name name="reaching_neighbours" arity="2"/> + <name name="reaching_neighbours" arity="2" since=""/> <fsummary>Return the neighbors that reach some vertices of a digraph. </fsummary> <desc> @@ -345,7 +345,7 @@ </func> <func> - <name name="strong_components" arity="1"/> + <name name="strong_components" arity="1" since=""/> <fsummary>Return the strong components of a digraph.</fsummary> <desc> <p>Returns a list of <seealso marker="#strong_components">strongly @@ -359,8 +359,8 @@ </func> <func> - <name name="subgraph" arity="2"/> - <name name="subgraph" arity="3"/> + <name name="subgraph" arity="2" since=""/> + <name name="subgraph" arity="3" since=""/> <fsummary>Return a subgraph of a digraph.</fsummary> <desc> <p>Creates a maximal <seealso marker="#subgraph">subgraph</seealso> @@ -387,7 +387,7 @@ </func> <func> - <name name="topsort" arity="1"/> + <name name="topsort" arity="1" since=""/> <fsummary>Return a topological sorting of the vertices of a digraph. </fsummary> <desc> diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml index d803d259aa..110c1cea2c 100644 --- a/lib/stdlib/doc/src/epp.xml +++ b/lib/stdlib/doc/src/epp.xml @@ -32,7 +32,7 @@ <rev>B</rev> <file>epp.xml</file> </header> - <module>epp</module> + <module since="">epp</module> <modulesummary>An Erlang code preprocessor.</modulesummary> <description> <p>The Erlang code preprocessor includes functions that are used by the @@ -76,7 +76,7 @@ <funcs> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close the preprocessing of the file associated with <c>Epp</c>. </fsummary> <desc> @@ -85,7 +85,7 @@ </func> <func> - <name name="default_encoding" arity="0"/> + <name name="default_encoding" arity="0" since="OTP R16B"/> <fsummary>Return the default encoding of Erlang source files.</fsummary> <desc> <p>Returns the default encoding of Erlang source files.</p> @@ -93,7 +93,7 @@ </func> <func> - <name name="encoding_to_string" arity="1"/> + <name name="encoding_to_string" arity="1" since="OTP R16B"/> <fsummary>Return a string representation of an encoding.</fsummary> <desc> <p>Returns a string representation of an encoding. The string @@ -107,7 +107,7 @@ </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since="OTP R14B03"/> <fsummary>Format an error descriptor.</fsummary> <desc> <p>Takes an <c><anno>ErrorDescriptor</anno></c> and returns @@ -120,7 +120,7 @@ </func> <func> - <name name="open" arity="1"/> + <name name="open" arity="1" since="OTP 17.0"/> <fsummary>Open a file for preprocessing.</fsummary> <desc> <p>Opens a file for preprocessing.</p> @@ -136,7 +136,7 @@ </func> <func> - <name name="open" arity="2"/> + <name name="open" arity="2" since=""/> <fsummary>Open a file for preprocessing.</fsummary> <desc> <p>Equivalent to @@ -145,7 +145,7 @@ </func> <func> - <name name="open" arity="3"/> + <name name="open" arity="3" since=""/> <fsummary>Open a file for preprocessing.</fsummary> <desc> <p>Equivalent to <c>epp:open([{name, FileName}, {includes, IncludePath}, @@ -154,7 +154,7 @@ </func> <func> - <name name="parse_erl_form" arity="1"/> + <name name="parse_erl_form" arity="1" since=""/> <fsummary>Return the next Erlang form from the opened Erlang source file. </fsummary> <type name="warning_info"/> @@ -167,7 +167,7 @@ </func> <func> - <name name="parse_file" arity="2"/> + <name name="parse_file" arity="2" since="OTP 17.0"/> <fsummary>Preprocess and parse an Erlang source file.</fsummary> <desc> <p>Preprocesses and parses an Erlang source file. @@ -185,7 +185,7 @@ </func> <func> - <name name="parse_file" arity="3"/> + <name name="parse_file" arity="3" since=""/> <fsummary>Preprocess and parse an Erlang source file.</fsummary> <desc> <p>Equivalent to <c>epp:parse_file(FileName, [{includes, IncludePath}, @@ -194,8 +194,8 @@ </func> <func> - <name name="read_encoding" arity="1"/> - <name name="read_encoding" arity="2"/> + <name name="read_encoding" arity="1" since="OTP R16B"/> + <name name="read_encoding" arity="2" since="OTP R16B"/> <fsummary>Read the encoding from a file.</fsummary> <desc> <p>Read the <seealso marker="#encoding">encoding</seealso> from @@ -209,8 +209,8 @@ </func> <func> - <name name="read_encoding_from_binary" arity="1"/> - <name name="read_encoding_from_binary" arity="2"/> + <name name="read_encoding_from_binary" arity="1" since="OTP R16B"/> + <name name="read_encoding_from_binary" arity="2" since="OTP R16B"/> <fsummary>Read the encoding from a binary.</fsummary> <desc> <p>Read the <seealso marker="#encoding">encoding</seealso> from @@ -224,7 +224,7 @@ </func> <func> - <name name="set_encoding" arity="1"/> + <name name="set_encoding" arity="1" since="OTP R16B"/> <fsummary>Read and set the encoding of an I/O device.</fsummary> <desc> <p>Reads the <seealso marker="#encoding">encoding</seealso> from @@ -239,7 +239,7 @@ </func> <func> - <name name="set_encoding" arity="2"/> + <name name="set_encoding" arity="2" since="OTP 17.0"/> <fsummary>Read and set the encoding of an I/O device.</fsummary> <desc> <p>Reads the <seealso marker="#encoding">encoding</seealso> from diff --git a/lib/stdlib/doc/src/erl_anno.xml b/lib/stdlib/doc/src/erl_anno.xml index f316f63d98..dff93619ab 100644 --- a/lib/stdlib/doc/src/erl_anno.xml +++ b/lib/stdlib/doc/src/erl_anno.xml @@ -34,7 +34,7 @@ <rev>A</rev> <file>erl_anno.xml</file> </header> - <module>erl_anno</module> + <module since="OTP 18.0">erl_anno</module> <modulesummary>Abstract datatype for the annotations of the Erlang Compiler. </modulesummary> @@ -135,7 +135,7 @@ <funcs> <func> - <name name="column" arity="1"/> + <name name="column" arity="1" since="OTP 18.0"/> <fsummary>Return the column.</fsummary> <type name="column"></type> <desc> @@ -144,7 +144,7 @@ </func> <func> - <name name="end_location" arity="1"/> + <name name="end_location" arity="1" since="OTP 18.0"/> <fsummary>Return the end location of the text.</fsummary> <type name="location"></type> <desc> @@ -155,7 +155,7 @@ </func> <func> - <name name="file" arity="1"/> + <name name="file" arity="1" since="OTP 18.0"/> <fsummary>Return the filename.</fsummary> <type name="filename"></type> <desc> @@ -165,7 +165,7 @@ </func> <func> - <name name="from_term" arity="1"/> + <name name="from_term" arity="1" since="OTP 18.0"/> <fsummary>Return annotations given a term.</fsummary> <desc> <p>Returns annotations with representation <anno>Term</anno>.</p> @@ -174,7 +174,7 @@ </func> <func> - <name name="generated" arity="1"/> + <name name="generated" arity="1" since="OTP 18.0"/> <fsummary>Return the generated Boolean.</fsummary> <type name="generated"></type> <desc> @@ -185,7 +185,7 @@ </func> <func> - <name name="is_anno" arity="1"/> + <name name="is_anno" arity="1" since="OTP 18.0"/> <fsummary>Test for a collection of annotations.</fsummary> <desc> <p>Returns <c>true</c> if <anno>Term</anno> is a collection of @@ -194,7 +194,7 @@ </func> <func> - <name name="line" arity="1"/> + <name name="line" arity="1" since="OTP 18.0"/> <fsummary>Return the line.</fsummary> <type name="line"></type> <desc> @@ -203,7 +203,7 @@ </func> <func> - <name name="location" arity="1"/> + <name name="location" arity="1" since="OTP 18.0"/> <fsummary>Return the location.</fsummary> <type name="location"></type> <desc> @@ -212,7 +212,7 @@ </func> <func> - <name name="new" arity="1"/> + <name name="new" arity="1" since="OTP 18.0"/> <fsummary>Create a new collection of annotations.</fsummary> <type name="location"></type> <desc> @@ -221,7 +221,7 @@ </func> <func> - <name name="set_file" arity="2"/> + <name name="set_file" arity="2" since="OTP 18.0"/> <fsummary>Modify the filename.</fsummary> <type name="filename"></type> <desc> @@ -230,7 +230,7 @@ </func> <func> - <name name="set_generated" arity="2"/> + <name name="set_generated" arity="2" since="OTP 18.0"/> <fsummary>Modify the generated marker.</fsummary> <type name="generated"></type> <desc> @@ -240,7 +240,7 @@ </func> <func> - <name name="set_line" arity="2"/> + <name name="set_line" arity="2" since="OTP 18.0"/> <fsummary>Modify the line.</fsummary> <type name="line"></type> <desc> @@ -249,7 +249,7 @@ </func> <func> - <name name="set_location" arity="2"/> + <name name="set_location" arity="2" since="OTP 18.0"/> <fsummary>Modify the location.</fsummary> <type name="location"></type> <desc> @@ -258,7 +258,7 @@ </func> <func> - <name name="set_record" arity="2"/> + <name name="set_record" arity="2" since="OTP 18.0"/> <fsummary>Modify the record marker.</fsummary> <type name="record"></type> <desc> @@ -267,7 +267,7 @@ </func> <func> - <name name="set_text" arity="2"/> + <name name="set_text" arity="2" since="OTP 18.0"/> <fsummary>Modify the text.</fsummary> <type name="text"></type> <desc> @@ -276,7 +276,7 @@ </func> <func> - <name name="text" arity="1"/> + <name name="text" arity="1" since="OTP 18.0"/> <fsummary>Return the text.</fsummary> <type name="text"></type> <desc> @@ -286,7 +286,7 @@ </func> <func> - <name name="to_term" arity="1"/> + <name name="to_term" arity="1" since="OTP 18.0"/> <fsummary>Return the term representing a collection of annotations. </fsummary> <desc> diff --git a/lib/stdlib/doc/src/erl_eval.xml b/lib/stdlib/doc/src/erl_eval.xml index 1c0f7f062f..813cbecd89 100644 --- a/lib/stdlib/doc/src/erl_eval.xml +++ b/lib/stdlib/doc/src/erl_eval.xml @@ -32,7 +32,7 @@ <rev>B</rev> <file>erl_eval.xml</file> </header> - <module>erl_eval</module> + <module since="">erl_eval</module> <modulesummary>The Erlang meta interpreter.</modulesummary> <description> <p>This module provides an interpreter for Erlang expressions. The @@ -96,7 +96,7 @@ <funcs> <func> - <name name="add_binding" arity="3"/> + <name name="add_binding" arity="3" since=""/> <fsummary>Add a binding.</fsummary> <desc> <p>Adds binding <c><anno>Name</anno>=<anno>Value</anno></c> @@ -106,7 +106,7 @@ </func> <func> - <name name="binding" arity="2"/> + <name name="binding" arity="2" since=""/> <fsummary>Return bindings.</fsummary> <desc> <p>Returns the binding of <c><anno>Name</anno></c> @@ -115,7 +115,7 @@ </func> <func> - <name name="bindings" arity="1"/> + <name name="bindings" arity="1" since=""/> <fsummary>Return bindings.</fsummary> <desc> <p>Returns the list of bindings contained in the binding @@ -124,7 +124,7 @@ </func> <func> - <name name="del_binding" arity="2"/> + <name name="del_binding" arity="2" since=""/> <fsummary>Delete a binding.</fsummary> <desc> <p>Removes the binding of <c><anno>Name</anno></c> @@ -134,10 +134,10 @@ </func> <func> - <name name="expr" arity="2"/> - <name name="expr" arity="3"/> - <name name="expr" arity="4"/> - <name name="expr" arity="5"/> + <name name="expr" arity="2" since=""/> + <name name="expr" arity="3" since=""/> + <name name="expr" arity="4" since=""/> + <name name="expr" arity="5" since=""/> <fsummary>Evaluate expression.</fsummary> <desc> <p>Evaluates <c><anno>Expression</anno></c> with the set of bindings @@ -157,9 +157,9 @@ </func> <func> - <name name="expr_list" arity="2"/> - <name name="expr_list" arity="3"/> - <name name="expr_list" arity="4"/> + <name name="expr_list" arity="2" since=""/> + <name name="expr_list" arity="3" since=""/> + <name name="expr_list" arity="4" since=""/> <fsummary>Evaluate a list of expressions.</fsummary> <desc> <p>Evaluates a list of expressions in parallel, using the same @@ -174,9 +174,9 @@ </func> <func> - <name name="exprs" arity="2"/> - <name name="exprs" arity="3"/> - <name name="exprs" arity="4"/> + <name name="exprs" arity="2" since=""/> + <name name="exprs" arity="3" since=""/> + <name name="exprs" arity="4" since=""/> <fsummary>Evaluate expressions.</fsummary> <desc> <p>Evaluates <c><anno>Expressions</anno></c> with the set of bindings @@ -197,7 +197,7 @@ </func> <func> - <name name="new_bindings" arity="0"/> + <name name="new_bindings" arity="0" since=""/> <fsummary>Return a bindings structure.</fsummary> <desc> <p>Returns an empty binding structure.</p> diff --git a/lib/stdlib/doc/src/erl_expand_records.xml b/lib/stdlib/doc/src/erl_expand_records.xml index b6aa75ed03..20e5f1960b 100644 --- a/lib/stdlib/doc/src/erl_expand_records.xml +++ b/lib/stdlib/doc/src/erl_expand_records.xml @@ -34,7 +34,7 @@ <rev>PA1</rev> <file>erl_expand_records.xml</file> </header> - <module>erl_expand_records</module> + <module since="">erl_expand_records</module> <modulesummary>Expands records in a module.</modulesummary> <description> <p>This module expands records in a module.</p> @@ -42,7 +42,7 @@ <funcs> <func> - <name name="module" arity="2"/> + <name name="module" arity="2" since=""/> <fsummary>Expand all records in a module.</fsummary> <desc> <p>Expands all records in a module to use explicit tuple diff --git a/lib/stdlib/doc/src/erl_id_trans.xml b/lib/stdlib/doc/src/erl_id_trans.xml index 16952a9582..ec66842ac0 100644 --- a/lib/stdlib/doc/src/erl_id_trans.xml +++ b/lib/stdlib/doc/src/erl_id_trans.xml @@ -34,7 +34,7 @@ <rev>B</rev> <file>erl_id_trans.xml</file> </header> - <module>erl_id_trans</module> + <module since="">erl_id_trans</module> <modulesummary>An identity parse transform.</modulesummary> <description> <p>This module performs an identity parse transformation of Erlang code. @@ -46,7 +46,7 @@ <funcs> <func> - <name>parse_transform(Forms, Options) -> Forms</name> + <name since="">parse_transform(Forms, Options) -> Forms</name> <fsummary>Transform Erlang forms.</fsummary> <type> <v>Forms = [<seealso marker="erl_parse#type-abstract_form">erl_parse:abstract_form()</seealso> diff --git a/lib/stdlib/doc/src/erl_internal.xml b/lib/stdlib/doc/src/erl_internal.xml index 17cd0fb240..77551ffed7 100644 --- a/lib/stdlib/doc/src/erl_internal.xml +++ b/lib/stdlib/doc/src/erl_internal.xml @@ -34,7 +34,7 @@ <rev>B</rev> <file>erl_internal.xml</file> </header> - <module>erl_internal</module> + <module since="">erl_internal</module> <modulesummary>Internal Erlang definitions.</modulesummary> <description> <p>This module defines Erlang BIFs, guard tests, and operators. @@ -44,7 +44,7 @@ <funcs> <func> - <name name="add_predefined_functions" arity="1"/> + <name name="add_predefined_functions" arity="1" since="OTP 20.0"/> <fsummary>Add code for pre-defined functions.</fsummary> <desc> <p>Adds to <c><anno>Forms</anno></c> the code for the standard @@ -54,7 +54,7 @@ </func> <func> - <name name="arith_op" arity="2"/> + <name name="arith_op" arity="2" since=""/> <fsummary>Test for an arithmetic operator.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c> @@ -63,7 +63,7 @@ </func> <func> - <name name="bif" arity="2"/> + <name name="bif" arity="2" since=""/> <fsummary>Test for an Erlang BIF.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Name</anno>/<anno>Arity</anno></c> @@ -73,7 +73,7 @@ </func> <func> - <name name="bool_op" arity="2"/> + <name name="bool_op" arity="2" since=""/> <fsummary>Test for a Boolean operator.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c> @@ -82,7 +82,7 @@ </func> <func> - <name name="comp_op" arity="2"/> + <name name="comp_op" arity="2" since=""/> <fsummary>Test for a comparison operator.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c> @@ -91,7 +91,7 @@ </func> <func> - <name name="guard_bif" arity="2"/> + <name name="guard_bif" arity="2" since=""/> <fsummary>Test for an Erlang BIF allowed in guards.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Name</anno>/<anno>Arity</anno></c> is @@ -100,7 +100,7 @@ </func> <func> - <name name="list_op" arity="2"/> + <name name="list_op" arity="2" since=""/> <fsummary>Test for a list operator.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c> @@ -109,7 +109,7 @@ </func> <func> - <name name="op_type" arity="2"/> + <name name="op_type" arity="2" since=""/> <fsummary>Return operator type.</fsummary> <desc> <p>Returns the <c><anno>Type</anno></c> of operator that @@ -120,7 +120,7 @@ </func> <func> - <name name="send_op" arity="2"/> + <name name="send_op" arity="2" since=""/> <fsummary>Test for a send operator.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c> @@ -129,7 +129,7 @@ </func> <func> - <name name="type_test" arity="2"/> + <name name="type_test" arity="2" since=""/> <fsummary>Test for a valid type test.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Name</anno>/<anno>Arity</anno></c> is diff --git a/lib/stdlib/doc/src/erl_lint.xml b/lib/stdlib/doc/src/erl_lint.xml index 77cb7a9916..12eaafc3a8 100644 --- a/lib/stdlib/doc/src/erl_lint.xml +++ b/lib/stdlib/doc/src/erl_lint.xml @@ -32,7 +32,7 @@ <rev>B</rev> <file>erl_lint.xml</file> </header> - <module>erl_lint</module> + <module since="">erl_lint</module> <modulesummary>The Erlang code linter.</modulesummary> <description> <p>This module is used to check Erlang code for illegal syntax and @@ -78,7 +78,7 @@ <funcs> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Format an error descriptor.</fsummary> <desc> <p>Takes an <c><anno>ErrorDescriptor</anno></c> and returns a string @@ -90,7 +90,7 @@ </func> <func> - <name name="is_guard_test" arity="1"/> + <name name="is_guard_test" arity="1" since=""/> <fsummary>Test for a guard test.</fsummary> <desc> <p>Tests if <c><anno>Expr</anno></c> is a legal guard test. @@ -102,9 +102,9 @@ </func> <func> - <name name="module" arity="1"/> - <name name="module" arity="2"/> - <name name="module" arity="3"/> + <name name="module" arity="1" since=""/> + <name name="module" arity="2" since=""/> + <name name="module" arity="3" since=""/> <fsummary>Check a module for errors.</fsummary> <desc> <p>Checks all the forms in a module for errors. It returns:</p> diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml index 647f36883c..8142e5c0aa 100644 --- a/lib/stdlib/doc/src/erl_parse.xml +++ b/lib/stdlib/doc/src/erl_parse.xml @@ -32,7 +32,7 @@ <rev>B</rev> <file>erl_parse.xml</file> </header> - <module>erl_parse</module> + <module since="">erl_parse</module> <modulesummary>The Erlang parser.</modulesummary> <description> <p>This module is the basic Erlang parser that converts tokens into @@ -89,7 +89,7 @@ <funcs> <func> - <name name="abstract" arity="1"/> + <name name="abstract" arity="1" since=""/> <fsummary>Convert an Erlang term into an abstract form.</fsummary> <desc> <p>Converts the Erlang data structure <c><anno>Data</anno></c> into an @@ -102,7 +102,7 @@ </func> <func> - <name name="abstract" arity="2"/> + <name name="abstract" arity="2" since="OTP R16B01"/> <fsummary>Convert an Erlang term into an abstract form.</fsummary> <type name="encoding_func"/> <desc> @@ -124,7 +124,7 @@ </func> <func> - <name name="anno_from_term" arity="1"/> + <name name="anno_from_term" arity="1" since="OTP 18.0"/> <fsummary>Return annotations as terms.</fsummary> <desc> <p>Assumes that <c><anno>Term</anno></c> is a term with the same @@ -140,7 +140,7 @@ </func> <func> - <name name="anno_to_term" arity="1"/> + <name name="anno_to_term" arity="1" since="OTP 18.0"/> <fsummary>Return the representation of annotations.</fsummary> <desc> <p>Returns a term where each collection of annotations @@ -154,7 +154,7 @@ </func> <func> - <name name="fold_anno" arity="3"/> + <name name="fold_anno" arity="3" since="OTP 18.0"/> <fsummary>Fold a function over the annotations of an <c>erl_parse</c> tree. </fsummary> <desc> @@ -171,7 +171,7 @@ </func> <func> - <name>format_error(ErrorDescriptor) -> Chars</name> + <name since="">format_error(ErrorDescriptor) -> Chars</name> <fsummary>Format an error descriptor.</fsummary> <type> <v>ErrorDescriptor = <seealso @@ -188,7 +188,7 @@ </func> <func> - <name name="map_anno" arity="2"/> + <name name="map_anno" arity="2" since="OTP 18.0"/> <fsummary>Map a function over the annotations of an <c>erl_parse</c> tree. </fsummary> <desc> @@ -201,7 +201,7 @@ </func> <func> - <name name="mapfold_anno" arity="3"/> + <name name="mapfold_anno" arity="3" since="OTP 18.0"/> <fsummary>Map and fold a function over the annotations of an <c>erl_parse</c> tree.</fsummary> <desc> @@ -220,7 +220,7 @@ </func> <func> - <name name="new_anno" arity="1"/> + <name name="new_anno" arity="1" since="OTP 18.0"/> <fsummary>Create new annotations.</fsummary> <desc> <p>Assumes that <c><anno>Term</anno></c> is a term with the same @@ -236,7 +236,7 @@ </func> <func> - <name name="normalise" arity="1"/> + <name name="normalise" arity="1" since=""/> <fsummary>Convert abstract form to an Erlang term.</fsummary> <desc> <p>Converts the abstract form <c><anno>AbsTerm</anno></c> of a @@ -247,7 +247,7 @@ </func> <func> - <name name="parse_exprs" arity="1"/> + <name name="parse_exprs" arity="1" since=""/> <fsummary>Parse Erlang expressions.</fsummary> <desc> <p>Parses <c><anno>Tokens</anno></c> as if it was a list of expressions. @@ -267,7 +267,7 @@ </func> <func> - <name name="parse_form" arity="1"/> + <name name="parse_form" arity="1" since=""/> <fsummary>Parse an Erlang form.</fsummary> <desc> <p>Parses <c><anno>Tokens</anno></c> as if it was a form. Returns one @@ -287,7 +287,7 @@ </func> <func> - <name name="parse_term" arity="1"/> + <name name="parse_term" arity="1" since=""/> <fsummary>Parse an Erlang term.</fsummary> <desc> <p>Parses <c><anno>Tokens</anno></c> as if it was a term. Returns @@ -307,8 +307,8 @@ </func> <func> - <name name="tokens" arity="1"/> - <name name="tokens" arity="2"/> + <name name="tokens" arity="1" since=""/> + <name name="tokens" arity="2" since=""/> <fsummary>Generate a list of tokens for an expression.</fsummary> <desc> <p>Generates a list of tokens representing the abstract diff --git a/lib/stdlib/doc/src/erl_pp.xml b/lib/stdlib/doc/src/erl_pp.xml index 77a7f1e8d1..f1c3aa5a41 100644 --- a/lib/stdlib/doc/src/erl_pp.xml +++ b/lib/stdlib/doc/src/erl_pp.xml @@ -34,7 +34,7 @@ <rev>B</rev> <file>erl_pp.xml</file> </header> - <module>erl_pp</module> + <module since="">erl_pp</module> <modulesummary>The Erlang pretty printer.</modulesummary> <description> <p>The functions in this module are used to generate @@ -73,8 +73,8 @@ <funcs> <func> - <name name="attribute" arity="1"/> - <name name="attribute" arity="2"/> + <name name="attribute" arity="1" since=""/> + <name name="attribute" arity="2" since=""/> <fsummary>Pretty print an attribute.</fsummary> <desc> <p>Same as <seealso marker="#form/1"><c>form/1,2</c></seealso>, @@ -83,10 +83,10 @@ </func> <func> - <name name="expr" arity="1"/> - <name name="expr" arity="2"/> - <name name="expr" arity="3"/> - <name name="expr" arity="4"/> + <name name="expr" arity="1" since=""/> + <name name="expr" arity="2" since=""/> + <name name="expr" arity="3" since=""/> + <name name="expr" arity="4" since=""/> <fsummary>Pretty print one <c>Expression</c>.</fsummary> <desc> <p>Prints one expression. It is useful for implementing hooks (see @@ -96,9 +96,9 @@ </func> <func> - <name name="exprs" arity="1"/> - <name name="exprs" arity="2"/> - <name name="exprs" arity="3"/> + <name name="exprs" arity="1" since=""/> + <name name="exprs" arity="2" since=""/> + <name name="exprs" arity="3" since=""/> <fsummary>Pretty print <c>Expressions</c>.</fsummary> <desc> <p>Same as <seealso marker="#form/1"><c>form/1,2</c></seealso>, @@ -108,8 +108,8 @@ </func> <func> - <name name="form" arity="1"/> - <name name="form" arity="2"/> + <name name="form" arity="1" since=""/> + <name name="form" arity="2" since=""/> <fsummary>Pretty print a form.</fsummary> <desc> <p>Pretty prints a @@ -120,8 +120,8 @@ </func> <func> - <name name="function" arity="1"/> - <name name="function" arity="2"/> + <name name="function" arity="1" since=""/> + <name name="function" arity="2" since=""/> <fsummary>Pretty print a function.</fsummary> <desc> <p>Same as <seealso marker="#form/1"><c>form/1,2</c></seealso>, @@ -130,8 +130,8 @@ </func> <func> - <name name="guard" arity="1"/> - <name name="guard" arity="2"/> + <name name="guard" arity="1" since=""/> + <name name="guard" arity="2" since=""/> <fsummary>Pretty print a guard.</fsummary> <desc> <p>Same as <seealso marker="#form/1"><c>form/1,2</c></seealso>, diff --git a/lib/stdlib/doc/src/erl_scan.xml b/lib/stdlib/doc/src/erl_scan.xml index 137ccd3416..38111f73bc 100644 --- a/lib/stdlib/doc/src/erl_scan.xml +++ b/lib/stdlib/doc/src/erl_scan.xml @@ -32,7 +32,7 @@ <rev>B</rev> <file>erl_scan.xml</file> </header> - <module>erl_scan</module> + <module since="">erl_scan</module> <modulesummary>The Erlang token scanner.</modulesummary> <description> <p>This module contains functions for tokenizing (scanning) characters into @@ -74,7 +74,7 @@ <funcs> <func> - <name name="category" arity="1"/> + <name name="category" arity="1" since="OTP 18.0"/> <fsummary>Return the category.</fsummary> <desc> <p>Returns the category of <c><anno>Token</anno></c>.</p> @@ -82,7 +82,7 @@ </func> <func> - <name name="column" arity="1"/> + <name name="column" arity="1" since="OTP 18.0"/> <fsummary>Return the column.</fsummary> <desc> <p>Returns the column of <c><anno>Token</anno></c>'s @@ -91,7 +91,7 @@ </func> <func> - <name name="end_location" arity="1"/> + <name name="end_location" arity="1" since="OTP 18.0"/> <fsummary>Return the end location of the text.</fsummary> <desc> <p>Returns the end location of the text of @@ -101,7 +101,7 @@ </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Format an error descriptor.</fsummary> <desc> <p>Uses an <c><anno>ErrorDescriptor</anno></c> and returns a string @@ -113,7 +113,7 @@ </func> <func> - <name name="line" arity="1"/> + <name name="line" arity="1" since="OTP 18.0"/> <fsummary>Return the line.</fsummary> <desc> <p>Returns the line of <c><anno>Token</anno></c>'s collection @@ -122,7 +122,7 @@ </func> <func> - <name name="location" arity="1"/> + <name name="location" arity="1" since="OTP 18.0"/> <fsummary>Return the location.</fsummary> <desc> <p>Returns the location of <c><anno>Token</anno></c>'s @@ -131,7 +131,7 @@ </func> <func> - <name name="reserved_word" arity="1"/> + <name name="reserved_word" arity="1" since=""/> <fsummary>Test for a reserved word.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Atom</anno></c> is an @@ -140,9 +140,9 @@ </func> <func> - <name name="string" arity="1"/> - <name name="string" arity="2"/> - <name name="string" arity="3"/> + <name name="string" arity="1" since=""/> + <name name="string" arity="2" since=""/> + <name name="string" arity="3" since=""/> <fsummary>Scan a string and return the Erlang tokens.</fsummary> <desc> <p>Takes the list of characters <c><anno>String</anno></c> and tries to @@ -229,7 +229,7 @@ </func> <func> - <name name="symbol" arity="1"/> + <name name="symbol" arity="1" since="OTP 18.0"/> <fsummary>Return the symbol.</fsummary> <desc> <p>Returns the symbol of <c><anno>Token</anno></c>.</p> @@ -237,7 +237,7 @@ </func> <func> - <name name="text" arity="1"/> + <name name="text" arity="1" since="OTP 18.0"/> <fsummary>Return the text.</fsummary> <desc> <p>Returns the text of <c><anno>Token</anno></c>'s collection @@ -247,8 +247,8 @@ </func> <func> - <name name="tokens" arity="3"/> - <name name="tokens" arity="4"/> + <name name="tokens" arity="3" since=""/> + <name name="tokens" arity="4" since=""/> <fsummary>Re-entrant scanner.</fsummary> <type name="char_spec"/> <type name="return_cont"/> diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml index 68fa071090..ea8173748a 100644 --- a/lib/stdlib/doc/src/erl_tar.xml +++ b/lib/stdlib/doc/src/erl_tar.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>erl_tar.xml</file> </header> - <module>erl_tar</module> + <module since="">erl_tar</module> <modulesummary>Unix 'tar' utility for reading and writing tar archives. </modulesummary> <description> @@ -127,7 +127,7 @@ <funcs> <func> - <name>add(TarDescriptor, Filename, Options) -> RetValue</name> + <name since="">add(TarDescriptor, Filename, Options) -> RetValue</name> <fsummary>Add a file to an open tar file.</fsummary> <type> <v>TarDescriptor = term()</v> @@ -211,7 +211,7 @@ </func> <func> - <name>add(TarDescriptor, FilenameOrBin, NameInArchive, Options) -> + <name since="">add(TarDescriptor, FilenameOrBin, NameInArchive, Options) -> RetValue </name> <fsummary>Add a file to an open tar file.</fsummary> <type> @@ -233,7 +233,7 @@ </func> <func> - <name>close(TarDescriptor)</name> + <name since="">close(TarDescriptor)</name> <fsummary>Close an open tar file.</fsummary> <type> <v>TarDescriptor = term()</v> @@ -245,7 +245,7 @@ </func> <func> - <name>create(Name, FileList) ->RetValue </name> + <name since="">create(Name, FileList) ->RetValue </name> <fsummary>Create a tar archive.</fsummary> <type> <v>Name = filename()</v> @@ -264,7 +264,7 @@ </func> <func> - <name>create(Name, FileList, OptionList)</name> + <name since="">create(Name, FileList, OptionList)</name> <fsummary>Create a tar archive with options.</fsummary> <type> <v>Name = filename()</v> @@ -315,7 +315,7 @@ </func> <func> - <name>extract(Name) -> RetValue</name> + <name since="">extract(Name) -> RetValue</name> <fsummary>Extract all files from a tar file.</fsummary> <type> <v>Name = filename() | {binary,binary()} | {file,Fd}</v> @@ -339,7 +339,7 @@ </func> <func> - <name>extract(Name, OptionList)</name> + <name since="">extract(Name, OptionList)</name> <fsummary>Extract files from a tar file.</fsummary> <type> <v>Name = filename() | {binary,binary()} | {file,Fd}</v> @@ -411,7 +411,7 @@ </func> <func> - <name>format_error(Reason) -> string()</name> + <name since="">format_error(Reason) -> string()</name> <fsummary>Convert error term to a readable string.</fsummary> <type> <v>Reason = term()</v> @@ -423,7 +423,7 @@ </func> <func> - <name>init(UserPrivate, AccessMode, Fun) -> + <name since="OTP 17.4">init(UserPrivate, AccessMode, Fun) -> {ok,TarDescriptor} | {error,Reason}</name> <fsummary>Create a <c>TarDescriptor</c> used in subsequent tar operations when defining own low-level storage access functions.</fsummary> @@ -518,7 +518,7 @@ erl_tar:close(TarDesc)</code> </func> <func> - <name>open(Name, OpenModeList) -> RetValue</name> + <name since="">open(Name, OpenModeList) -> RetValue</name> <fsummary>Open a tar file for writing.</fsummary> <type> <v>Name = filename()</v> @@ -565,7 +565,7 @@ erl_tar:close(TarDesc)</code> </func> <func> - <name>table(Name) -> RetValue</name> + <name since="">table(Name) -> RetValue</name> <fsummary>Retrieve the name of all files in a tar file.</fsummary> <type> <v>Name = filename()|{binary,binary()}|{file,file_descriptor()}</v> @@ -578,7 +578,7 @@ erl_tar:close(TarDesc)</code> </func> <func> - <name>table(Name, Options)</name> + <name since="">table(Name, Options)</name> <fsummary>Retrieve name and information of all files in a tar file. </fsummary> <type> @@ -590,7 +590,7 @@ erl_tar:close(TarDesc)</code> </func> <func> - <name>t(Name)</name> + <name since="">t(Name)</name> <fsummary>Print the name of each file in a tar file.</fsummary> <type> <v>Name = filename()|{binary,binary()}|{file,file_descriptor()}</v> @@ -602,7 +602,7 @@ erl_tar:close(TarDesc)</code> </func> <func> - <name>tt(Name)</name> + <name since="">tt(Name)</name> <fsummary>Print name and information for each file in a tar file. </fsummary> <type> diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index ad006f9a2b..622edc072e 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>ets</module> + <module since="">ets</module> <modulesummary>Built-in term storage.</modulesummary> <description> <p>This module is an interface to the Erlang built-in term storage @@ -138,23 +138,71 @@ operation. In database terms the isolation level can be seen as "serializable", as if all isolated operations are carried out serially, one after the other in a strict order.</p> + </section> - <p>No other support is available within this module that would guarantee - consistency between objects. However, function - <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso> - can be used to guarantee that a sequence of - <seealso marker="#first/1"><c>first/1</c></seealso> and - <seealso marker="#next/2"><c>next/2</c></seealso> calls traverse the - table without errors and that each existing object in the table is - visited exactly once, even if another (or the same) process - simultaneously deletes or inserts objects into the table. - Nothing else is guaranteed; in particular objects that are inserted - or deleted during such a traversal can be visited once or not at all. - Functions that internally traverse over a table, like - <seealso marker="#select/1"><c>select</c></seealso> and - <seealso marker="#match/1"><c>match</c></seealso>, - give the same guarantee as - <seealso marker="#safe_fixtable/2"><c>safe_fixtable</c></seealso>.</p> + <section><marker id="traversal"></marker> + <title>Table traversal</title> + <p>There are different ways to traverse through the objects of a table.</p> + <list type="bulleted"> + <item><p><em>Single-step</em> traversal one key at at time, using + <seealso marker="#first/1"><c>first/1</c></seealso>, + <seealso marker="#next/2"><c>next/2</c></seealso>, + <seealso marker="#last/1"><c>last/1</c></seealso> and + <seealso marker="#prev/2"><c>prev/2</c></seealso>.</p> + </item> + <item><p>Search with simple <em>match patterns</em>, using + <seealso marker="#match/1"><c>match/1/2/3</c></seealso>, + <seealso marker="#match_delete/2"><c>match_delete/2</c></seealso> and + <seealso marker="#match_object/1"><c>match_object/1/2/3</c></seealso>.</p> + </item> + <item><p>Search with more powerful <em>match specifications</em>, using + <seealso marker="#select/1"><c>select/1/2/3</c></seealso>, + <seealso marker="#select_count/2"><c>select_count/2</c></seealso>, + <seealso marker="#select_delete/2"><c>select_delete/2</c></seealso>, + <seealso marker="#select_replace/2"><c>select_replace/2</c></seealso> and + <seealso marker="#select_reverse/1"><c>select_reverse/1/2/3</c></seealso>.</p> + </item> + <item><p><em>Table conversions</em>, using + <seealso marker="#tab2file/2"><c>tab2file/2/3</c></seealso> and + <seealso marker="#tab2list/1"><c>tab2list/1</c></seealso>.</p> + </item> + </list> + <p>None of these ways of table traversal will guarantee a consistent table snapshot + if the table is also updated during the traversal. Moreover, traversals not + done in a <em>safe</em> way, on tables where keys are inserted or deleted + during the traversal, may yield the following undesired effects:</p> + <list type="bulleted"> + <item><p>Any key may be missed.</p></item> + <item><p>Any key may be found more than once.</p></item> + <item><p>The traversal may fail with <c>badarg</c> exception if keys are deleted.</p> + </item> + </list> + <p>A table traversal is <em>safe</em> if either</p> + <list type="bulleted"> + <item><p>the table is of type <c>ordered_set</c>.</p> + </item> + <item><p>the entire table traversal is done within one ETS function + call.</p> + </item> + <item><p>function <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso> + is used to keep the table fixated during the entire traversal.</p> + </item> + </list> + <p>Traversals using <c>match</c> and <c>select</c> functions may not need to + scan the entire table depending on how the key is specified. A match + pattern with a <em>fully bound key</em> (without any match variables) will + optimize the operation to a single key lookup without any table traversal + at all. For <c>ordered_set</c> a <em>partially bound key</em> will limit the + traversal to only scan a subset of the table based on term order. A + partially bound key is either a list or a tuple with a prefix that is fully + bound. Example:</p> +<pre> +1> <input>T = ets:new(t,[ordered_set]), ets:insert(T, {"555-1234", "John Smith"}).</input> +true +2> <input>%% Efficient search of all with area code 555</input> +2> <input>ets:match(T,{[$5,$5,$5,$- |'$1'],'$2'}).</input> +[["1234","John Smith"]] +</pre> </section> <section> @@ -207,7 +255,7 @@ <funcs> <func> - <name name="all" arity="0"/> + <name name="all" arity="0" since=""/> <fsummary>Return a list of all ETS tables.</fsummary> <desc> <p>Returns a list of all tables at the node. Named tables are @@ -222,7 +270,7 @@ </func> <func> - <name name="delete" arity="1"/> + <name name="delete" arity="1" since=""/> <fsummary>Delete an entire ETS table.</fsummary> <desc> <p>Deletes the entire table <c><anno>Tab</anno></c>.</p> @@ -230,7 +278,7 @@ </func> <func> - <name name="delete" arity="2"/> + <name name="delete" arity="2" since=""/> <fsummary>Delete all objects with a specified key from an ETS table.</fsummary> <desc> @@ -240,7 +288,7 @@ </func> <func> - <name name="delete_all_objects" arity="1"/> + <name name="delete_all_objects" arity="1" since=""/> <fsummary>Delete all objects in an ETS table.</fsummary> <desc> <p>Delete all objects in the ETS table <c><anno>Tab</anno></c>. @@ -250,7 +298,7 @@ </func> <func> - <name name="delete_object" arity="2"/> + <name name="delete_object" arity="2" since=""/> <fsummary>Deletes a specific from an ETS table.</fsummary> <desc> <p>Delete the exact object <c><anno>Object</anno></c> from the @@ -262,7 +310,7 @@ </func> <func> - <name name="file2tab" arity="1"/> + <name name="file2tab" arity="1" since=""/> <fsummary>Read an ETS table from a file.</fsummary> <desc> <p>Reads a file produced by <seealso marker="#tab2file/2"> @@ -274,7 +322,7 @@ </func> <func> - <name name="file2tab" arity="2"/> + <name name="file2tab" arity="2" since=""/> <fsummary>Read an ETS table from a file.</fsummary> <desc> <p>Reads a file produced by <seealso marker="#tab2file/2"> @@ -306,7 +354,7 @@ </func> <func> - <name name="first" arity="1"/> + <name name="first" arity="1" since=""/> <fsummary>Return the first key in an ETS table.</fsummary> <desc> <p>Returns the first key <c><anno>Key</anno></c> in table @@ -321,7 +369,7 @@ </func> <func> - <name name="foldl" arity="3"/> + <name name="foldl" arity="3" since=""/> <fsummary>Fold a function over an ETS table.</fsummary> <desc> <p><c><anno>Acc0</anno></c> is returned if the table is empty. @@ -337,7 +385,7 @@ </func> <func> - <name name="foldr" arity="3"/> + <name name="foldr" arity="3" since=""/> <fsummary>Fold a function over an ETS table.</fsummary> <desc> <p><c><anno>Acc0</anno></c> is returned if the table is empty. @@ -353,7 +401,7 @@ </func> <func> - <name name="from_dets" arity="2"/> + <name name="from_dets" arity="2" since=""/> <fsummary>Fill an ETS table with objects from a Dets table.</fsummary> <desc> @@ -367,7 +415,7 @@ </func> <func> - <name name="fun2ms" arity="1"/> + <name name="fun2ms" arity="1" since=""/> <fsummary>Pseudo function that transforms fun syntax to a match specification.</fsummary> <desc> @@ -436,7 +484,7 @@ Error: fun containing local Erlang function calls </func> <func> - <name name="give_away" arity="3"/> + <name name="give_away" arity="3" since=""/> <fsummary>Change owner of a table.</fsummary> <desc> <p>Make process <c><anno>Pid</anno></c> the new owner of table @@ -454,7 +502,7 @@ Error: fun containing local Erlang function calls </func> <func> - <name name="i" arity="0"/> + <name name="i" arity="0" since=""/> <fsummary>Display information about all ETS tables on a terminal. </fsummary> <desc> @@ -463,7 +511,7 @@ Error: fun containing local Erlang function calls </func> <func> - <name name="i" arity="1"/> + <name name="i" arity="1" since=""/> <fsummary>Browse an ETS table on a terminal.</fsummary> <desc> <p>Browses table <c><anno>Tab</anno></c> on a terminal.</p> @@ -471,7 +519,7 @@ Error: fun containing local Erlang function calls </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since=""/> <fsummary>Return information about an <c>table</c>.</fsummary> <desc> <p>Returns information about table <c><anno>Tab</anno></c> as a list of @@ -547,7 +595,7 @@ Error: fun containing local Erlang function calls </func> <func> - <name name="info" arity="2"/> + <name name="info" arity="2" since=""/> <fsummary>Return the information associated with the specified item for an ETS table.</fsummary> <desc> @@ -619,7 +667,7 @@ Error: fun containing local Erlang function calls </func> <func> - <name name="init_table" arity="2"/> + <name name="init_table" arity="2" since=""/> <fsummary>Replace all objects of an ETS table.</fsummary> <desc> <p>Replaces the existing objects of table <c><anno>Tab</anno></c> with @@ -649,7 +697,7 @@ Error: fun containing local Erlang function calls </func> <func> - <name name="insert" arity="2"/> + <name name="insert" arity="2" since=""/> <fsummary>Insert an object into an ETS table.</fsummary> <desc> <p>Inserts the object or all of the objects in list @@ -681,7 +729,7 @@ Error: fun containing local Erlang function calls </func> <func> - <name name="insert_new" arity="2"/> + <name name="insert_new" arity="2" since=""/> <fsummary>Insert an object into an ETS table if the key is not already present.</fsummary> <desc> @@ -700,7 +748,7 @@ Error: fun containing local Erlang function calls </func> <func> - <name name="is_compiled_ms" arity="1"/> + <name name="is_compiled_ms" arity="1" since=""/> <fsummary>Check if an Erlang term is the result of <c>match_spec_compile</c>.</fsummary> <desc> @@ -732,7 +780,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="last" arity="1"/> + <name name="last" arity="1" since=""/> <fsummary>Return the last key in an ETS table of type <c>ordered_set</c>.</fsummary> <desc> @@ -747,7 +795,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="lookup" arity="2"/> + <name name="lookup" arity="2" since=""/> <fsummary>Return all objects with a specified key in an ETS table. </fsummary> <desc> @@ -787,7 +835,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="lookup_element" arity="3"/> + <name name="lookup_element" arity="3" since=""/> <fsummary>Return the <c>Pos</c>:th element of all objects with a specified key in an ETS table.</fsummary> <desc> @@ -810,7 +858,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="match" arity="1"/> + <name name="match" arity="1" since=""/> <fsummary>Continues matching objects in an ETS table.</fsummary> <desc> <p>Continues a match started with @@ -824,7 +872,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="match" arity="2"/> + <name name="match" arity="2" since=""/> <fsummary>Match the objects in an ETS table against a pattern. </fsummary> <desc> @@ -856,7 +904,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="match" arity="3"/> + <name name="match" arity="3" since=""/> <fsummary>Match the objects in an ETS table against a pattern and return part of the answers.</fsummary> <desc> @@ -871,11 +919,14 @@ ets:is_compiled_ms(Broken).</code> <seealso marker="#first/1"><c>first/1</c></seealso> and <seealso marker="#next/2"><c>next/2</c></seealso>.</p> <p>If the table is empty, <c>'$end_of_table'</c> is returned.</p> + <p>Use <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso> + to guarantee <seealso marker="#traversal">safe traversal</seealso> + for subsequent calls to <seealso marker="#match/1"><c>match/1</c></seealso>.</p> </desc> </func> <func> - <name name="match_delete" arity="2"/> + <name name="match_delete" arity="2" since=""/> <fsummary>Delete all objects that match a specified pattern from an ETS table.</fsummary> <desc> @@ -886,7 +937,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="match_object" arity="1"/> + <name name="match_object" arity="1" since=""/> <fsummary>Continues matching objects in an ETS table.</fsummary> <desc> <p>Continues a match started with @@ -901,7 +952,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="match_object" arity="2"/> + <name name="match_object" arity="2" since=""/> <fsummary>Match the objects in an ETS table against a pattern. </fsummary> <desc> @@ -920,7 +971,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="match_object" arity="3"/> + <name name="match_object" arity="3" since=""/> <fsummary>Match the objects in an ETS table against a pattern and return part of the answers.</fsummary> <desc> @@ -936,11 +987,15 @@ ets:is_compiled_ms(Broken).</code> <seealso marker="#first/1"><c>first/1</c></seealso> and <seealso marker="#next/2"><c>next/2</c></seealso>.</p> <p>If the table is empty, <c>'$end_of_table'</c> is returned.</p> + <p>Use <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso> + to guarantee <seealso marker="#traversal">safe traversal</seealso> + for subsequent calls to <seealso marker="#match_object/1"> + <c>match_object/1</c></seealso>.</p> </desc> </func> <func> - <name name="match_spec_compile" arity="1"/> + <name name="match_spec_compile" arity="1" since=""/> <fsummary>Compile a match specification into its internal representation. </fsummary> <desc> @@ -968,7 +1023,7 @@ ets:is_compiled_ms(Broken).</code> </func> <func> - <name name="match_spec_run" arity="2"/> + <name name="match_spec_run" arity="2" since=""/> <fsummary>Perform matching, using a compiled match specification on a list of terms.</fsummary> <desc> @@ -1005,7 +1060,7 @@ ets:select(Table, MatchSpec),</code> </func> <func> - <name name="member" arity="2"/> + <name name="member" arity="2" since=""/> <fsummary>Tests for occurrence of a key in an ETS table.</fsummary> <desc> <p>Works like <seealso marker="#lookup/2"><c>lookup/2</c></seealso>, @@ -1016,7 +1071,7 @@ ets:select(Table, MatchSpec),</code> </func> <func> - <name name="new" arity="2"/> + <name name="new" arity="2" since=""/> <fsummary>Create a new ETS table.</fsummary> <desc> <p>Creates a new table and returns a table identifier that can @@ -1180,7 +1235,7 @@ ets:select(Table, MatchSpec),</code> </func> <func> - <name name="next" arity="2"/> + <name name="next" arity="2" since=""/> <fsummary>Return the next key in an ETS table.</fsummary> <desc> <p>Returns the next key <c><anno>Key2</anno></c>, following key @@ -1192,17 +1247,18 @@ ets:select(Table, MatchSpec),</code> <p>To find the first key in the table, use <seealso marker="#first/1"><c>first/1</c></seealso>.</p> <p>Unless a table of type <c>set</c>, <c>bag</c>, or - <c>duplicate_bag</c> is protected using + <c>duplicate_bag</c> is fixated using <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso>, - a traversal can fail if - concurrent updates are made to the table. For table - type <c>ordered_set</c>, the function returns the next key in - order, even if the object does no longer exist.</p> + a call to <c>next/2</c> will fail if <c><anno>Key1</anno></c> no longer + exists in the table. For table type <c>ordered_set</c>, the function + always returns the next key after <c><anno>Key1</anno></c> in term + order, regardless whether <c><anno>Key1</anno></c> ever existed in the + table.</p> </desc> </func> <func> - <name name="prev" arity="2"/> + <name name="prev" arity="2" since=""/> <fsummary>Return the previous key in an ETS table of type <c>ordered_set</c>.</fsummary> <desc> @@ -1212,13 +1268,13 @@ ets:select(Table, MatchSpec),</code> table types, the function is synonymous to <seealso marker="#next/2"><c>next/2</c></seealso>. If no previous key exists, <c>'$end_of_table'</c> is returned.</p> - <p>To find the last key in the table, use + <p>To find the last key in an <c>ordered_set</c> table, use <seealso marker="#last/1"><c>last/1</c></seealso>.</p> </desc> </func> <func> - <name name="rename" arity="2"/> + <name name="rename" arity="2" since=""/> <fsummary>Rename a named ETS table.</fsummary> <desc> <p>Renames the named table <c><anno>Tab</anno></c> to the new name @@ -1228,7 +1284,7 @@ ets:select(Table, MatchSpec),</code> </func> <func> - <name name="repair_continuation" arity="2"/> + <name name="repair_continuation" arity="2" since=""/> <fsummary>Repair a continuation from <c>ets:select/1 or ets:select/3</c> that has passed through external representation.</fsummary> <desc> @@ -1283,11 +1339,20 @@ ets:select(ets:repair_continuation(Broken,MS)).</code> </func> <func> - <name name="safe_fixtable" arity="2"/> + <name name="safe_fixtable" arity="2" since=""/> <fsummary>Fix an ETS table for safe traversal.</fsummary> <desc> <p>Fixes a table of type <c>set</c>, <c>bag</c>, or - <c>duplicate_bag</c> for safe traversal.</p> + <c>duplicate_bag</c> for <seealso marker="#traversal"> + safe traversal</seealso> using + <seealso marker="#first/1"><c>first/1</c></seealso> & + <seealso marker="#next/2"><c>next/2</c></seealso>, + <seealso marker="#match/3"><c>match/3</c></seealso> & + <seealso marker="#match/1"><c>match/1</c></seealso>, + <seealso marker="#match_object/3"><c>match_object/3</c></seealso> & + <seealso marker="#match_object/1"><c>match_object/1</c></seealso>, or + <seealso marker="#select/3"><c>select/3</c></seealso> & + <seealso marker="#select/1"><c>select/1</c></seealso>.</p> <p>A process fixes a table by calling <c>safe_fixtable(<anno>Tab</anno>, true)</c>. The table remains fixed until the process releases it by calling @@ -1300,11 +1365,11 @@ ets:select(ets:repair_continuation(Broken,MS)).</code> <p>When a table is fixed, a sequence of <seealso marker="#first/1"><c>first/1</c></seealso> and <seealso marker="#next/2"><c>next/2</c></seealso> calls are - guaranteed to succeed, and each object in - the table is returned only once, even if objects - are removed or inserted during the traversal. The keys for new - objects inserted during the traversal <em>can</em> be returned by - <c>next/2</c> (it depends on the internal ordering of the keys).</p> + guaranteed to succeed even if keys are removed during the + traversal. The keys for objects inserted or deleted during a + traversal may or may not be returned by <c>next/2</c> depending on + the ordering of keys within the table and if the key exists at the time + <c>next/2</c> is called.</p> <p><em>Example:</em></p> <code type="none"> clean_all_with_value(Tab,X) -> @@ -1322,7 +1387,7 @@ clean_all_with_value(Tab,X,Key) -> true end, clean_all_with_value(Tab,X,ets:next(Tab,Key)).</code> - <p>Notice that no deleted objects are removed from a + <p>Notice that deleted objects are not freed from a fixed table until it has been released. If a process fixes a table but never releases it, the memory used by the deleted objects is never freed. The performance of operations on @@ -1332,14 +1397,14 @@ clean_all_with_value(Tab,X,Key) -> <c>info(Tab, safe_fixed_monotonic_time)</c></seealso>. A system with many processes fixing tables can need a monitor that sends alarms when tables have been fixed for too long.</p> - <p>Notice that for table type <c>ordered_set</c>, - <c>safe_fixtable/2</c> is not necessary, as calls to - <c>first/1</c> and <c>next/2</c> always succeed.</p> + <p>Notice that <c>safe_fixtable/2</c> is not necessary for table type + <c>ordered_set</c> and for traversals done by a single ETS function call, + like <seealso marker="#select/2"><c>select/2</c></seealso>.</p> </desc> </func> <func> - <name name="select" arity="1"/> + <name name="select" arity="1" since=""/> <fsummary>Continue matching objects in an ETS table.</fsummary> <desc> <p>Continues a match started with @@ -1353,7 +1418,7 @@ clean_all_with_value(Tab,X,Key) -> </func> <func> - <name name="select" arity="2"/> + <name name="select" arity="2" since=""/> <fsummary>Match the objects in an ETS table against a match specification.</fsummary> <desc> @@ -1448,7 +1513,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </func> <func> - <name name="select" arity="3"/> + <name name="select" arity="3" since=""/> <fsummary>Match the objects in an ETS table against a match specification and return part of the answers.</fsummary> <desc> @@ -1462,12 +1527,15 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> table, which is still faster than traversing the table object by object using <seealso marker="#first/1"><c>first/1</c></seealso> and <seealso marker="#next/2"><c>next/2</c></seealso>.</p> - <p>If the table is empty, <c>'$end_of_table'</c> is returned.</p> + <p>If the table is empty, <c>'$end_of_table'</c> is returned.</p> + <p>Use <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso> + to guarantee <seealso marker="#traversal">safe traversal</seealso> + for subsequent calls to <seealso marker="#select/1"><c>select/1</c></seealso>.</p> </desc> </func> <func> - <name name="select_count" arity="2"/> + <name name="select_count" arity="2" since=""/> <fsummary>Match the objects in an ETS table against a match specification and return the number of objects for which the match specification returned <c>true</c>.</fsummary> @@ -1486,7 +1554,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </func> <func> - <name name="select_delete" arity="2"/> + <name name="select_delete" arity="2" since=""/> <fsummary>Match the objects in an ETS table against a match specification and delete objects where the match specification returns <c>true</c>.</fsummary> @@ -1510,7 +1578,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </func> <func> - <name name="select_replace" arity="2"/> + <name name="select_replace" arity="2" since="OTP 20.0"/> <fsummary>Match and replace objects atomically in an ETS table</fsummary> <desc> <p>Matches the objects in the table <c><anno>Tab</anno></c> using a @@ -1519,7 +1587,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> the match specification result.</p> <p>The match-and-replace operation for each individual object is guaranteed to be <seealso marker="#concurrency">atomic and isolated</seealso>. The - <c>select_replace</c> table iteration as a whole, like all other select functions, + <c>select_replace</c> table traversal as a whole, like all other select functions, does not give such guarantees.</p> <p>The match specifiction must be guaranteed to <em>retain the key</em> of any matched object. If not, <c>select_replace</c> will fail with <c>badarg</c> @@ -1549,7 +1617,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="select_reverse" arity="1"/> + <name name="select_reverse" arity="1" since="OTP R14B"/> <fsummary>Continue matching objects in an ETS table.</fsummary> <desc> <p>Continues a match started with <seealso marker="#select_reverse/3"> @@ -1582,7 +1650,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="select_reverse" arity="2"/> + <name name="select_reverse" arity="2" since="OTP R14B"/> <fsummary>Match the objects in an ETS table against a match specification.</fsummary> <desc> @@ -1594,7 +1662,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="select_reverse" arity="3"/> + <name name="select_reverse" arity="3" since="OTP R14B"/> <fsummary>Match the objects in an ETS table against a match specification and return part of the answers.</fsummary> <desc> @@ -1612,7 +1680,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="setopts" arity="2"/> + <name name="setopts" arity="2" since=""/> <fsummary>Set table options.</fsummary> <desc> <p>Sets table options. The only allowed option to be set after the @@ -1623,7 +1691,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="slot" arity="2"/> + <name name="slot" arity="2" since=""/> <fsummary>Return all objects in a specified slot of an ETS table. </fsummary> <desc> @@ -1648,7 +1716,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="tab2file" arity="2"/> + <name name="tab2file" arity="2" since=""/> <fsummary>Dump an ETS table to a file.</fsummary> <desc> <p>Dumps table <c><anno>Tab</anno></c> to file @@ -1659,7 +1727,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="tab2file" arity="3"/> + <name name="tab2file" arity="3" since=""/> <fsummary>Dump an ETS table to a file.</fsummary> <desc> <p>Dumps table <c><anno>Tab</anno></c> to file @@ -1706,7 +1774,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="tab2list" arity="1"/> + <name name="tab2list" arity="1" since=""/> <fsummary>Return a list of all objects in an ETS table.</fsummary> <desc> <p>Returns a list of all objects in table <c><anno>Tab</anno></c>.</p> @@ -1714,7 +1782,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="tabfile_info" arity="1"/> + <name name="tabfile_info" arity="1" since=""/> <fsummary>Return a list of all objects in an ETS table.</fsummary> <desc> <p>Returns information about the table dumped to file by @@ -1792,8 +1860,8 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), </func> <func> - <name name="table" arity="1"/> - <name name="table" arity="2"/> + <name name="table" arity="1" since=""/> + <name name="table" arity="2" since=""/> <fsummary>Return a QLC query handle.</fsummary> <desc> <p>Returns a Query List @@ -1869,7 +1937,7 @@ true</pre> </func> <func> - <name name="take" arity="2"/> + <name name="take" arity="2" since="OTP 18.0"/> <fsummary>Return and remove all objects with a specified key from an ETS table.</fsummary> <desc> @@ -1884,7 +1952,7 @@ true</pre> </desc> </func> <func> - <name name="test_ms" arity="2"/> + <name name="test_ms" arity="2" since=""/> <fsummary>Test a match specification for use in <c>select/2</c>. </fsummary> <desc> @@ -1911,7 +1979,7 @@ true</pre> </func> <func> - <name name="to_dets" arity="2"/> + <name name="to_dets" arity="2" since=""/> <fsummary>Fill a Dets table with objects from an ETS table. </fsummary> <desc> @@ -1922,12 +1990,12 @@ true</pre> </func> <func> - <name name="update_counter" arity="3" clause_i="1"/> - <name name="update_counter" arity="4" clause_i="1"/> - <name name="update_counter" arity="3" clause_i="2"/> - <name name="update_counter" arity="4" clause_i="2"/> - <name name="update_counter" arity="3" clause_i="3"/> - <name name="update_counter" arity="4" clause_i="3"/> + <name name="update_counter" arity="3" clause_i="1" since=""/> + <name name="update_counter" arity="4" clause_i="1" since="OTP 18.0"/> + <name name="update_counter" arity="3" clause_i="2" since=""/> + <name name="update_counter" arity="4" clause_i="2" since="OTP 18.0"/> + <name name="update_counter" arity="3" clause_i="3" since=""/> + <name name="update_counter" arity="4" clause_i="3" since="OTP 18.0"/> <fsummary>Update a counter object in an ETS table.</fsummary> <type variable="Tab"/> <type variable="Key"/> @@ -2006,8 +2074,8 @@ true</pre> </func> <func> - <name name="update_element" arity="3" clause_i="1"/> - <name name="update_element" arity="3" clause_i="2"/> + <name name="update_element" arity="3" clause_i="1" since=""/> + <name name="update_element" arity="3" clause_i="2" since=""/> <fsummary>Update the <c>Pos</c>:th element of the object with a specified key in an ETS table.</fsummary> <type variable="Tab"/> @@ -2049,7 +2117,7 @@ true</pre> </func> <func> - <name name="whereis" arity="1"/> + <name name="whereis" arity="1" since="OTP 21.0"/> <fsummary>Retrieves the tid() of a named table.</fsummary> <desc> <p>This function returns the diff --git a/lib/stdlib/doc/src/file_sorter.xml b/lib/stdlib/doc/src/file_sorter.xml index e988d58c2f..942d98fe61 100644 --- a/lib/stdlib/doc/src/file_sorter.xml +++ b/lib/stdlib/doc/src/file_sorter.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>file_sorter.xml</file> </header> - <module>file_sorter</module> + <module since="">file_sorter</module> <modulesummary>File sorter.</modulesummary> <description> <p>This module contains functions for sorting terms on files, merging @@ -334,8 +334,8 @@ output(L) -> <funcs> <func> - <name name="check" arity="1"/> - <name name="check" arity="2"/> + <name name="check" arity="1" since=""/> + <name name="check" arity="2" since=""/> <fsummary>Check whether terms on files are sorted.</fsummary> <desc> <p>Checks files for sortedness. If a file is not sorted, the @@ -347,8 +347,8 @@ output(L) -> </func> <func> - <name name="keycheck" arity="2"/> - <name name="keycheck" arity="3"/> + <name name="keycheck" arity="2" since=""/> + <name name="keycheck" arity="3" since=""/> <fsummary>Check whether terms on files are sorted by key.</fsummary> <desc> <p>Checks files for sortedness. If a file is not sorted, the @@ -360,8 +360,8 @@ output(L) -> </func> <func> - <name name="keymerge" arity="3"/> - <name name="keymerge" arity="4"/> + <name name="keymerge" arity="3" since=""/> + <name name="keymerge" arity="4" since=""/> <fsummary>Merge terms on files by key.</fsummary> <desc> <p>Merges tuples on files. Each input file is assumed to be @@ -372,7 +372,7 @@ output(L) -> </func> <func> - <name name="keysort" arity="2"/> + <name name="keysort" arity="2" since=""/> <fsummary>Sort terms on files by key.</fsummary> <desc> <p>Sorts tuples on files.</p> @@ -382,8 +382,8 @@ output(L) -> </func> <func> - <name name="keysort" arity="3"/> - <name name="keysort" arity="4"/> + <name name="keysort" arity="3" since=""/> + <name name="keysort" arity="4" since=""/> <fsummary>Sort terms on files by key.</fsummary> <desc> <p>Sorts tuples on files. The sort is performed on the @@ -397,8 +397,8 @@ output(L) -> </func> <func> - <name name="merge" arity="2"/> - <name name="merge" arity="3"/> + <name name="merge" arity="2" since=""/> + <name name="merge" arity="3" since=""/> <fsummary>Merge terms on files.</fsummary> <desc> <p>Merges terms on files. Each input file is assumed to be @@ -409,7 +409,7 @@ output(L) -> </func> <func> - <name name="sort" arity="1"/> + <name name="sort" arity="1" since=""/> <fsummary>Sort terms on files.</fsummary> <desc> <p>Sorts terms on files.</p> @@ -419,8 +419,8 @@ output(L) -> </func> <func> - <name name="sort" arity="2"/> - <name name="sort" arity="3"/> + <name name="sort" arity="2" since=""/> + <name name="sort" arity="3" since=""/> <fsummary>Sort terms on files.</fsummary> <desc> <p>Sorts terms on files.</p> diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml index 3b5be75bc0..5df415834f 100644 --- a/lib/stdlib/doc/src/filelib.xml +++ b/lib/stdlib/doc/src/filelib.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>filelib.xml</file> </header> - <module>filelib</module> + <module since="">filelib</module> <modulesummary>File utilities, such as wildcard matching of filenames. </modulesummary> <description> @@ -94,7 +94,7 @@ <funcs> <func> - <name name="ensure_dir" arity="1"/> + <name name="ensure_dir" arity="1" since=""/> <fsummary>Ensure that all parent directories for a file or directory exist.</fsummary> <desc> @@ -108,7 +108,7 @@ </func> <func> - <name name="file_size" arity="1"/> + <name name="file_size" arity="1" since=""/> <fsummary>Return the size in bytes of a file.</fsummary> <desc> <p>Returns the size of the specified file.</p> @@ -116,7 +116,7 @@ </func> <func> - <name name="fold_files" arity="5"/> + <name name="fold_files" arity="5" since=""/> <fsummary>Fold over all files matching a regular expression.</fsummary> <desc> <p>Folds function <c><anno>Fun</anno></c> over all (regular) files @@ -142,7 +142,7 @@ </func> <func> - <name name="is_dir" arity="1"/> + <name name="is_dir" arity="1" since=""/> <fsummary>Test whether <c>Name</c> refers to a directory.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Name</anno></c> @@ -151,7 +151,7 @@ </func> <func> - <name name="is_file" arity="1"/> + <name name="is_file" arity="1" since=""/> <fsummary>Test whether <c>Name</c> refers to a file or directory. </fsummary> <desc> @@ -161,7 +161,7 @@ </func> <func> - <name name="is_regular" arity="1"/> + <name name="is_regular" arity="1" since=""/> <fsummary>Test whether <c>Name</c> refers to a (regular) file.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Name</anno></c> @@ -170,7 +170,7 @@ </func> <func> - <name name="last_modified" arity="1"/> + <name name="last_modified" arity="1" since=""/> <fsummary>Return the local date and time when a file was last modified. </fsummary> <desc> @@ -180,7 +180,7 @@ </func> <func> - <name name="wildcard" arity="1"/> + <name name="wildcard" arity="1" since=""/> <fsummary>Match filenames using Unix-style wildcards.</fsummary> <desc> <p>Returns a list of all files that match Unix-style wildcard string @@ -252,7 +252,7 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code> </func> <func> - <name name="wildcard" arity="2"/> + <name name="wildcard" arity="2" since=""/> <fsummary>Match filenames using Unix-style wildcards starting at a specified directory.</fsummary> <desc> @@ -263,8 +263,8 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code> </func> <func> - <name name="find_file" arity="2"/> - <name name="find_file" arity="3"/> + <name name="find_file" arity="2" since="OTP 20.0"/> + <name name="find_file" arity="3" since="OTP 20.0"/> <fsummary>Find a file relative to a given directory.</fsummary> <desc> <p>Looks for a file of the given name by applying suffix rules to @@ -278,7 +278,7 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code> </desc> </func> <func> - <name name="find_source" arity="1"/> + <name name="find_source" arity="1" since="OTP 20.0"/> <fsummary>Find the source file for a given object file.</fsummary> <desc> <p>Equivalent to <c>find_source(Base, Dir)</c>, where <c>Dir</c> is @@ -287,8 +287,8 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code> </desc> </func> <func> - <name name="find_source" arity="2"/> - <name name="find_source" arity="3"/> + <name name="find_source" arity="2" since="OTP 20.0"/> + <name name="find_source" arity="3" since="OTP 20.0"/> <fsummary>Find a source file relative to a given directory.</fsummary> <desc> <p>Applies file extension specific rules to find the source file for diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml index 36254c2d00..ae42846c6b 100644 --- a/lib/stdlib/doc/src/filename.xml +++ b/lib/stdlib/doc/src/filename.xml @@ -28,7 +28,7 @@ <date>1997-11-13</date> <rev>B</rev> </header> - <module>filename</module> + <module since="">filename</module> <modulesummary>Filename manipulation functions.</modulesummary> <description> <p>This module provides functions @@ -87,7 +87,7 @@ <funcs> <func> - <name name="absname" arity="1"/> + <name name="absname" arity="1" since=""/> <fsummary>Convert a filename to an absolute name, relative the working directory.</fsummary> <desc> @@ -119,7 +119,7 @@ </func> <func> - <name name="absname" arity="2"/> + <name name="absname" arity="2" since=""/> <fsummary>Convert a filename to an absolute name, relative a specified directory.</fsummary> <desc> @@ -130,7 +130,7 @@ </func> <func> - <name name="absname_join" arity="2"/> + <name name="absname_join" arity="2" since=""/> <fsummary>Join an absolute directory with a relative filename.</fsummary> <desc> <p>Joins an absolute directory with a relative filename. Similar to @@ -144,8 +144,8 @@ </func> <func> - <name name="basedir" arity="2" clause_i="1"/> - <name name="basedir" arity="2" clause_i="2"/> + <name name="basedir" arity="2" clause_i="1" since="OTP 19.0"/> + <name name="basedir" arity="2" clause_i="2" since="OTP 19.0"/> <fsummary>Equivalent to <c>basedir(<anno>PathType</anno>, <anno>Application</anno>,#{})</c> or <c>basedir(<anno>PathsType</anno>, <anno>Application</anno>,#{})</c>. @@ -165,8 +165,8 @@ basedir(<anno>PathsType</anno>, <anno>Application</anno>, #{})</seealso>. </desc> </func> <func> - <name name="basedir" arity="3" clause_i="1" anchor="basedir_3_1"/> - <name name="basedir" arity="3" clause_i="2" anchor="basedir_3_2"/> + <name name="basedir" arity="3" clause_i="1" anchor="basedir_3_1" since="OTP 19.0"/> + <name name="basedir" arity="3" clause_i="2" anchor="basedir_3_2" since="OTP 19.0"/> <fsummary></fsummary> <type variable="PathType" name_i="1"/> <type name="basedir_path_type"/> @@ -314,7 +314,7 @@ true </desc> </func> <func> - <name name="basename" arity="1"/> + <name name="basename" arity="1" since=""/> <fsummary>Return the last component of a filename.</fsummary> <desc> <p>Returns the last component of <c><anno>Filename</anno></c>, or @@ -332,7 +332,7 @@ true </func> <func> - <name name="basename" arity="2"/> + <name name="basename" arity="2" since=""/> <fsummary>Return the last component of a filename, stripped of the specified extension.</fsummary> <desc> @@ -357,7 +357,7 @@ true </func> <func> - <name name="dirname" arity="1"/> + <name name="dirname" arity="1" since=""/> <fsummary>Return the directory part of a path name.</fsummary> <desc> <p>Returns the directory part of <c><anno>Filename</anno></c>.</p> @@ -374,7 +374,7 @@ true </func> <func> - <name name="extension" arity="1"/> + <name name="extension" arity="1" since=""/> <fsummary>Return the file extension.</fsummary> <desc> <p>Returns the file extension of <c><anno>Filename</anno></c>, @@ -390,8 +390,8 @@ true </func> <func> - <name name="find_src" arity="1"/> - <name name="find_src" arity="2"/> + <name name="find_src" arity="1" since=""/> + <name name="find_src" arity="2" since=""/> <fsummary>Find the filename and compiler options for a module.</fsummary> <desc> <p>Finds the source filename and compiler options for a module. @@ -438,7 +438,7 @@ true </func> <func> - <name name="flatten" arity="1"/> + <name name="flatten" arity="1" since=""/> <fsummary>Convert a filename to a flat string.</fsummary> <desc> <p>Converts a possibly deep list filename consisting of @@ -448,7 +448,7 @@ true </func> <func> - <name name="join" arity="1"/> + <name name="join" arity="1" since=""/> <fsummary>Join a list of filename components with directory separators. </fsummary> <desc> @@ -476,7 +476,7 @@ true </func> <func> - <name name="join" arity="2"/> + <name name="join" arity="2" since=""/> <fsummary>Join two filename components with directory separators. </fsummary> <desc> @@ -487,7 +487,7 @@ true </func> <func> - <name name="nativename" arity="1"/> + <name name="nativename" arity="1" since=""/> <fsummary>Return the native form of a file path.</fsummary> <desc> <p>Converts <c><anno>Path</anno></c> to a form accepted by the command @@ -506,7 +506,7 @@ true </func> <func> - <name name="pathtype" arity="1"/> + <name name="pathtype" arity="1" since=""/> <fsummary>Return the path type.</fsummary> <desc> <p>Returns the path type, which is one of the following:</p> @@ -536,8 +536,8 @@ true </func> <func> - <name name="rootname" arity="1"/> - <name name="rootname" arity="2"/> + <name name="rootname" arity="1" since=""/> + <name name="rootname" arity="2" since=""/> <fsummary>Remove a filename extension.</fsummary> <desc> <p>Removes a filename extension. <c>rootname/2</c> works as @@ -557,7 +557,7 @@ true </func> <func> - <name name="safe_relative_path" arity="1"/> + <name name="safe_relative_path" arity="1" since="OTP 19.3"/> <fsummary>Sanitize a relative path to avoid directory traversal attacks.</fsummary> <desc> <p>Sanitizes the relative path by eliminating ".." and "." @@ -584,7 +584,7 @@ unsafe</pre> </func> <func> - <name name="split" arity="1"/> + <name name="split" arity="1" since=""/> <fsummary>Split a filename into its path components.</fsummary> <desc> <p>Returns a list whose elements are the path components of diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml index 03397b4503..a9596c6e4d 100644 --- a/lib/stdlib/doc/src/gb_sets.xml +++ b/lib/stdlib/doc/src/gb_sets.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>gb_sets</module> + <module since="">gb_sets</module> <modulesummary>General balanced trees.</modulesummary> <description> <p>This module provides ordered sets using Prof. Arne Andersson's @@ -123,8 +123,8 @@ <funcs> <func> - <name name="add" arity="2"/> - <name name="add_element" arity="2"/> + <name name="add" arity="2" since=""/> + <name name="add_element" arity="2" since=""/> <fsummary>Add a (possibly existing) element to a set.</fsummary> <desc> <p>Returns a new set formed from <c><anno>Set1</anno></c> with @@ -135,7 +135,7 @@ </func> <func> - <name name="balance" arity="1"/> + <name name="balance" arity="1" since=""/> <fsummary>Rebalance tree representation of a set.</fsummary> <desc> <p>Rebalances the tree representation of <c><anno>Set1</anno></c>. @@ -149,7 +149,7 @@ </func> <func> - <name name="del_element" arity="2"/> + <name name="del_element" arity="2" since=""/> <fsummary>Remove a (possibly non-existing) element from a set.</fsummary> <desc> <p>Returns a new set formed from <c><anno>Set1</anno></c> with @@ -160,7 +160,7 @@ </func> <func> - <name name="delete" arity="2"/> + <name name="delete" arity="2" since=""/> <fsummary>Remove an element from a set.</fsummary> <desc> <p>Returns a new set formed from <c><anno>Set1</anno></c> with @@ -171,7 +171,7 @@ </func> <func> - <name name="delete_any" arity="2"/> + <name name="delete_any" arity="2" since=""/> <fsummary>Remove a (possibly non-existing) element from a set.</fsummary> <desc> <p>Returns a new set formed from <c><anno>Set1</anno></c> with @@ -182,7 +182,7 @@ </func> <func> - <name name="difference" arity="2"/> + <name name="difference" arity="2" since=""/> <fsummary>Return the difference of two sets.</fsummary> <desc> <p>Returns only the elements of <c><anno>Set1</anno></c> that are not @@ -191,7 +191,7 @@ </func> <func> - <name name="empty" arity="0"/> + <name name="empty" arity="0" since=""/> <fsummary>Return an empty set.</fsummary> <desc> <p>Returns a new empty set.</p> @@ -199,7 +199,7 @@ </func> <func> - <name name="filter" arity="2"/> + <name name="filter" arity="2" since=""/> <fsummary>Filter set elements.</fsummary> <desc> <p>Filters elements in <c><anno>Set1</anno></c> using predicate function @@ -208,7 +208,7 @@ </func> <func> - <name name="fold" arity="3"/> + <name name="fold" arity="3" since=""/> <fsummary>Fold over set elements.</fsummary> <desc> <p>Folds <c><anno>Function</anno></c> over every element in @@ -218,7 +218,7 @@ </func> <func> - <name name="from_list" arity="1"/> + <name name="from_list" arity="1" since=""/> <fsummary>Convert a list into a set.</fsummary> <desc> <p>Returns a set of the elements in <c><anno>List</anno></c>, where @@ -227,7 +227,7 @@ </func> <func> - <name name="from_ordset" arity="1"/> + <name name="from_ordset" arity="1" since=""/> <fsummary>Make a set from an ordset list.</fsummary> <desc> <p>Turns an ordered-set list <c><anno>List</anno></c> into a set. @@ -236,7 +236,7 @@ </func> <func> - <name name="insert" arity="2"/> + <name name="insert" arity="2" since=""/> <fsummary>Add a new element to a set.</fsummary> <desc> <p>Returns a new set formed from <c><anno>Set1</anno></c> with @@ -247,7 +247,7 @@ </func> <func> - <name name="intersection" arity="1"/> + <name name="intersection" arity="1" since=""/> <fsummary>Return the intersection of a list of sets.</fsummary> <desc> <p>Returns the intersection of the non-empty list of sets.</p> @@ -255,7 +255,7 @@ </func> <func> - <name name="intersection" arity="2"/> + <name name="intersection" arity="2" since=""/> <fsummary>Return the intersection of two sets.</fsummary> <desc> <p>Returns the intersection of <c><anno>Set1</anno></c> and @@ -264,7 +264,7 @@ </func> <func> - <name name="is_disjoint" arity="2"/> + <name name="is_disjoint" arity="2" since=""/> <fsummary>Check whether two sets are disjoint.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Set1</anno></c> and @@ -274,7 +274,7 @@ </func> <func> - <name name="is_element" arity="2"/> + <name name="is_element" arity="2" since=""/> <fsummary>Test for membership of a set.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Element</anno></c> is an element of @@ -283,7 +283,7 @@ </func> <func> - <name name="is_empty" arity="1"/> + <name name="is_empty" arity="1" since=""/> <fsummary>Test for empty set.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Set</anno></c> is an empty set, @@ -292,7 +292,7 @@ </func> <func> - <name name="is_member" arity="2"/> + <name name="is_member" arity="2" since=""/> <fsummary>Test for membership of a set.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Element</anno></c> is an element of @@ -301,7 +301,7 @@ </func> <func> - <name name="is_set" arity="1"/> + <name name="is_set" arity="1" since=""/> <fsummary>Test for a set.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> appears to be a set, @@ -310,7 +310,7 @@ </func> <func> - <name name="is_subset" arity="2"/> + <name name="is_subset" arity="2" since=""/> <fsummary>Test for subset.</fsummary> <desc> <p>Returns <c>true</c> when every element of <c><anno>Set1</anno></c> is @@ -319,7 +319,7 @@ </func> <func> - <name name="iterator" arity="1"/> + <name name="iterator" arity="1" since=""/> <fsummary>Return an iterator for a set.</fsummary> <desc> <p>Returns an iterator that can be used for traversing the entries of @@ -336,7 +336,7 @@ </func> <func> - <name name="iterator_from" arity="2"/> + <name name="iterator_from" arity="2" since="OTP 18.0"/> <fsummary>Return an iterator for a set starting from a specified element. </fsummary> <desc> @@ -351,7 +351,7 @@ </func> <func> - <name name="largest" arity="1"/> + <name name="largest" arity="1" since=""/> <fsummary>Return largest element.</fsummary> <desc> <p>Returns the largest element in <c><anno>Set</anno></c>. Assumes that @@ -360,7 +360,7 @@ </func> <func> - <name name="new" arity="0"/> + <name name="new" arity="0" since=""/> <fsummary>Return an empty set.</fsummary> <desc> <p>Returns a new empty set.</p> @@ -368,7 +368,7 @@ </func> <func> - <name name="next" arity="1"/> + <name name="next" arity="1" since=""/> <fsummary>Traverse a set with an iterator.</fsummary> <desc> <p>Returns <c>{<anno>Element</anno>, <anno>Iter2</anno>}</c>, where @@ -381,7 +381,7 @@ </func> <func> - <name name="singleton" arity="1"/> + <name name="singleton" arity="1" since=""/> <fsummary>Return a set with one element.</fsummary> <desc> <p>Returns a set containing only element <c><anno>Element</anno></c>. @@ -390,7 +390,7 @@ </func> <func> - <name name="size" arity="1"/> + <name name="size" arity="1" since=""/> <fsummary>Return the number of elements in a set.</fsummary> <desc> <p>Returns the number of elements in <c><anno>Set</anno></c>.</p> @@ -398,7 +398,7 @@ </func> <func> - <name name="smallest" arity="1"/> + <name name="smallest" arity="1" since=""/> <fsummary>Return smallest element.</fsummary> <desc> <p>Returns the smallest element in <c><anno>Set</anno></c>. Assumes that @@ -407,7 +407,7 @@ </func> <func> - <name name="subtract" arity="2"/> + <name name="subtract" arity="2" since=""/> <fsummary>Return the difference of two sets.</fsummary> <desc> <p>Returns only the elements of <c><anno>Set1</anno></c> that are not @@ -416,7 +416,7 @@ </func> <func> - <name name="take_largest" arity="1"/> + <name name="take_largest" arity="1" since=""/> <fsummary>Extract largest element.</fsummary> <desc> <p>Returns <c>{<anno>Element</anno>, <anno>Set2</anno>}</c>, where @@ -428,7 +428,7 @@ </func> <func> - <name name="take_smallest" arity="1"/> + <name name="take_smallest" arity="1" since=""/> <fsummary>Extract smallest element.</fsummary> <desc> <p>Returns <c>{<anno>Element</anno>, <anno>Set2</anno>}</c>, where @@ -440,7 +440,7 @@ </func> <func> - <name name="to_list" arity="1"/> + <name name="to_list" arity="1" since=""/> <fsummary>Convert a set into a list.</fsummary> <desc> <p>Returns the elements of <c><anno>Set</anno></c> as a list.</p> @@ -448,7 +448,7 @@ </func> <func> - <name name="union" arity="1"/> + <name name="union" arity="1" since=""/> <fsummary>Return the union of a list of sets.</fsummary> <desc> <p>Returns the merged (union) set of the list of sets.</p> @@ -456,7 +456,7 @@ </func> <func> - <name name="union" arity="2"/> + <name name="union" arity="2" since=""/> <fsummary>Return the union of two sets.</fsummary> <desc> <p>Returns the merged (union) set of <c><anno>Set1</anno></c> and diff --git a/lib/stdlib/doc/src/gb_trees.xml b/lib/stdlib/doc/src/gb_trees.xml index 5cfff021c1..570c9c7cb6 100644 --- a/lib/stdlib/doc/src/gb_trees.xml +++ b/lib/stdlib/doc/src/gb_trees.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>gb_trees</module> + <module since="">gb_trees</module> <modulesummary>General balanced trees.</modulesummary> <description> <p>This module provides Prof. Arne Andersson's General @@ -75,7 +75,7 @@ <funcs> <func> - <name name="balance" arity="1"/> + <name name="balance" arity="1" since=""/> <fsummary>Rebalance a tree.</fsummary> <desc> <p>Rebalances <c><anno>Tree1</anno></c>. Notice that this is @@ -88,7 +88,7 @@ </func> <func> - <name name="delete" arity="2"/> + <name name="delete" arity="2" since=""/> <fsummary>Remove a node from a tree.</fsummary> <desc> <p>Removes the node with key <c><anno>Key</anno></c> from @@ -98,7 +98,7 @@ </func> <func> - <name name="delete_any" arity="2"/> + <name name="delete_any" arity="2" since=""/> <fsummary>Remove a (possibly non-existing) node from a tree.</fsummary> <desc> <p>Removes the node with key <c><anno>Key</anno></c> from @@ -109,7 +109,7 @@ </func> <func> - <name name="take" arity="2"/> + <name name="take" arity="2" since="OTP 20.0"/> <fsummary>Returns a value and new tree without node with key <c>Key</c>.</fsummary> <desc> <p>Returns a value <c><anno>Value</anno></c> from node with key <c><anno>Key</anno></c> @@ -120,7 +120,7 @@ </func> <func> - <name name="take_any" arity="2"/> + <name name="take_any" arity="2" since="OTP 20.0"/> <fsummary>Returns a value and new tree without node with key <c>Key</c>.</fsummary> <desc> <p>Returns a value <c><anno>Value</anno></c> from node with key <c><anno>Key</anno></c> @@ -131,7 +131,7 @@ </func> <func> - <name name="empty" arity="0"/> + <name name="empty" arity="0" since=""/> <fsummary>Return an empty tree.</fsummary> <desc> <p>Returns a new empty tree.</p> @@ -139,7 +139,7 @@ </func> <func> - <name name="enter" arity="3"/> + <name name="enter" arity="3" since=""/> <fsummary>Insert or update key with value in a tree.</fsummary> <desc> <p>Inserts <c><anno>Key</anno></c> with value <c><anno>Value</anno></c> @@ -151,7 +151,7 @@ </func> <func> - <name name="from_orddict" arity="1"/> + <name name="from_orddict" arity="1" since=""/> <fsummary>Make a tree from an orddict.</fsummary> <desc> <p>Turns an ordered list <c><anno>List</anno></c> of key-value tuples @@ -160,7 +160,7 @@ </func> <func> - <name name="get" arity="2"/> + <name name="get" arity="2" since=""/> <fsummary>Look up a key in a tree, if present.</fsummary> <desc> <p>Retrieves the value stored with <c><anno>Key</anno></c> in @@ -171,7 +171,7 @@ </func> <func> - <name name="insert" arity="3"/> + <name name="insert" arity="3" since=""/> <fsummary>Insert a new key and value in a tree.</fsummary> <desc> <p>Inserts <c><anno>Key</anno></c> with value <c><anno>Value</anno></c> @@ -182,7 +182,7 @@ </func> <func> - <name name="is_defined" arity="2"/> + <name name="is_defined" arity="2" since=""/> <fsummary>Test for membership of a tree.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Key</anno></c> is present in @@ -191,7 +191,7 @@ </func> <func> - <name name="is_empty" arity="1"/> + <name name="is_empty" arity="1" since=""/> <fsummary>Test for empty tree.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Tree</anno></c> is an empty tree, @@ -200,7 +200,7 @@ </func> <func> - <name name="iterator" arity="1"/> + <name name="iterator" arity="1" since=""/> <fsummary>Return an iterator for a tree.</fsummary> <desc> <p>Returns an iterator that can be used for traversing the @@ -218,7 +218,7 @@ </func> <func> - <name name="iterator_from" arity="2"/> + <name name="iterator_from" arity="2" since="OTP 18.0"/> <fsummary>Return an iterator for a tree starting from a specified key. </fsummary> <desc> @@ -233,7 +233,7 @@ </func> <func> - <name name="keys" arity="1"/> + <name name="keys" arity="1" since=""/> <fsummary>Return a list of the keys in a tree.</fsummary> <desc> <p>Returns the keys in <c><anno>Tree</anno></c> as an ordered list.</p> @@ -241,7 +241,7 @@ </func> <func> - <name name="largest" arity="1"/> + <name name="largest" arity="1" since=""/> <fsummary>Return largest key and value.</fsummary> <desc> <p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>}</c>, where @@ -253,7 +253,7 @@ </func> <func> - <name name="lookup" arity="2"/> + <name name="lookup" arity="2" since=""/> <fsummary>Look up a key in a tree.</fsummary> <desc> <p>Looks up <c><anno>Key</anno></c> in <c><anno>Tree</anno></c>. @@ -263,7 +263,7 @@ </func> <func> - <name name="map" arity="2"/> + <name name="map" arity="2" since=""/> <fsummary>Return largest key and value.</fsummary> <desc> <p>Maps function F(<anno>K</anno>, <anno>V1</anno>) -> <anno>V2</anno> @@ -275,7 +275,7 @@ </func> <func> - <name name="next" arity="1"/> + <name name="next" arity="1" since=""/> <fsummary>Traverse a tree with an iterator.</fsummary> <desc> <p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>, @@ -288,7 +288,7 @@ </func> <func> - <name name="size" arity="1"/> + <name name="size" arity="1" since=""/> <fsummary>Return the number of nodes in a tree.</fsummary> <desc> <p>Returns the number of nodes in <c><anno>Tree</anno></c>.</p> @@ -296,7 +296,7 @@ </func> <func> - <name name="smallest" arity="1"/> + <name name="smallest" arity="1" since=""/> <fsummary>Return smallest key and value.</fsummary> <desc> <p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>}</c>, where @@ -308,7 +308,7 @@ </func> <func> - <name name="take_largest" arity="1"/> + <name name="take_largest" arity="1" since=""/> <fsummary>Extract largest key and value.</fsummary> <desc> <p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>, @@ -321,7 +321,7 @@ </func> <func> - <name name="take_smallest" arity="1"/> + <name name="take_smallest" arity="1" since=""/> <fsummary>Extract smallest key and value.</fsummary> <desc> <p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>, @@ -334,7 +334,7 @@ </func> <func> - <name name="to_list" arity="1"/> + <name name="to_list" arity="1" since=""/> <fsummary>Convert a tree into a list.</fsummary> <desc> <p>Converts a tree into an ordered list of key-value tuples.</p> @@ -342,7 +342,7 @@ </func> <func> - <name name="update" arity="3"/> + <name name="update" arity="3" since=""/> <fsummary>Update a key to new value in a tree.</fsummary> <desc> <p>Updates <c><anno>Key</anno></c> to value <c><anno>Value</anno></c> @@ -352,7 +352,7 @@ </func> <func> - <name name="values" arity="1"/> + <name name="values" arity="1" since=""/> <fsummary>Return a list of the values in a tree.</fsummary> <desc> <p>Returns the values in <c><anno>Tree</anno></c> as an ordered list, diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml index fc34e51216..2915c4f507 100644 --- a/lib/stdlib/doc/src/gen_event.xml +++ b/lib/stdlib/doc/src/gen_event.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>gen_event</module> + <module since="">gen_event</module> <modulesummary>Generic event handling behavior.</modulesummary> <description> <p>This behavior module provides event handling functionality. It @@ -130,7 +130,7 @@ gen_event:stop -----> Module:terminate/2 <funcs> <func> - <name>add_handler(EventMgrRef, Handler, Args) -> Result</name> + <name since="">add_handler(EventMgrRef, Handler, Args) -> Result</name> <fsummary>Add an event handler to a generic event manager.</fsummary> <type> <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName} @@ -178,7 +178,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>add_sup_handler(EventMgrRef, Handler, Args) -> Result</name> + <name since="">add_sup_handler(EventMgrRef, Handler, Args) -> Result</name> <fsummary>Add a supervised event handler to a generic event manager. </fsummary> <type> @@ -241,8 +241,8 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>call(EventMgrRef, Handler, Request) -> Result</name> - <name>call(EventMgrRef, Handler, Request, Timeout) -> Result</name> + <name since="">call(EventMgrRef, Handler, Request) -> Result</name> + <name since="">call(EventMgrRef, Handler, Request, Timeout) -> Result</name> <fsummary>Make a synchronous call to a generic event manager.</fsummary> <type> <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName} @@ -285,7 +285,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>delete_handler(EventMgrRef, Handler, Args) -> Result</name> + <name since="">delete_handler(EventMgrRef, Handler, Args) -> Result</name> <fsummary>Delete an event handler from a generic event manager.</fsummary> <type> <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName} @@ -318,8 +318,8 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>notify(EventMgrRef, Event) -> ok</name> - <name>sync_notify(EventMgrRef, Event) -> ok</name> + <name since="">notify(EventMgrRef, Event) -> ok</name> + <name since="">sync_notify(EventMgrRef, Event) -> ok</name> <fsummary>Notify an event manager about an event.</fsummary> <type> <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName} @@ -349,9 +349,9 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>start() -> Result</name> - <name>start(EventMgrName | Options) -> Result</name> - <name>start(EventMgrName, Options) -> Result</name> + <name since="">start() -> Result</name> + <name since="">start(EventMgrName | Options) -> Result</name> + <name since="OTP 20.0">start(EventMgrName, Options) -> Result</name> <fsummary>Create a stand-alone event manager process.</fsummary> <type> <v>EventMgrName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}</v> @@ -375,9 +375,9 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>start_link() -> Result</name> - <name>start_link(EventMgrName | Options) -> Result</name> - <name>start_link(EventMgrName, Options) -> Result</name> + <name since="">start_link() -> Result</name> + <name since="">start_link(EventMgrName | Options) -> Result</name> + <name since="OTP 20.0">start_link(EventMgrName, Options) -> Result</name> <fsummary>Create a generic event manager process in a supervision tree. </fsummary> <type> @@ -436,8 +436,8 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>stop(EventMgrRef) -> ok</name> - <name>stop(EventMgrRef, Reason, Timeout) -> ok</name> + <name since="">stop(EventMgrRef) -> ok</name> + <name since="OTP 18.0">stop(EventMgrRef, Reason, Timeout) -> ok</name> <fsummary>Terminate a generic event manager.</fsummary> <type> <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName} @@ -474,7 +474,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name> + <name since="">swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name> <fsummary>Replace an event handler in a generic event manager.</fsummary> <type> <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName} @@ -521,7 +521,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name> + <name since="">swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name> <fsummary>Replace an event handler in a generic event manager.</fsummary> <type> <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName} @@ -546,7 +546,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>which_handlers(EventMgrRef) -> [Handler]</name> + <name since="">which_handlers(EventMgrRef) -> [Handler]</name> <fsummary>Return all event handlers installed in a generic event manager. </fsummary> <type> @@ -575,7 +575,7 @@ gen_event:stop -----> Module:terminate/2 <funcs> <func> - <name>Module:code_change(OldVsn, State, Extra) -> {ok, NewState}</name> + <name since="">Module:code_change(OldVsn, State, Extra) -> {ok, NewState}</name> <fsummary>Update the internal state during upgrade/downgrade.</fsummary> <type> <v>OldVsn = Vsn | {down, Vsn}</v> @@ -611,7 +611,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>Module:format_status(Opt, [PDict, State]) -> Status</name> + <name since="OTP R14B">Module:format_status(Opt, [PDict, State]) -> Status</name> <fsummary>Optional function for providing a term describing the current event handler state.</fsummary> <type> @@ -667,7 +667,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>Module:handle_call(Request, State) -> Result</name> + <name since="">Module:handle_call(Request, State) -> Result</name> <fsummary>Handle a synchronous request.</fsummary> <type> <v>Request = term()</v> @@ -698,7 +698,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>Module:handle_event(Event, State) -> Result</name> + <name since="">Module:handle_event(Event, State) -> Result</name> <fsummary>Handle an event.</fsummary> <type> <v>Event = term()</v> @@ -756,7 +756,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>Module:handle_info(Info, State) -> Result</name> + <name since="">Module:handle_info(Info, State) -> Result</name> <fsummary>Handle an incoming message.</fsummary> <type> <v>Info = term()</v> @@ -788,7 +788,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate} | {error,Reason}</name> + <name since="">Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate} | {error,Reason}</name> <fsummary>Initialize an event handler.</fsummary> <type> <v>InitArgs = Args | {Args,Term}</v> @@ -825,7 +825,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name>Module:terminate(Arg, State) -> term()</name> + <name since="">Module:terminate(Arg, State) -> term()</name> <fsummary>Clean up before deletion.</fsummary> <type> <v>Arg = Args | {stop,Reason} | stop | remove_handler</v> diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml index 106bda85f5..a4554d7657 100644 --- a/lib/stdlib/doc/src/gen_server.xml +++ b/lib/stdlib/doc/src/gen_server.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>gen_server</module> + <module since="">gen_server</module> <modulesummary>Generic server behavior.</modulesummary> <description> <p>This behavior module provides the server of a client-server @@ -101,8 +101,8 @@ gen_server:abcast -----> Module:handle_cast/2 <funcs> <func> - <name>abcast(Name, Request) -> abcast</name> - <name>abcast(Nodes, Name, Request) -> abcast</name> + <name since="">abcast(Name, Request) -> abcast</name> + <name since="">abcast(Nodes, Name, Request) -> abcast</name> <fsummary>Send an asynchronous request to many generic servers.</fsummary> <type> <v>Nodes = [Node]</v> @@ -124,8 +124,8 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>call(ServerRef, Request) -> Reply</name> - <name>call(ServerRef, Request, Timeout) -> Reply</name> + <name since="">call(ServerRef, Request) -> Reply</name> + <name since="">call(ServerRef, Request, Timeout) -> Reply</name> <fsummary>Make a synchronous call to a generic server.</fsummary> <type> <v>ServerRef = Name | {Name,Node} | {global,GlobalName}</v> @@ -175,7 +175,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>cast(ServerRef, Request) -> ok</name> + <name since="">cast(ServerRef, Request) -> ok</name> <fsummary>Send an asynchronous request to a generic server.</fsummary> <type> <v>ServerRef = Name | {Name,Node} | {global,GlobalName}</v> @@ -200,10 +200,10 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>enter_loop(Module, Options, State)</name> - <name>enter_loop(Module, Options, State, ServerName)</name> - <name>enter_loop(Module, Options, State, Timeout)</name> - <name>enter_loop(Module, Options, State, ServerName, Timeout)</name> + <name since="">enter_loop(Module, Options, State)</name> + <name since="">enter_loop(Module, Options, State, ServerName)</name> + <name since="">enter_loop(Module, Options, State, Timeout)</name> + <name since="">enter_loop(Module, Options, State, ServerName, Timeout)</name> <fsummary>Enter the <c>gen_server</c> receive loop.</fsummary> <type> <v>Module = atom()</v> @@ -248,9 +248,9 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>multi_call(Name, Request) -> Result</name> - <name>multi_call(Nodes, Name, Request) -> Result</name> - <name>multi_call(Nodes, Name, Request, Timeout) -> Result</name> + <name since="">multi_call(Name, Request) -> Result</name> + <name since="">multi_call(Nodes, Name, Request) -> Result</name> + <name since="">multi_call(Nodes, Name, Request, Timeout) -> Result</name> <fsummary>Make a synchronous call to many generic servers.</fsummary> <type> <v>Nodes = [Node]</v> @@ -307,7 +307,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>reply(Client, Reply) -> Result</name> + <name since="">reply(Client, Reply) -> Result</name> <fsummary>Send a reply to a client.</fsummary> <type> <v>Client - see below</v> @@ -332,8 +332,8 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>start(Module, Args, Options) -> Result</name> - <name>start(ServerName, Module, Args, Options) -> Result</name> + <name since="">start(Module, Args, Options) -> Result</name> + <name since="">start(ServerName, Module, Args, Options) -> Result</name> <fsummary>Create a standalone <c>gen_server</c> process.</fsummary> <type> <v>ServerName = {local,Name} | {global,GlobalName}</v> @@ -361,8 +361,8 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>start_link(Module, Args, Options) -> Result</name> - <name>start_link(ServerName, Module, Args, Options) -> Result</name> + <name since="">start_link(Module, Args, Options) -> Result</name> + <name since="">start_link(ServerName, Module, Args, Options) -> Result</name> <fsummary>Create a <c>gen_server</c> process in a supervision tree. </fsummary> <type> @@ -466,8 +466,8 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>stop(ServerRef) -> ok</name> - <name>stop(ServerRef, Reason, Timeout) -> ok</name> + <name since="OTP 18.0">stop(ServerRef) -> ok</name> + <name since="OTP 18.0">stop(ServerRef, Reason, Timeout) -> ok</name> <fsummary>Synchronously stop a generic server.</fsummary> <type> <v>ServerRef = Name | {Name,Node} | {global,GlobalName}</v> @@ -508,7 +508,7 @@ gen_server:abcast -----> Module:handle_cast/2 <funcs> <func> - <name>Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason}</name> + <name since="">Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason}</name> <fsummary>Update the internal state during upgrade/downgrade.</fsummary> <type> <v>OldVsn = Vsn | {down, Vsn}</v> @@ -550,7 +550,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>Module:format_status(Opt, [PDict, State]) -> Status</name> + <name since="OTP R13B04">Module:format_status(Opt, [PDict, State]) -> Status</name> <fsummary>Optional function for providing a term describing the current <c>gen_server</c> status.</fsummary> <type> @@ -610,7 +610,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>Module:handle_call(Request, From, State) -> Result</name> + <name since="">Module:handle_call(Request, From, State) -> Result</name> <fsummary>Handle a synchronous request.</fsummary> <type> <v>Request = term()</v> @@ -677,7 +677,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>Module:handle_cast(Request, State) -> Result</name> + <name since="">Module:handle_cast(Request, State) -> Result</name> <fsummary>Handle an asynchronous request.</fsummary> <type> <v>Request = term()</v> @@ -703,7 +703,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>Module:handle_continue(Continue, State) -> Result</name> + <name since="OTP 21.0">Module:handle_continue(Continue, State) -> Result</name> <fsummary>Handle a continue instruction.</fsummary> <type> <v>Continue = term()</v> @@ -738,7 +738,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>Module:handle_info(Info, State) -> Result</name> + <name since="">Module:handle_info(Info, State) -> Result</name> <fsummary>Handle an incoming message.</fsummary> <type> <v>Info = timeout | term()</v> @@ -770,7 +770,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>Module:init(Args) -> Result</name> + <name since="">Module:init(Args) -> Result</name> <fsummary>Initialize process and internal state.</fsummary> <type> <v>Args = term()</v> @@ -811,7 +811,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name>Module:terminate(Reason, State)</name> + <name since="">Module:terminate(Reason, State)</name> <fsummary>Clean up before termination.</fsummary> <type> <v>Reason = normal | shutdown | {shutdown,term()} | term()</v> diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml index a808d3af55..aaa26df18d 100644 --- a/lib/stdlib/doc/src/gen_statem.xml +++ b/lib/stdlib/doc/src/gen_statem.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>gen_statem</module> + <module since="OTP 19.0">gen_statem</module> <modulesummary>Generic state machine behavior.</modulesummary> <description> <p> @@ -1398,8 +1398,8 @@ handle_event(_, _, State, Data) -> <funcs> <func> - <name name="call" arity="2"/> - <name name="call" arity="3"/> + <name name="call" arity="2" since="OTP 19.0"/> + <name name="call" arity="3" since="OTP 19.0"/> <fsummary>Make a synchronous call to a <c>gen_statem</c>.</fsummary> <desc> <p> @@ -1474,7 +1474,7 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="cast" arity="2"/> + <name name="cast" arity="2" since="OTP 19.0"/> <fsummary>Send an asynchronous event to a <c>gen_statem</c>.</fsummary> <desc> <p> @@ -1493,7 +1493,7 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="enter_loop" arity="4"/> + <name name="enter_loop" arity="4" since="OTP 19.1"/> <fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary> <desc> <p> @@ -1507,7 +1507,7 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="enter_loop" arity="5"/> + <name name="enter_loop" arity="5" since="OTP 19.0"/> <fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary> <desc> <p> @@ -1531,7 +1531,7 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="enter_loop" arity="6"/> + <name name="enter_loop" arity="6" since="OTP 19.0"/> <fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary> <desc> <p> @@ -1588,8 +1588,8 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="reply" arity="1"/> - <name name="reply" arity="2"/> + <name name="reply" arity="1" since="OTP 19.0"/> + <name name="reply" arity="2" since="OTP 19.0"/> <fsummary>Reply to a caller.</fsummary> <desc> <p> @@ -1621,8 +1621,8 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="start" arity="3"/> - <name name="start" arity="4"/> + <name name="start" arity="3" since="OTP 19.0"/> + <name name="start" arity="4" since="OTP 19.0"/> <fsummary>Create a standalone <c>gen_statem</c> process.</fsummary> <desc> <p> @@ -1642,8 +1642,8 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="start_link" arity="3"/> - <name name="start_link" arity="4"/> + <name name="start_link" arity="3" since="OTP 19.0"/> + <name name="start_link" arity="4" since="OTP 19.0"/> <fsummary>Create a linked <c>gen_statem</c> process.</fsummary> <desc> <p> @@ -1750,7 +1750,7 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="stop" arity="1"/> + <name name="stop" arity="1" since="OTP 19.0"/> <fsummary>Synchronously stop a generic server.</fsummary> <desc> <p> @@ -1761,7 +1761,7 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="stop" arity="3"/> + <name name="stop" arity="3" since="OTP 19.0"/> <fsummary>Synchronously stop a generic server.</fsummary> <desc> <p> @@ -1807,7 +1807,7 @@ handle_event(_, _, State, Data) -> <funcs> <func> - <name>Module:callback_mode() -> CallbackMode</name> + <name since="OTP 19.1">Module:callback_mode() -> CallbackMode</name> <fsummary>Update the internal state during upgrade/downgrade.</fsummary> <type> <v> @@ -1858,7 +1858,7 @@ handle_event(_, _, State, Data) -> </func> <func> - <name>Module:code_change(OldVsn, OldState, OldData, Extra) -> + <name since="OTP 19.0">Module:code_change(OldVsn, OldState, OldData, Extra) -> Result </name> <fsummary>Update the internal state during upgrade/downgrade.</fsummary> @@ -1947,7 +1947,7 @@ handle_event(_, _, State, Data) -> </func> <func> - <name>Module:init(Args) -> Result(StateType)</name> + <name since="OTP 19.0">Module:init(Args) -> Result(StateType)</name> <fsummary> Initializing process and internal state. </fsummary> @@ -1989,7 +1989,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre> </func> <func> - <name>Module:format_status(Opt, [PDict,State,Data]) -> + <name since="OTP 19.0">Module:format_status(Opt, [PDict,State,Data]) -> Status </name> <fsummary>Optional function for providing a term describing the @@ -2088,16 +2088,16 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre> </func> <func> - <name>Module:StateName(enter, OldState, Data) -> + <name since="OTP 19.0">Module:StateName(enter, OldState, Data) -> StateEnterResult(StateName) </name> - <name>Module:StateName(EventType, EventContent, Data) -> + <name since="OTP 19.0">Module:StateName(EventType, EventContent, Data) -> StateFunctionResult </name> - <name>Module:handle_event(enter, OldState, State, Data) -> + <name since="OTP 19.0">Module:handle_event(enter, OldState, State, Data) -> StateEnterResult(State) </name> - <name>Module:handle_event(EventType, EventContent, State, Data) -> + <name since="OTP 19.0">Module:handle_event(EventType, EventContent, State, Data) -> HandleEventResult </name> <fsummary>Handle an event.</fsummary> @@ -2216,7 +2216,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre> </func> <func> - <name>Module:terminate(Reason, State, Data) -> Ignored</name> + <name since="OTP 19.0">Module:terminate(Reason, State, Data) -> Ignored</name> <fsummary>Clean up before termination.</fsummary> <type> <v>Reason = normal | shutdown | {shutdown,term()} | term()</v> diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml index d4a2713840..d69e808586 100644 --- a/lib/stdlib/doc/src/io.xml +++ b/lib/stdlib/doc/src/io.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>io</module> + <module since="">io</module> <modulesummary>Standard I/O server interface functions.</modulesummary> <description> <p>This module provides an interface to standard Erlang I/O servers. @@ -104,8 +104,8 @@ <funcs> <func> - <name name="columns" arity="0"/> - <name name="columns" arity="1"/> + <name name="columns" arity="0" since=""/> + <name name="columns" arity="1" since=""/> <fsummary>Get the number of columns of an I/O device.</fsummary> <desc> <p>Retrieves the number of columns of the @@ -116,12 +116,12 @@ </func> <func> - <name name="format" arity="1"/> - <name name="format" arity="2"/> - <name name="format" arity="3"/> - <name name="fwrite" arity="1"/> - <name name="fwrite" arity="2"/> - <name name="fwrite" arity="3"/> + <name name="format" arity="1" since=""/> + <name name="format" arity="2" since=""/> + <name name="format" arity="3" since=""/> + <name name="fwrite" arity="1" since=""/> + <name name="fwrite" arity="2" since=""/> + <name name="fwrite" arity="3" since=""/> <fsummary>Write formatted output.</fsummary> <desc> <p>Writes the items in <c><anno>Data</anno></c> (<c>[]</c>) on the @@ -523,8 +523,8 @@ ok </func> <func> - <name name="fread" arity="2"/> - <name name="fread" arity="3"/> + <name name="fread" arity="2" since=""/> + <name name="fread" arity="3" since=""/> <fsummary>Read formatted input.</fsummary> <type name="server_no_data"/> <desc> @@ -690,8 +690,8 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in </func> <func> - <name name="get_chars" arity="2"/> - <name name="get_chars" arity="3"/> + <name name="get_chars" arity="2" since=""/> + <name name="get_chars" arity="3" since=""/> <fsummary>Read a specified number of characters.</fsummary> <type name="server_no_data"/> <desc> @@ -722,8 +722,8 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in </func> <func> - <name name="get_line" arity="1"/> - <name name="get_line" arity="2"/> + <name name="get_line" arity="1" since=""/> + <name name="get_line" arity="2" since=""/> <fsummary>Read a line.</fsummary> <type name="server_no_data"/> <desc> @@ -754,8 +754,8 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in </func> <func> - <name name="getopts" arity="0"/> - <name name="getopts" arity="1"/> + <name name="getopts" arity="0" since=""/> + <name name="getopts" arity="1" since=""/> <fsummary>Get the supported options and values from an I/O server. </fsummary> <desc> @@ -781,8 +781,8 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in </func> <func> - <name name="nl" arity="0"/> - <name name="nl" arity="1"/> + <name name="nl" arity="0" since=""/> + <name name="nl" arity="1" since=""/> <fsummary>Write a newline.</fsummary> <desc> <p>Writes new line to the standard output @@ -791,10 +791,10 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in </func> <func> - <name name="parse_erl_exprs" arity="1"/> - <name name="parse_erl_exprs" arity="2"/> - <name name="parse_erl_exprs" arity="3"/> - <name name="parse_erl_exprs" arity="4"/> + <name name="parse_erl_exprs" arity="1" since=""/> + <name name="parse_erl_exprs" arity="2" since=""/> + <name name="parse_erl_exprs" arity="3" since=""/> + <name name="parse_erl_exprs" arity="4" since="OTP R16B"/> <fsummary>Read, tokenize, and parse Erlang expressions.</fsummary> <type name="parse_ret"/> <type name="server_no_data"/> @@ -844,10 +844,10 @@ enter><input>abc("hey".</input> </func> <func> - <name name="parse_erl_form" arity="1"/> - <name name="parse_erl_form" arity="2"/> - <name name="parse_erl_form" arity="3"/> - <name name="parse_erl_form" arity="4"/> + <name name="parse_erl_form" arity="1" since=""/> + <name name="parse_erl_form" arity="2" since=""/> + <name name="parse_erl_form" arity="3" since=""/> + <name name="parse_erl_form" arity="4" since="OTP R16B"/> <fsummary>Read, tokenize, and parse an Erlang form.</fsummary> <type name="parse_form_ret"/> <type name="server_no_data"/> @@ -888,7 +888,7 @@ enter><input>abc("hey".</input> </func> <func> - <name name="printable_range" arity="0"/> + <name name="printable_range" arity="0" since="OTP R16B"/> <fsummary>Get user-requested printable character range.</fsummary> <desc> <p>Returns the user-requested range of printable Unicode characters.</p> @@ -918,8 +918,8 @@ enter><input>abc("hey".</input> </func> <func> - <name name="put_chars" arity="1"/> - <name name="put_chars" arity="2"/> + <name name="put_chars" arity="1" since=""/> + <name name="put_chars" arity="2" since=""/> <fsummary>Write a list of characters.</fsummary> <desc> <p>Writes the characters of <c><anno>CharData</anno></c> to the I/O @@ -928,8 +928,8 @@ enter><input>abc("hey".</input> </func> <func> - <name name="read" arity="1"/> - <name name="read" arity="2"/> + <name name="read" arity="1" since=""/> + <name name="read" arity="2" since=""/> <fsummary>Read a term.</fsummary> <type name="server_no_data"/> <desc> @@ -960,8 +960,8 @@ enter><input>abc("hey".</input> </func> <func> - <name name="read" arity="3"/> - <name name="read" arity="4"/> + <name name="read" arity="3" since=""/> + <name name="read" arity="4" since="OTP R16B"/> <fsummary>Read a term.</fsummary> <type name="server_no_data"/> <desc> @@ -997,8 +997,8 @@ enter><input>abc("hey".</input> </func> <func> - <name name="rows" arity="0"/> - <name name="rows" arity="1"/> + <name name="rows" arity="0" since=""/> + <name name="rows" arity="1" since=""/> <fsummary>Get the number of rows of an I/O device.</fsummary> <desc> <p>Retrieves the number of rows of <c><anno>IoDevice</anno></c> @@ -1009,10 +1009,10 @@ enter><input>abc("hey".</input> </func> <func> - <name name="scan_erl_exprs" arity="1"/> - <name name="scan_erl_exprs" arity="2"/> - <name name="scan_erl_exprs" arity="3"/> - <name name="scan_erl_exprs" arity="4"/> + <name name="scan_erl_exprs" arity="1" since=""/> + <name name="scan_erl_exprs" arity="2" since=""/> + <name name="scan_erl_exprs" arity="3" since=""/> + <name name="scan_erl_exprs" arity="4" since="OTP R16B"/> <fsummary>Read and tokenize Erlang expressions.</fsummary> <type name="server_no_data"/> <desc> @@ -1060,10 +1060,10 @@ enter><input>1.0er.</input> </func> <func> - <name name="scan_erl_form" arity="1"/> - <name name="scan_erl_form" arity="2"/> - <name name="scan_erl_form" arity="3"/> - <name name="scan_erl_form" arity="4"/> + <name name="scan_erl_form" arity="1" since=""/> + <name name="scan_erl_form" arity="2" since=""/> + <name name="scan_erl_form" arity="3" since=""/> + <name name="scan_erl_form" arity="4" since="OTP R16B"/> <fsummary>Read and tokenize an Erlang form.</fsummary> <type name="server_no_data"/> <desc> @@ -1083,8 +1083,8 @@ enter><input>1.0er.</input> </func> <func> - <name name="setopts" arity="1"/> - <name name="setopts" arity="2"/> + <name name="setopts" arity="1" since=""/> + <name name="setopts" arity="2" since=""/> <fsummary>Set options.</fsummary> <desc> <p>Set options for the standard I/O device @@ -1198,8 +1198,8 @@ fun("") -> {yes, "quit", []}; </func> <func> - <name name="write" arity="1"/> - <name name="write" arity="2"/> + <name name="write" arity="1" since=""/> + <name name="write" arity="2" since=""/> <fsummary>Write a term.</fsummary> <desc> <p>Writes term <c><anno>Term</anno></c> to the standard output diff --git a/lib/stdlib/doc/src/io_lib.xml b/lib/stdlib/doc/src/io_lib.xml index a3df2897ac..4d527f8ed3 100644 --- a/lib/stdlib/doc/src/io_lib.xml +++ b/lib/stdlib/doc/src/io_lib.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>io_lib</module> + <module since="">io_lib</module> <modulesummary>I/O library functions.</modulesummary> <description> <p>This module contains functions for converting to and from @@ -99,7 +99,7 @@ <funcs> <func> - <name name="build_text" arity="1"/> + <name name="build_text" arity="1" since="OTP 18.0"/> <fsummary>Build the output text for a preparsed format list.</fsummary> <desc> <p>For details, see @@ -108,7 +108,7 @@ </func> <func> - <name name="char_list" arity="1"/> + <name name="char_list" arity="1" since=""/> <fsummary>Test for a list of characters.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of @@ -117,7 +117,7 @@ </func> <func> - <name name="deep_char_list" arity="1"/> + <name name="deep_char_list" arity="1" since=""/> <fsummary>Test for a deep list of characters.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a, possibly deep, @@ -126,7 +126,7 @@ </func> <func> - <name name="deep_latin1_char_list" arity="1"/> + <name name="deep_latin1_char_list" arity="1" since="OTP R16B"/> <fsummary>Test for a deep list of characters.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a, possibly deep, @@ -136,8 +136,8 @@ </func> <func> - <name name="format" arity="2"/> - <name name="fwrite" arity="2"/> + <name name="format" arity="2" since=""/> + <name name="fwrite" arity="2" since=""/> <fsummary>Write formatted output.</fsummary> <desc> <p>Returns a character list that represents <c><anno>Data</anno></c> @@ -156,8 +156,8 @@ </func> <func> - <name name="format" arity="3"/> - <name name="fwrite" arity="3"/> + <name name="format" arity="3" since="OTP 21.0"/> + <name name="fwrite" arity="3" since="OTP 21.0"/> <fsummary>Write formatted output.</fsummary> <desc> <p>Returns a character list that represents <c><anno>Data</anno></c> @@ -181,7 +181,7 @@ </func> <func> - <name name="fread" arity="2"/> + <name name="fread" arity="2" since=""/> <fsummary>Read formatted input.</fsummary> <desc> <p>Tries to read <c><anno>String</anno></c> in accordance with the @@ -222,7 +222,7 @@ </func> <func> - <name name="fread" arity="3"/> + <name name="fread" arity="3" since=""/> <fsummary>Re-entrant formatted reader</fsummary> <desc> <p>This is the re-entrant formatted reader. The continuation of @@ -268,7 +268,7 @@ </func> <func> - <name name="indentation" arity="2"/> + <name name="indentation" arity="2" since=""/> <fsummary>Indentation after printing string.</fsummary> <desc> <p>Returns the indentation if <c><anno>String</anno></c> has been @@ -277,7 +277,7 @@ </func> <func> - <name name="latin1_char_list" arity="1"/> + <name name="latin1_char_list" arity="1" since="OTP R16B"/> <fsummary>Test for a list of ISO Latin-1 characters.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of @@ -286,7 +286,7 @@ </func> <func> - <name name="nl" arity="0"/> + <name name="nl" arity="0" since=""/> <fsummary>Write a newline.</fsummary> <desc> <p>Returns a character list that represents a new line character.</p> @@ -294,8 +294,8 @@ </func> <func> - <name name="print" arity="1"/> - <name name="print" arity="4"/> + <name name="print" arity="1" since=""/> + <name name="print" arity="4" since=""/> <fsummary>Pretty print a term.</fsummary> <desc> <p>Returns a list of characters that represents @@ -315,7 +315,7 @@ </func> <func> - <name name="printable_latin1_list" arity="1"/> + <name name="printable_latin1_list" arity="1" since="OTP R16B"/> <fsummary>Test for a list of printable ISO Latin-1 characters.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of @@ -324,7 +324,7 @@ </func> <func> - <name name="printable_list" arity="1"/> + <name name="printable_list" arity="1" since=""/> <fsummary>Test for a list of printable characters.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of @@ -338,7 +338,7 @@ </func> <func> - <name name="printable_unicode_list" arity="1"/> + <name name="printable_unicode_list" arity="1" since="OTP R16B"/> <fsummary>Test for a list of printable Unicode characters.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of @@ -347,7 +347,7 @@ </func> <func> - <name name="scan_format" arity="2"/> + <name name="scan_format" arity="2" since="OTP 18.0"/> <fsummary>Parse all control sequences in the format string.</fsummary> <desc> <p>Returns a list corresponding to the specified format string, @@ -373,7 +373,7 @@ </func> <func> - <name name="unscan_format" arity="1"/> + <name name="unscan_format" arity="1" since="OTP 18.0"/> <fsummary>Revert a preparsed format list to a plain character list and a list of arguments.</fsummary> <desc> @@ -383,9 +383,9 @@ </func> <func> - <name name="write" arity="1"/> - <name name="write" arity="2" clause_i="1"/> - <name name="write" arity="2" clause_i="2"/> + <name name="write" arity="1" since=""/> + <name name="write" arity="2" clause_i="1" since=""/> + <name name="write" arity="2" clause_i="2" since="OTP 20.0"/> <fsummary>Write a term.</fsummary> <desc> <p>Returns a character list that represents <c><anno>Term</anno></c>. @@ -411,7 +411,7 @@ </func> <func> - <name name="write_atom" arity="1"/> + <name name="write_atom" arity="1" since=""/> <fsummary>Write an atom.</fsummary> <desc> <p>Returns the list of characters needed to print atom @@ -420,7 +420,7 @@ </func> <func> - <name name="write_atom_as_latin1" arity="1"/> + <name name="write_atom_as_latin1" arity="1" since="OTP 20.0"/> <fsummary>Write an atom.</fsummary> <desc> <p>Returns the list of characters needed to print atom @@ -430,7 +430,7 @@ </func> <func> - <name name="write_char" arity="1"/> + <name name="write_char" arity="1" since=""/> <fsummary>Write a character.</fsummary> <desc> <p>Returns the list of characters needed to print a character @@ -439,7 +439,7 @@ </func> <func> - <name name="write_char_as_latin1" arity="1"/> + <name name="write_char_as_latin1" arity="1" since="OTP R16B"/> <fsummary>Write a character.</fsummary> <desc> <p>Returns the list of characters needed to print a character @@ -449,7 +449,7 @@ </func> <func> - <name name="write_latin1_char" arity="1"/> + <name name="write_latin1_char" arity="1" since="OTP R16B"/> <fsummary>Write an ISO Latin-1 character.</fsummary> <desc> <p>Returns the list of characters needed to print a character @@ -458,7 +458,7 @@ </func> <func> - <name name="write_latin1_string" arity="1"/> + <name name="write_latin1_string" arity="1" since="OTP R16B"/> <fsummary>Write an ISO Latin-1 string.</fsummary> <desc> <p>Returns the list of characters needed to print @@ -467,7 +467,7 @@ </func> <func> - <name name="write_string" arity="1"/> + <name name="write_string" arity="1" since=""/> <fsummary>Write a string.</fsummary> <desc> <p>Returns the list of characters needed to print @@ -476,7 +476,7 @@ </func> <func> - <name name="write_string_as_latin1" arity="1"/> + <name name="write_string_as_latin1" arity="1" since="OTP R16B"/> <fsummary>Write a string.</fsummary> <desc> <p>Returns the list of characters needed to print diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml index e4215a5336..2755fb3dce 100644 --- a/lib/stdlib/doc/src/lists.xml +++ b/lib/stdlib/doc/src/lists.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2018</year> + <year>1996</year><year>2019</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -28,7 +28,7 @@ <date>1996-09-28</date> <rev>A</rev> </header> - <module>lists</module> + <module since="">lists</module> <modulesummary>List processing functions.</modulesummary> <description> <p>This module contains functions for list processing.</p> @@ -63,7 +63,7 @@ <funcs> <func> - <name name="all" arity="2"/> + <name name="all" arity="2" since=""/> <fsummary>Return <c>true</c> if all elements in a list satisfy <c>Pred</c>.</fsummary> <desc> @@ -74,7 +74,7 @@ </func> <func> - <name name="any" arity="2"/> + <name name="any" arity="2" since=""/> <fsummary>Return <c>true</c> if any of the elements in a list satisfies <c>Pred</c>.</fsummary> <desc> @@ -85,7 +85,7 @@ </func> <func> - <name name="append" arity="1"/> + <name name="append" arity="1" since=""/> <fsummary>Append a list of lists.</fsummary> <desc> <p>Returns a list in which all the sublists of @@ -98,7 +98,7 @@ </func> <func> - <name name="append" arity="2"/> + <name name="append" arity="2" since=""/> <fsummary>Append two lists.</fsummary> <desc> <p>Returns a new list <c><anno>List3</anno></c>, which is made from @@ -113,7 +113,7 @@ </func> <func> - <name name="concat" arity="1"/> + <name name="concat" arity="1" since=""/> <fsummary>Concatenate a list of atoms.</fsummary> <desc> <p>Concatenates the text representation of the elements of @@ -127,7 +127,7 @@ </func> <func> - <name name="delete" arity="2"/> + <name name="delete" arity="2" since=""/> <fsummary>Delete an element from a list.</fsummary> <desc> <p>Returns a copy of <c><anno>List1</anno></c> where the first element @@ -137,7 +137,7 @@ </func> <func> - <name name="droplast" arity="1"/> + <name name="droplast" arity="1" since="OTP 17.0"/> <fsummary>Drop the last element of a list.</fsummary> <desc> <p>Drops the last element of a <c><anno>List</anno></c>. The list is to @@ -147,7 +147,7 @@ </func> <func> - <name name="dropwhile" arity="2"/> + <name name="dropwhile" arity="2" since=""/> <fsummary>Drop elements from a list while a predicate is <c>true</c>. </fsummary> <desc> @@ -159,7 +159,7 @@ </func> <func> - <name name="duplicate" arity="2"/> + <name name="duplicate" arity="2" since=""/> <fsummary>Make <c>N</c> copies of element.</fsummary> <desc> <p>Returns a list containing <c><anno>N</anno></c> copies of term @@ -172,7 +172,7 @@ </func> <func> - <name name="filter" arity="2"/> + <name name="filter" arity="2" since=""/> <fsummary>Select elements that satisfy a predicate.</fsummary> <desc> <p><c><anno>List2</anno></c> is a list of all elements @@ -182,7 +182,7 @@ </func> <func> - <name name="filtermap" arity="2"/> + <name name="filtermap" arity="2" since="OTP R16B01"/> <fsummary>Filter and map elements that satisfy a function.</fsummary> <desc> <p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>)</c> on successive @@ -211,7 +211,7 @@ filtermap(Fun, List1) -> </func> <func> - <name name="flatlength" arity="1"/> + <name name="flatlength" arity="1" since=""/> <fsummary>Length of flattened deep list.</fsummary> <desc> <p>Equivalent to <c>length(flatten(<anno>DeepList</anno>))</c>, but @@ -220,7 +220,7 @@ filtermap(Fun, List1) -> </func> <func> - <name name="flatmap" arity="2"/> + <name name="flatmap" arity="2" since=""/> <fsummary>Map and flatten in one pass.</fsummary> <desc> <p>Takes a function from <c><anno>A</anno></c>s to lists of @@ -241,7 +241,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="flatten" arity="1"/> + <name name="flatten" arity="1" since=""/> <fsummary>Flatten a deep list.</fsummary> <desc> <p>Returns a flattened version of <c><anno>DeepList</anno></c>.</p> @@ -249,7 +249,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="flatten" arity="2"/> + <name name="flatten" arity="2" since=""/> <fsummary>Flatten a deep list.</fsummary> <desc> <p>Returns a flattened version of <c><anno>DeepList</anno></c> with tail @@ -258,7 +258,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="foldl" arity="3"/> + <name name="foldl" arity="3" since=""/> <fsummary>Fold a function over a list.</fsummary> <desc> <p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>, <anno>AccIn</anno>)</c> @@ -278,7 +278,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="foldr" arity="3"/> + <name name="foldr" arity="3" since=""/> <fsummary>Fold a function over a list.</fsummary> <desc> <p>Like <seealso marker="#foldl/3"><c>foldl/3</c></seealso>, but the @@ -297,7 +297,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="join" arity="2"/> + <name name="join" arity="2" since="OTP 19.0"/> <fsummary>Insert an element between elements in a list</fsummary> <desc> <p>Inserts <c><anno>Sep</anno></c> between each element in <c><anno>List1</anno></c>. Has no @@ -312,7 +312,7 @@ flatmap(Fun, List1) -> </desc> </func> <func> - <name name="foreach" arity="2"/> + <name name="foreach" arity="2" since=""/> <fsummary>Apply a function to each element of a list.</fsummary> <desc> <p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>)</c> for each element @@ -324,7 +324,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keydelete" arity="3"/> + <name name="keydelete" arity="3" since=""/> <fsummary>Delete an element from a list of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -336,7 +336,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keyfind" arity="3"/> + <name name="keyfind" arity="3" since=""/> <fsummary>Search for an element in a list of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -349,7 +349,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keymap" arity="3"/> + <name name="keymap" arity="3" since=""/> <fsummary>Map a function over a list of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -368,7 +368,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keymember" arity="3"/> + <name name="keymember" arity="3" since=""/> <fsummary>Test for membership of a list of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -379,7 +379,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keymerge" arity="3"/> + <name name="keymerge" arity="3" since=""/> <fsummary>Merge two key-sorted lists of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -395,7 +395,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keyreplace" arity="4"/> + <name name="keyreplace" arity="4" since=""/> <fsummary>Replace an element in a list of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -407,7 +407,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keysearch" arity="3"/> + <name name="keysearch" arity="3" since=""/> <fsummary>Search for an element in a list of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -425,7 +425,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keysort" arity="2"/> + <name name="keysort" arity="2" since=""/> <fsummary>Sort a list of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -436,7 +436,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keystore" arity="4"/> + <name name="keystore" arity="4" since=""/> <fsummary>Store an element in a list of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -452,7 +452,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="keytake" arity="3"/> + <name name="keytake" arity="3" since=""/> <fsummary>Extract an element from a list of tuples.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -467,7 +467,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="last" arity="1"/> + <name name="last" arity="1" since=""/> <fsummary>Return last element in a list.</fsummary> <desc> <p>Returns the last element in <c><anno>List</anno></c>.</p> @@ -475,7 +475,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="map" arity="2"/> + <name name="map" arity="2" since=""/> <fsummary>Map a function over a list.</fsummary> <desc> <p>Takes a function from <c><anno>A</anno></c>s to @@ -488,7 +488,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="mapfoldl" arity="3"/> + <name name="mapfoldl" arity="3" since=""/> <fsummary>Map and fold in one pass.</fsummary> <desc> <p>Combines the operations of @@ -504,7 +504,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="mapfoldr" arity="3"/> + <name name="mapfoldr" arity="3" since=""/> <fsummary>Map and fold in one pass.</fsummary> <desc> <p>Combines the operations of @@ -514,7 +514,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="max" arity="1"/> + <name name="max" arity="1" since=""/> <fsummary>Return maximum element of a list.</fsummary> <desc> <p>Returns the first element of <c><anno>List</anno></c> that compares @@ -524,7 +524,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="member" arity="2"/> + <name name="member" arity="2" since=""/> <fsummary>Test for membership of a list.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Elem</anno></c> matches some element @@ -533,7 +533,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="merge" arity="1"/> + <name name="merge" arity="1" since=""/> <fsummary>Merge a list of sorted lists.</fsummary> <desc> <p>Returns the sorted list formed by merging all the sublists of @@ -546,7 +546,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="merge" arity="2"/> + <name name="merge" arity="2" since=""/> <fsummary>Merge two sorted lists.</fsummary> <desc> <p>Returns the sorted list formed by merging <c><anno>List1</anno></c> @@ -559,7 +559,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="merge" arity="3"/> + <name name="merge" arity="3" since=""/> <fsummary>Merge two sorted list.</fsummary> <desc> <p>Returns the sorted list formed by merging <c><anno>List1</anno></c> @@ -577,7 +577,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="merge3" arity="3"/> + <name name="merge3" arity="3" since=""/> <fsummary>Merge three sorted lists.</fsummary> <desc> <p>Returns the sorted list formed by merging <c><anno>List1</anno></c>, @@ -593,7 +593,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="min" arity="1"/> + <name name="min" arity="1" since=""/> <fsummary>Return minimum element of a list.</fsummary> <desc> <p>Returns the first element of <c><anno>List</anno></c> that compares @@ -603,7 +603,7 @@ flatmap(Fun, List1) -> </func> <func> - <name name="nth" arity="2"/> + <name name="nth" arity="2" since=""/> <fsummary>Return the <c>N</c>th element of a list.</fsummary> <type_desc variable="N">1..length(<anno>List</anno>)</type_desc> <desc> @@ -617,7 +617,7 @@ c</pre> </func> <func> - <name name="nthtail" arity="2"/> + <name name="nthtail" arity="2" since=""/> <fsummary>Return the <c>N</c>th tail of a list.</fsummary> <type_desc variable="N">0..length(<anno>List</anno>)</type_desc> <desc> @@ -638,7 +638,7 @@ c</pre> </func> <func> - <name name="partition" arity="2"/> + <name name="partition" arity="2" since=""/> <fsummary>Partition a list into two lists based on a predicate.</fsummary> <desc> <p>Partitions <c><anno>List</anno></c> into two lists, where the first @@ -658,7 +658,7 @@ c</pre> </func> <func> - <name name="prefix" arity="2"/> + <name name="prefix" arity="2" since=""/> <fsummary>Test for list prefix.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>List1</anno></c> is a prefix of @@ -667,7 +667,7 @@ c</pre> </func> <func> - <name name="reverse" arity="1"/> + <name name="reverse" arity="1" since=""/> <fsummary>Reverse a list.</fsummary> <desc> <p>Returns a list with the elements in <c><anno>List1</anno></c> @@ -676,7 +676,7 @@ c</pre> </func> <func> - <name name="reverse" arity="2"/> + <name name="reverse" arity="2" since=""/> <fsummary>Reverse a list appending a tail.</fsummary> <desc> <p>Returns a list with the elements in <c><anno>List1</anno></c> @@ -689,8 +689,20 @@ c</pre> </func> <func> - <name name="seq" arity="2"/> - <name name="seq" arity="3"/> + <name name="search" arity="2" since="OTP 21.0"/> + <fsummary>Find the first element that satisfies a predicate.</fsummary> + <desc> + <p>If there is a <c><anno>Value</anno></c> in <c><anno>List</anno></c> + such that <c><anno>Pred</anno>(<anno>Value</anno>)</c> returns + <c>true</c>, returns <c>{value, <anno>Value</anno>}</c> + for the first such <c><anno>Value</anno></c>, + otherwise returns <c>false</c>.</p> + </desc> + </func> + + <func> + <name name="seq" arity="2" since=""/> + <name name="seq" arity="3" since=""/> <fsummary>Generate a sequence of integers.</fsummary> <desc> <p>Returns a sequence of integers that starts with @@ -736,7 +748,7 @@ length(lists:seq(From, To, Incr)) =:= (To - From + Incr) div Incr</code> </func> <func> - <name name="sort" arity="1"/> + <name name="sort" arity="1" since=""/> <fsummary>Sort a list.</fsummary> <desc> <p>Returns a list containing the sorted elements of @@ -745,7 +757,7 @@ length(lists:seq(From, To, Incr)) =:= (To - From + Incr) div Incr</code> </func> <func> - <name name="sort" arity="2"/> + <name name="sort" arity="2" since=""/> <fsummary>Sort a list.</fsummary> <desc> <p>Returns a list containing the sorted elements of @@ -759,7 +771,7 @@ length(lists:seq(From, To, Incr)) =:= (To - From + Incr) div Incr</code> </func> <func> - <name name="split" arity="2"/> + <name name="split" arity="2" since=""/> <fsummary>Split a list into two lists.</fsummary> <type_desc variable="N">0..length(<anno>List1</anno>)</type_desc> <desc> @@ -771,19 +783,7 @@ length(lists:seq(From, To, Incr)) =:= (To - From + Incr) div Incr</code> </func> <func> - <name name="search" arity="2"/> - <fsummary>Find the first element that satisfies a predicate.</fsummary> - <desc> - <p>If there is a <c><anno>Value</anno></c> in <c><anno>List</anno></c> - such that <c><anno>Pred</anno>(<anno>Value</anno>)</c> returns - <c>true</c>, returns <c>{value, <anno>Value</anno>}</c> - for the first such <c><anno>Value</anno></c>, - otherwise returns <c>false</c>.</p> - </desc> - </func> - - <func> - <name name="splitwith" arity="2"/> + <name name="splitwith" arity="2" since=""/> <fsummary>Split a list into two lists based on a predicate.</fsummary> <desc> <p>Partitions <c><anno>List</anno></c> into two lists according to @@ -804,7 +804,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="sublist" arity="2"/> + <name name="sublist" arity="2" since=""/> <fsummary>Return a sublist of a certain length, starting at the first position.</fsummary> <desc> @@ -816,7 +816,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="sublist" arity="3"/> + <name name="sublist" arity="3" since=""/> <fsummary>Return a sublist starting at a specified position and with a specified number of elements.</fsummary> <type_desc variable="Start">1..(length(<anno>List1</anno>)+1)</type_desc> @@ -838,7 +838,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="subtract" arity="2"/> + <name name="subtract" arity="2" since=""/> <fsummary>Subtract the element in one list from another list.</fsummary> <desc> <p>Returns a new list <c><anno>List3</anno></c> that is a copy of @@ -854,7 +854,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="suffix" arity="2"/> + <name name="suffix" arity="2" since=""/> <fsummary>Test for list suffix.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>List1</anno></c> is a suffix of @@ -863,7 +863,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="sum" arity="1"/> + <name name="sum" arity="1" since=""/> <fsummary>Return the sum of elements in a list.</fsummary> <desc> <p>Returns the sum of the elements in <c><anno>List</anno></c>.</p> @@ -871,7 +871,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="takewhile" arity="2"/> + <name name="takewhile" arity="2" since=""/> <fsummary>Take elements from a list while a predicate is <c>true</c>. </fsummary> <desc> @@ -884,7 +884,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="ukeymerge" arity="3"/> + <name name="ukeymerge" arity="3" since=""/> <fsummary>Merge two key-sorted lists of tuples, removing duplicates. </fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> @@ -902,7 +902,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="ukeysort" arity="2"/> + <name name="ukeysort" arity="2" since=""/> <fsummary>Sort a list of tuples, removing duplicates.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -914,7 +914,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="umerge" arity="1"/> + <name name="umerge" arity="1" since=""/> <fsummary>Merge a list of sorted lists, removing duplicates.</fsummary> <desc> <p>Returns the sorted list formed by merging all the sublists @@ -927,7 +927,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="umerge" arity="2"/> + <name name="umerge" arity="2" since=""/> <fsummary>Merge two sorted lists, removing duplicates.</fsummary> <desc> <p>Returns the sorted list formed by merging <c><anno>List1</anno></c> @@ -941,7 +941,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="umerge" arity="3"/> + <name name="umerge" arity="3" since=""/> <fsummary>Merge two sorted lists, removing duplicates.</fsummary> <desc> <p>Returns the sorted list formed by merging <c><anno>List1</anno></c> @@ -958,7 +958,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="umerge3" arity="3"/> + <name name="umerge3" arity="3" since=""/> <fsummary>Merge three sorted lists, removing duplicates.</fsummary> <desc> <p>Returns the sorted list formed by merging <c><anno>List1</anno></c>, @@ -973,7 +973,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="unzip" arity="1"/> + <name name="unzip" arity="1" since=""/> <fsummary>Unzip a list of two-tuples into two lists.</fsummary> <desc> <p>"Unzips" a list of two-tuples into two lists, where the first @@ -983,7 +983,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="unzip3" arity="1"/> + <name name="unzip3" arity="1" since=""/> <fsummary>Unzip a list of three-tuples into three lists.</fsummary> <desc> <p>"Unzips" a list of three-tuples into three lists, where @@ -994,7 +994,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="usort" arity="1"/> + <name name="usort" arity="1" since=""/> <fsummary>Sort a list, removing duplicates.</fsummary> <desc> <p>Returns a list containing the sorted elements of @@ -1004,7 +1004,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="usort" arity="2"/> + <name name="usort" arity="2" since=""/> <fsummary>Sort a list, removing duplicates.</fsummary> <desc> <p>Returns a list containing the sorted elements of @@ -1019,7 +1019,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="zip" arity="2"/> + <name name="zip" arity="2" since=""/> <fsummary>Zip two lists into a list of two-tuples.</fsummary> <desc> <p>"Zips" two lists of equal length into one list of two-tuples, @@ -1030,7 +1030,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="zip3" arity="3"/> + <name name="zip3" arity="3" since=""/> <fsummary>Zip three lists into a list of three-tuples.</fsummary> <desc> <p>"Zips" three lists of equal length into one list of @@ -1042,7 +1042,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="zipwith" arity="3"/> + <name name="zipwith" arity="3" since=""/> <fsummary>Zip two lists into one list according to a fun.</fsummary> <desc> <p>Combines the elements of two lists of equal length into one list. @@ -1059,7 +1059,7 @@ splitwith(Pred, List) -> </func> <func> - <name name="zipwith3" arity="4"/> + <name name="zipwith3" arity="4" since=""/> <fsummary>Zip three lists into one list according to a fun.</fsummary> <desc> <p>Combines the elements of three lists of equal length into one diff --git a/lib/stdlib/doc/src/log_mf_h.xml b/lib/stdlib/doc/src/log_mf_h.xml index edc3d31025..b922006cc0 100644 --- a/lib/stdlib/doc/src/log_mf_h.xml +++ b/lib/stdlib/doc/src/log_mf_h.xml @@ -34,7 +34,7 @@ <rev>A</rev> <file>log_mf_h.xml</file> </header> - <module>log_mf_h</module> + <module since="">log_mf_h</module> <modulesummary>An event handler that logs events to disk.</modulesummary> <description> <p>This module is a <c>gen_event</c> handler module that can be installed @@ -60,8 +60,8 @@ <funcs> <func> - <name name="init" arity="3"/> - <name name="init" arity="4"/> + <name name="init" arity="3" since=""/> + <name name="init" arity="4" since=""/> <fsummary>Initiate the event handler.</fsummary> <desc> <p>Initiates the event handler. Returns <c><anno>Args</anno></c>, which diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml index a225dea3b5..e2a62cb397 100644 --- a/lib/stdlib/doc/src/maps.xml +++ b/lib/stdlib/doc/src/maps.xml @@ -27,7 +27,7 @@ <date>2014-02-28</date> <rev>A</rev> </header> - <module>maps</module> + <module since="OTP 17.0">maps</module> <modulesummary>Maps processing functions.</modulesummary> <description> <p>This module contains functions for maps processing.</p> @@ -49,7 +49,7 @@ <funcs> <func> - <name name="filter" arity="2"/> + <name name="filter" arity="2" since="OTP 18.0"/> <fsummary>Select pairs that satisfy a predicate.</fsummary> <desc> <p>Returns a map <c><anno>Map</anno></c> for which predicate @@ -68,7 +68,7 @@ </func> <func> - <name name="find" arity="2"/> + <name name="find" arity="2" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Returns a tuple <c>{ok, Value}</c>, where <c><anno>Value</anno></c> @@ -87,7 +87,7 @@ </func> <func> - <name name="fold" arity="3"/> + <name name="fold" arity="3" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Calls <c>F(K, V, AccIn)</c> for every <c><anno>K</anno></c> to value @@ -111,7 +111,7 @@ </func> <func> - <name name="from_list" arity="1"/> + <name name="from_list" arity="1" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Takes a list of key-value tuples elements and builds a map. The @@ -128,7 +128,7 @@ </func> <func> - <name name="get" arity="2"/> + <name name="get" arity="2" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Returns value <c><anno>Value</anno></c> associated with @@ -147,7 +147,7 @@ </func> <func> - <name name="get" arity="3"/> + <name name="get" arity="3" since="OTP 17.1"/> <fsummary></fsummary> <desc> <p>Returns value <c><anno>Value</anno></c> associated with @@ -168,7 +168,7 @@ val1 </func> <func> - <name name="is_key" arity="2"/> + <name name="is_key" arity="2" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Returns <c>true</c> if map <c><anno>Map</anno></c> contains @@ -188,7 +188,7 @@ false</code> </func> <func> - <name name="iterator" arity="1"/> + <name name="iterator" arity="1" since="OTP 21.0"/> <fsummary>Create a map iterator.</fsummary> <desc> <p>Returns a map iterator <c><anno>Iterator</anno></c> that can @@ -202,19 +202,19 @@ false</code> <code type="none"> > M = #{ a => 1, b => 2 }. #{a => 1,b => 2} -> I = maps:iterator(M). -[{a,1},{b,2}] -> {K1, V1, I2} = maps:next(I). -{a,1,[{b,2}]} -> {K2, V2, I3} = maps:next(I2). -{b,2,[]} +> I = maps:iterator(M), ok. +ok +> {K1, V1, I2} = maps:next(I), {K1, V1}. +{a,1} +> {K2, V2, I3} = maps:next(I2),{K2, V2}. +{b,2} > maps:next(I3). none</code> </desc> </func> <func> - <name name="keys" arity="1"/> + <name name="keys" arity="1" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Returns a complete list of keys, in any order, which resides @@ -230,7 +230,7 @@ none</code> </func> <func> - <name name="map" arity="2"/> + <name name="map" arity="2" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Produces a new map <c><anno>Map</anno></c> by calling function @@ -253,7 +253,7 @@ none</code> </func> <func> - <name name="merge" arity="2"/> + <name name="merge" arity="2" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Merges two maps into a single map <c><anno>Map3</anno></c>. If two @@ -271,7 +271,7 @@ none</code> </func> <func> - <name name="new" arity="0"/> + <name name="new" arity="0" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Returns a new empty map.</p> @@ -283,7 +283,7 @@ none</code> </func> <func> - <name name="next" arity="1"/> + <name name="next" arity="1" since="OTP 21.0"/> <fsummary>Get the next key and value from an iterator.</fsummary> <desc> <p>Returns the next key-value association in @@ -298,21 +298,21 @@ none</code> <code type="none"> > Map = #{a => 1, b => 2, c => 3}. #{a => 1,b => 2,c => 3} -> Iter = maps:iterator(Map). -[{a,1},{b,2},{c,3}] -> {_, _, Iter1} = maps:next(Iter). -{a,1,[{b,2},{c,3}]} -> {_, _, Iter2} = maps:next(Iter1). -{b,2,[{c,3}]} -> {_, _, Iter3} = maps:next(Iter2). -{c,3,[]} -> maps:next(Iter3). +> I = maps:iterator(Map), ok. +ok +> {K1, V1, I1} = maps:next(I), {K1, V1}. +{a,1} +> {K2, V2, I2} = maps:next(I1), {K2, V2}. +{b,2} +> {K3, V3, I3} = maps:next(I2), {K3, V3}. +{c,3} +> maps:next(I3). none</code> </desc> </func> <func> - <name name="put" arity="3"/> + <name name="put" arity="3" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Associates <c><anno>Key</anno></c> with value @@ -336,7 +336,7 @@ none</code> </func> <func> - <name name="remove" arity="2"/> + <name name="remove" arity="2" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Removes the <c><anno>Key</anno></c>, if it exists, and its @@ -356,7 +356,7 @@ none</code> </func> <func> - <name name="size" arity="1"/> + <name name="size" arity="1" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Returns the number of key-value associations in @@ -370,7 +370,7 @@ none</code> </func> <func> - <name name="take" arity="2"/> + <name name="take" arity="2" since="OTP 19.0"/> <fsummary></fsummary> <desc> <p>The function removes the <c><anno>Key</anno></c>, if it @@ -395,7 +395,7 @@ error</code> </func> <func> - <name name="to_list" arity="1"/> + <name name="to_list" arity="1" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Returns a list of pairs representing the key-value associations of @@ -412,7 +412,7 @@ error</code> </func> <func> - <name name="update" arity="3"/> + <name name="update" arity="3" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>If <c><anno>Key</anno></c> exists in <c><anno>Map1</anno></c>, the @@ -432,7 +432,7 @@ error</code> </func> <func> - <name name="update_with" arity="3"/> + <name name="update_with" arity="3" since="OTP 19.0"/> <fsummary></fsummary> <desc> <p>Update a value in a <c><anno>Map1</anno></c> associated @@ -451,7 +451,7 @@ error</code> </func> <func> - <name name="update_with" arity="4"/> + <name name="update_with" arity="4" since="OTP 19.0"/> <fsummary></fsummary> <desc> <p>Update a value in a <c><anno>Map1</anno></c> associated @@ -471,7 +471,7 @@ error</code> </func> <func> - <name name="values" arity="1"/> + <name name="values" arity="1" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Returns a complete list of values, in arbitrary order, contained in @@ -487,7 +487,7 @@ error</code> </func> <func> - <name name="with" arity="2"/> + <name name="with" arity="2" since="OTP 17.3"/> <fsummary></fsummary> <desc> <p>Returns a new map <c><anno>Map2</anno></c> with the keys <c>K1</c> @@ -504,7 +504,7 @@ error</code> </func> <func> - <name name="without" arity="2"/> + <name name="without" arity="2" since="OTP 17.0"/> <fsummary></fsummary> <desc> <p>Returns a new map <c><anno>Map2</anno></c> without keys <c>K1</c> diff --git a/lib/stdlib/doc/src/math.xml b/lib/stdlib/doc/src/math.xml index b4f096217a..d89310e2c8 100644 --- a/lib/stdlib/doc/src/math.xml +++ b/lib/stdlib/doc/src/math.xml @@ -34,7 +34,7 @@ <rev>B</rev> <file>math.xml</file> </header> - <module>math</module> + <module since="">math</module> <modulesummary>Mathematical functions.</modulesummary> <description> <p>This module provides an interface to a number of mathematical @@ -50,28 +50,28 @@ <funcs> <func> - <name name="acos" arity="1"/> - <name name="acosh" arity="1"/> - <name name="asin" arity="1"/> - <name name="asinh" arity="1"/> - <name name="atan" arity="1"/> - <name name="atan2" arity="2"/> - <name name="atanh" arity="1"/> - <name name="ceil" arity="1"/> - <name name="cos" arity="1"/> - <name name="cosh" arity="1"/> - <name name="exp" arity="1"/> - <name name="floor" arity="1"/> - <name name="fmod" arity="2"/> - <name name="log" arity="1"/> - <name name="log10" arity="1"/> - <name name="log2" arity="1"/> - <name name="pow" arity="2"/> - <name name="sin" arity="1"/> - <name name="sinh" arity="1"/> - <name name="sqrt" arity="1"/> - <name name="tan" arity="1"/> - <name name="tanh" arity="1"/> + <name name="acos" arity="1" since=""/> + <name name="acosh" arity="1" since=""/> + <name name="asin" arity="1" since=""/> + <name name="asinh" arity="1" since=""/> + <name name="atan" arity="1" since=""/> + <name name="atan2" arity="2" since=""/> + <name name="atanh" arity="1" since=""/> + <name name="ceil" arity="1" since="OTP 20.0"/> + <name name="cos" arity="1" since=""/> + <name name="cosh" arity="1" since=""/> + <name name="exp" arity="1" since=""/> + <name name="floor" arity="1" since="OTP 20.0"/> + <name name="fmod" arity="2" since="OTP 20.0"/> + <name name="log" arity="1" since=""/> + <name name="log10" arity="1" since=""/> + <name name="log2" arity="1" since="OTP 18.0"/> + <name name="pow" arity="2" since=""/> + <name name="sin" arity="1" since=""/> + <name name="sinh" arity="1" since=""/> + <name name="sqrt" arity="1" since=""/> + <name name="tan" arity="1" since=""/> + <name name="tanh" arity="1" since=""/> <fsummary>Diverse math functions.</fsummary> <type variable="X" name_i="6"/> <type variable="Y" name_i="6"/> @@ -82,7 +82,7 @@ </func> <func> - <name name="erf" arity="1"/> + <name name="erf" arity="1" since=""/> <fsummary>Error function.</fsummary> <desc> <p>Returns the error function of <c><anno>X</anno></c>, where:</p> @@ -92,7 +92,7 @@ erf(X) = 2/sqrt(pi)*integral from 0 to X of exp(-t*t) dt.</pre> </func> <func> - <name name="erfc" arity="1"/> + <name name="erfc" arity="1" since=""/> <fsummary>Another error function.</fsummary> <desc> <p><c>erfc(X)</c> returns <c>1.0</c> - <c>erf(X)</c>, computed by @@ -101,7 +101,7 @@ erf(X) = 2/sqrt(pi)*integral from 0 to X of exp(-t*t) dt.</pre> </func> <func> - <name name="pi" arity="0"/> + <name name="pi" arity="0" since=""/> <fsummary>A useful number.</fsummary> <desc> <p>A useful number.</p> diff --git a/lib/stdlib/doc/src/ms_transform.xml b/lib/stdlib/doc/src/ms_transform.xml index 0a05fa37c5..65cc150507 100644 --- a/lib/stdlib/doc/src/ms_transform.xml +++ b/lib/stdlib/doc/src/ms_transform.xml @@ -32,7 +32,7 @@ <rev>C</rev> <file>ms_transform.xml</file> </header> - <module>ms_transform</module> + <module since="">ms_transform</module> <modulesummary>A parse transformation that translates fun syntax into match specifications.</modulesummary> <description> @@ -731,7 +731,7 @@ ets:select(Table, [{{'$1',test,'$2'},[],['$_']}]).</code> <funcs> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Error formatting function as required by the parse transformation interface.</fsummary> <desc> <p>Takes an error code returned by one of the other functions @@ -741,7 +741,7 @@ ets:select(Table, [{{'$1',test,'$2'},[],['$_']}]).</code> </func> <func> - <name name="parse_transform" arity="2"/> + <name name="parse_transform" arity="2" since=""/> <fsummary>Transforms Erlang abstract format containing calls to ets/dbg:fun2ms/1 into literal match specifications.</fsummary> <type_desc variable="Options">Option list, required but not used. @@ -762,7 +762,7 @@ ets:select(Table, [{{'$1',test,'$2'},[],['$_']}]).</code> </func> <func> - <name name="transform_from_shell" arity="3"/> + <name name="transform_from_shell" arity="3" since=""/> <fsummary>Used when transforming funs created in the shell into match_specifications.</fsummary> <type_desc variable="BoundEnvironment">List of variable bindings in the diff --git a/lib/stdlib/doc/src/orddict.xml b/lib/stdlib/doc/src/orddict.xml index 26bbf499c6..27ccccee7e 100644 --- a/lib/stdlib/doc/src/orddict.xml +++ b/lib/stdlib/doc/src/orddict.xml @@ -32,7 +32,7 @@ <rev>B</rev> <file>orddict.xml</file> </header> - <module>orddict</module> + <module since="">orddict</module> <modulesummary>Key-value dictionary as ordered list.</modulesummary> <description> <p>This module provides a <c>Key</c>-<c>Value</c> dictionary. @@ -61,7 +61,7 @@ <funcs> <func> - <name name="append" arity="3"/> + <name name="append" arity="3" since=""/> <fsummary>Append a value to keys in a dictionary.</fsummary> <desc> <p>Appends a new <c><anno>Value</anno></c> to the current list @@ -73,7 +73,7 @@ </func> <func> - <name name="append_list" arity="3"/> + <name name="append_list" arity="3" since=""/> <fsummary>Append new values to keys in a dictionary.</fsummary> <desc> <p>Appends a list of values <c><anno>ValList</anno></c> to @@ -85,7 +85,7 @@ </func> <func> - <name name="erase" arity="2"/> + <name name="erase" arity="2" since=""/> <fsummary>Erase a key from a dictionary.</fsummary> <desc> <p>Erases all items with a specified key from a dictionary.</p> @@ -93,7 +93,7 @@ </func> <func> - <name name="fetch" arity="2"/> + <name name="fetch" arity="2" since=""/> <fsummary>Look up values in a dictionary.</fsummary> <desc> <p>Returns the value associated with <c><anno>Key</anno></c> @@ -105,7 +105,7 @@ </func> <func> - <name name="fetch_keys" arity="1"/> + <name name="fetch_keys" arity="1" since=""/> <fsummary>Return all keys in a dictionary.</fsummary> <desc> <p>Returns a list of all keys in a dictionary.</p> @@ -113,7 +113,7 @@ </func> <func> - <name name="take" arity="2"/> + <name name="take" arity="2" since="OTP 20.0"/> <fsummary>Return value and new dictionary without element with this value.</fsummary> <desc> <p>This function returns value from dictionary and new dictionary without this value. @@ -122,7 +122,7 @@ </func> <func> - <name name="filter" arity="2"/> + <name name="filter" arity="2" since=""/> <fsummary>Select elements that satisfy a predicate.</fsummary> <desc> <p><c><anno>Orddict2</anno></c> is a dictionary of all keys and values @@ -133,7 +133,7 @@ </func> <func> - <name name="find" arity="2"/> + <name name="find" arity="2" since=""/> <fsummary>Search for a key in a dictionary.</fsummary> <desc> <p>Searches for a key in a dictionary. Returns @@ -145,7 +145,7 @@ </func> <func> - <name name="fold" arity="3"/> + <name name="fold" arity="3" since=""/> <fsummary>Fold a function over a dictionary.</fsummary> <desc> <p>Calls <c><anno>Fun</anno></c> on successive keys and values of @@ -157,7 +157,7 @@ </func> <func> - <name name="from_list" arity="1"/> + <name name="from_list" arity="1" since=""/> <fsummary>Convert a list of pairs to a dictionary.</fsummary> <desc> <p>Converts the <c><anno>Key</anno></c>-<c><anno>Value</anno></c> list @@ -166,7 +166,7 @@ </func> <func> - <name name="is_empty" arity="1"/> + <name name="is_empty" arity="1" since="OTP 17.0"/> <fsummary>Return true if the dictionary is empty.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Orddict</anno></c> has no elements, @@ -175,7 +175,7 @@ </func> <func> - <name name="is_key" arity="2"/> + <name name="is_key" arity="2" since=""/> <fsummary>Test if a key is in a dictionary.</fsummary> <desc> <p>Tests if <c><anno>Key</anno></c> is contained in @@ -184,7 +184,7 @@ </func> <func> - <name name="map" arity="2"/> + <name name="map" arity="2" since=""/> <fsummary>Map a function over a dictionary.</fsummary> <desc> <p>Calls <c><anno>Fun</anno></c> on successive keys and values of @@ -193,7 +193,7 @@ </func> <func> - <name name="merge" arity="3"/> + <name name="merge" arity="3" since=""/> <fsummary>Merge two dictionaries.</fsummary> <desc> <p>Merges two dictionaries, <c><anno>Orddict1</anno></c> and @@ -212,7 +212,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="new" arity="0"/> + <name name="new" arity="0" since=""/> <fsummary>Create a dictionary.</fsummary> <desc> <p>Creates a new dictionary.</p> @@ -220,7 +220,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="size" arity="1"/> + <name name="size" arity="1" since=""/> <fsummary>Return the number of elements in an ordered dictionary. </fsummary> <desc> @@ -229,7 +229,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="store" arity="3"/> + <name name="store" arity="3" since=""/> <fsummary>Store a value in a dictionary.</fsummary> <desc> <p>Stores a <c><anno>Key</anno></c>-<c><anno>Value</anno></c> pair in a @@ -240,7 +240,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="to_list" arity="1"/> + <name name="to_list" arity="1" since=""/> <fsummary>Convert a dictionary to a list of pairs.</fsummary> <desc> <p>Converts a dictionary to a list representation.</p> @@ -248,7 +248,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="update" arity="3"/> + <name name="update" arity="3" since=""/> <fsummary>Update a value in a dictionary.</fsummary> <desc> <p>Updates a value in a dictionary by calling <c><anno>Fun</anno></c> @@ -258,7 +258,7 @@ merge(Fun, D1, D2) -> </func> <func> - <name name="update" arity="4"/> + <name name="update" arity="4" since=""/> <fsummary>Update a value in a dictionary.</fsummary> <desc> <p>Updates a value in a dictionary by calling <c><anno>Fun</anno></c> @@ -273,7 +273,7 @@ append(Key, Val, D) -> </func> <func> - <name name="update_counter" arity="3"/> + <name name="update_counter" arity="3" since=""/> <fsummary>Increment a value in a dictionary.</fsummary> <desc> <p>Adds <c><anno>Increment</anno></c> to the value associated with diff --git a/lib/stdlib/doc/src/ordsets.xml b/lib/stdlib/doc/src/ordsets.xml index 11f98c8fb7..fbe334c009 100644 --- a/lib/stdlib/doc/src/ordsets.xml +++ b/lib/stdlib/doc/src/ordsets.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>ordsets.xml</file> </header> - <module>ordsets</module> + <module since="">ordsets</module> <modulesummary>Functions for manipulating sets as ordered lists. </modulesummary> <description> @@ -60,7 +60,7 @@ <funcs> <func> - <name name="add_element" arity="2"/> + <name name="add_element" arity="2" since=""/> <fsummary>Add an element to an <c>Ordset</c>.</fsummary> <desc> <p>Returns a new ordered set formed from <c><anno>Ordset1</anno></c> @@ -69,7 +69,7 @@ </func> <func> - <name name="del_element" arity="2"/> + <name name="del_element" arity="2" since=""/> <fsummary>Remove an element from an <c>Ordset</c>.</fsummary> <desc> <p>Returns <c><anno>Ordset1</anno></c>, but with @@ -78,7 +78,7 @@ </func> <func> - <name name="filter" arity="2"/> + <name name="filter" arity="2" since=""/> <fsummary>Filter set elements.</fsummary> <desc> <p>Filters elements in <c><anno>Ordset1</anno></c> with boolean function @@ -87,7 +87,7 @@ </func> <func> - <name name="fold" arity="3"/> + <name name="fold" arity="3" since=""/> <fsummary>Fold over set elements.</fsummary> <desc> <p>Folds <c><anno>Function</anno></c> over every element in @@ -97,7 +97,7 @@ </func> <func> - <name name="from_list" arity="1"/> + <name name="from_list" arity="1" since=""/> <fsummary>Convert a list into an <c>Ordset</c>.</fsummary> <desc> <p>Returns an ordered set of the elements in <c><anno>List</anno></c>. @@ -106,7 +106,7 @@ </func> <func> - <name name="intersection" arity="1"/> + <name name="intersection" arity="1" since=""/> <fsummary>Return the intersection of a list of <c>Ordsets</c></fsummary> <desc> <p>Returns the intersection of the non-empty list of sets.</p> @@ -114,7 +114,7 @@ </func> <func> - <name name="intersection" arity="2"/> + <name name="intersection" arity="2" since=""/> <fsummary>Return the intersection of two <c>Ordsets</c>.</fsummary> <desc> <p>Returns the intersection of <c><anno>Ordset1</anno></c> and @@ -123,7 +123,7 @@ </func> <func> - <name name="is_disjoint" arity="2"/> + <name name="is_disjoint" arity="2" since=""/> <fsummary>Check whether two <c>Ordsets</c> are disjoint.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Ordset1</anno></c> and @@ -133,7 +133,7 @@ </func> <func> - <name name="is_element" arity="2"/> + <name name="is_element" arity="2" since=""/> <fsummary>Test for membership of an <c>Ordset</c>.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Element</anno></c> is an element of @@ -142,7 +142,7 @@ </func> <func> - <name name="is_empty" arity="1"/> + <name name="is_empty" arity="1" since="OTP 21.0"/> <fsummary>Test for empty set.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Ordset</anno></c> is an empty set, @@ -151,7 +151,7 @@ </func> <func> - <name name="is_set" arity="1"/> + <name name="is_set" arity="1" since=""/> <fsummary>Test for an <c>Ordset</c>.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Ordset</anno></c> is an ordered set @@ -160,7 +160,7 @@ </func> <func> - <name name="is_subset" arity="2"/> + <name name="is_subset" arity="2" since=""/> <fsummary>Test for subset.</fsummary> <desc> <p>Returns <c>true</c> when every element of <c><anno>Ordset1</anno></c> @@ -170,7 +170,7 @@ </func> <func> - <name name="new" arity="0"/> + <name name="new" arity="0" since=""/> <fsummary>Return an empty set.</fsummary> <desc> <p>Returns a new empty ordered set.</p> @@ -178,7 +178,7 @@ </func> <func> - <name name="size" arity="1"/> + <name name="size" arity="1" since=""/> <fsummary>Return the number of elements in a set.</fsummary> <desc> <p>Returns the number of elements in <c><anno>Ordset</anno></c>.</p> @@ -186,7 +186,7 @@ </func> <func> - <name name="subtract" arity="2"/> + <name name="subtract" arity="2" since=""/> <fsummary>Return the difference of two <c>Ordsets</c>.</fsummary> <desc> <p>Returns only the elements of <c><anno>Ordset1</anno></c> that are not @@ -195,7 +195,7 @@ </func> <func> - <name name="to_list" arity="1"/> + <name name="to_list" arity="1" since=""/> <fsummary>Convert an <c>Ordset</c> into a list.</fsummary> <desc> <p>Returns the elements of <c><anno>Ordset</anno></c> as a list.</p> @@ -203,7 +203,7 @@ </func> <func> - <name name="union" arity="1"/> + <name name="union" arity="1" since=""/> <fsummary>Return the union of a list of <c>Ordsets</c>.</fsummary> <desc> <p>Returns the merged (union) set of the list of sets.</p> @@ -211,7 +211,7 @@ </func> <func> - <name name="union" arity="2"/> + <name name="union" arity="2" since=""/> <fsummary>Return the union of two <c>Ordsets</c>.</fsummary> <desc> <p>Returns the merged (union) set of <c><anno>Ordset1</anno></c> and diff --git a/lib/stdlib/doc/src/pool.xml b/lib/stdlib/doc/src/pool.xml index 05d12ade28..675ee08bfb 100644 --- a/lib/stdlib/doc/src/pool.xml +++ b/lib/stdlib/doc/src/pool.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>pool</module> + <module since="">pool</module> <modulesummary>Load distribution facility.</modulesummary> <description> <p>This module can be used to run a set of Erlang nodes as a pool @@ -54,7 +54,7 @@ <funcs> <func> - <name name="attach" arity="1"/> + <name name="attach" arity="1" since=""/> <fsummary>Ensure that a pool master is running.</fsummary> <desc> <p>Ensures that a pool master is running and includes @@ -63,7 +63,7 @@ </func> <func> - <name name="get_node" arity="0"/> + <name name="get_node" arity="0" since=""/> <fsummary>Return the node with the expected lowest future load.</fsummary> <desc> <p>Returns the node with the expected lowest future load.</p> @@ -71,7 +71,7 @@ </func> <func> - <name name="get_nodes" arity="0"/> + <name name="get_nodes" arity="0" since=""/> <fsummary>Return a list of the current member nodes of the pool. </fsummary> <desc> @@ -80,7 +80,7 @@ </func> <func> - <name name="pspawn" arity="3"/> + <name name="pspawn" arity="3" since=""/> <fsummary>Spawn a process on the pool node with expected lowest future load.</fsummary> <desc> @@ -90,7 +90,7 @@ </func> <func> - <name name="pspawn_link" arity="3"/> + <name name="pspawn_link" arity="3" since=""/> <fsummary>Spawn and link to a process on the pool node with expected lowest future load.</fsummary> <desc> @@ -100,8 +100,8 @@ </func> <func> - <name name="start" arity="1"/> - <name name="start" arity="2"/> + <name name="start" arity="1" since=""/> + <name name="start" arity="2" since=""/> <fsummary>>Start a new pool.</fsummary> <desc> <p>Starts a new pool. The file <c>.hosts.erlang</c> is read to @@ -122,7 +122,7 @@ </func> <func> - <name name="stop" arity="0"/> + <name name="stop" arity="0" since=""/> <fsummary>Stop the pool and kill all the slave nodes.</fsummary> <desc> <p>Stops the pool and kills all the slave nodes.</p> diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml index b85fab67d5..aeb9f48735 100644 --- a/lib/stdlib/doc/src/proc_lib.xml +++ b/lib/stdlib/doc/src/proc_lib.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>proc_lib</module> + <module since="">proc_lib</module> <modulesummary>Functions for asynchronous and synchronous start of processes adhering to the OTP design principles.</modulesummary> <description> @@ -102,7 +102,7 @@ <funcs> <func> - <name name="format" arity="1"/> + <name name="format" arity="1" since=""/> <fsummary>Format a crash report.</fsummary> <desc> <p>Equivalent to <seealso marker="#format/2"> @@ -111,7 +111,7 @@ </func> <func> - <name name="format" arity="2"/> + <name name="format" arity="2" since="OTP R16B"/> <fsummary>Format a crash report.</fsummary> <desc> <note> @@ -138,7 +138,7 @@ </func> <func> - <name name="format" arity="3"/> + <name name="format" arity="3" since="OTP 18.1"/> <fsummary>Format a crash report.</fsummary> <desc> <note> @@ -162,7 +162,7 @@ </func> <func> - <name name="hibernate" arity="3"/> + <name name="hibernate" arity="3" since=""/> <fsummary>Hibernate a process until a message is sent to it.</fsummary> <desc> <p>This function does the same as (and does call) the @@ -176,8 +176,8 @@ </func> <func> - <name name="init_ack" arity="1"/> - <name name="init_ack" arity="2"/> + <name name="init_ack" arity="1" since=""/> + <name name="init_ack" arity="2" since=""/> <fsummary>Used by a process when it has started.</fsummary> <desc> <p>This function must be used by a process that has been started by @@ -214,7 +214,7 @@ init(Parent) -> </func> <func> - <name name="initial_call" arity="1"/> + <name name="initial_call" arity="1" since=""/> <fsummary>Extract the initial call of a <c>proc_lib</c>spawned process. </fsummary> <desc> @@ -244,10 +244,10 @@ init(Parent) -> </func> <func> - <name name="spawn" arity="1"/> - <name name="spawn" arity="2"/> - <name name="spawn" arity="3"/> - <name name="spawn" arity="4"/> + <name name="spawn" arity="1" since=""/> + <name name="spawn" arity="2" since=""/> + <name name="spawn" arity="3" since=""/> + <name name="spawn" arity="4" since=""/> <fsummary>Spawn a new process.</fsummary> <type variable="Node"/> <type variable="Fun" name_i="1"/> @@ -262,10 +262,10 @@ init(Parent) -> </func> <func> - <name name="spawn_link" arity="1"/> - <name name="spawn_link" arity="2"/> - <name name="spawn_link" arity="3"/> - <name name="spawn_link" arity="4"/> + <name name="spawn_link" arity="1" since=""/> + <name name="spawn_link" arity="2" since=""/> + <name name="spawn_link" arity="3" since=""/> + <name name="spawn_link" arity="4" since=""/> <fsummary>Spawn and link to a new process.</fsummary> <type variable="Node"/> <type variable="Fun" name_i="1"/> @@ -281,10 +281,10 @@ init(Parent) -> </func> <func> - <name name="spawn_opt" arity="2"/> - <name name="spawn_opt" arity="3"/> - <name name="spawn_opt" arity="4"/> - <name name="spawn_opt" arity="5"/> + <name name="spawn_opt" arity="2" since=""/> + <name name="spawn_opt" arity="3" since=""/> + <name name="spawn_opt" arity="4" since=""/> + <name name="spawn_opt" arity="5" since=""/> <fsummary>Spawn a new process with specified options.</fsummary> <type variable="Node"/> <type variable="Fun" name_i="1"/> @@ -306,12 +306,12 @@ init(Parent) -> </func> <func> - <name name="start" arity="3"/> - <name name="start" arity="4"/> - <name name="start" arity="5"/> - <name name="start_link" arity="3"/> - <name name="start_link" arity="4"/> - <name name="start_link" arity="5"/> + <name name="start" arity="3" since=""/> + <name name="start" arity="4" since=""/> + <name name="start" arity="5" since=""/> + <name name="start_link" arity="3" since=""/> + <name name="start_link" arity="4" since=""/> + <name name="start_link" arity="5" since=""/> <fsummary>Start a new process synchronously.</fsummary> <desc> <p>Starts a new process synchronously. Spawns the process and @@ -341,7 +341,7 @@ init(Parent) -> </func> <func> - <name name="stop" arity="1"/> + <name name="stop" arity="1" since="OTP 18.0"/> <fsummary>Terminate a process synchronously.</fsummary> <type variable="Process"/> <desc> @@ -351,7 +351,7 @@ init(Parent) -> </func> <func> - <name name="stop" arity="3"/> + <name name="stop" arity="3" since="OTP 18.0"/> <fsummary>Terminate a process synchronously.</fsummary> <type variable="Process"/> <type variable="Reason"/> @@ -375,7 +375,7 @@ init(Parent) -> </func> <func> - <name name="translate_initial_call" arity="1"/> + <name name="translate_initial_call" arity="1" since=""/> <fsummary>Extract and translate the initial call of a <c>proc_lib</c>spawned process.</fsummary> <desc> diff --git a/lib/stdlib/doc/src/proplists.xml b/lib/stdlib/doc/src/proplists.xml index f9a54bf804..4465103469 100644 --- a/lib/stdlib/doc/src/proplists.xml +++ b/lib/stdlib/doc/src/proplists.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>proplists.xml</file> </header> - <module>proplists</module> + <module since="">proplists</module> <modulesummary>Support functions for property lists.</modulesummary> <description> <p>Property lists are ordinary lists containing entries in the form @@ -57,11 +57,16 @@ <datatype> <name name="property"/> </datatype> + + <datatype> + <name name="proplist"/> + </datatype> + </datatypes> <funcs> <func> - <name name="append_values" arity="2"/> + <name name="append_values" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Similar to @@ -79,7 +84,7 @@ append_values(a, [{a, [1,2]}, {b, 0}, {a, 3}, {c, -1}, {a, [4]}])</code> </func> <func> - <name name="compact" arity="1"/> + <name name="compact" arity="1" since=""/> <fsummary></fsummary> <desc> <p>Minimizes the representation of all entries in the list. This is @@ -91,7 +96,7 @@ append_values(a, [{a, [1,2]}, {b, 0}, {a, 3}, {c, -1}, {a, [4]}])</code> </func> <func> - <name name="delete" arity="2"/> + <name name="delete" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Deletes all entries associated with <c><anno>Key</anno></c> from @@ -100,7 +105,7 @@ append_values(a, [{a, [1,2]}, {b, 0}, {a, 3}, {c, -1}, {a, [4]}])</code> </func> <func> - <name name="expand" arity="2"/> + <name name="expand" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Expands particular properties to corresponding sets of @@ -133,7 +138,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="get_all_values" arity="2"/> + <name name="get_all_values" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Similar to @@ -145,7 +150,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="get_bool" arity="2"/> + <name name="get_bool" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Returns the value of a boolean key/value option. If @@ -159,7 +164,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="get_keys" arity="1"/> + <name name="get_keys" arity="1" since=""/> <fsummary></fsummary> <desc> <p>Returns an unordered list of the keys used in @@ -168,7 +173,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="get_value" arity="2"/> + <name name="get_value" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Equivalent to @@ -177,7 +182,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="get_value" arity="3"/> + <name name="get_value" arity="3" since=""/> <fsummary></fsummary> <desc> <p>Returns the value of a simple key/value property in @@ -194,7 +199,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="is_defined" arity="2"/> + <name name="is_defined" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Returns <c>true</c> if <c><anno>List</anno></c> contains at least @@ -204,7 +209,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="lookup" arity="2"/> + <name name="lookup" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Returns the first entry associated with <c><anno>Key</anno></c> in @@ -219,7 +224,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="lookup_all" arity="2"/> + <name name="lookup_all" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Returns the list of all entries associated with @@ -231,7 +236,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="normalize" arity="2"/> + <name name="normalize" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Passes <c><anno>ListIn</anno></c> through a sequence of @@ -263,7 +268,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="property" arity="1"/> + <name name="property" arity="1" since=""/> <fsummary></fsummary> <desc> <p>Creates a normal form (minimal) representation of a property. If @@ -276,7 +281,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="property" arity="2"/> + <name name="property" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Creates a normal form (minimal) representation of a simple key/value @@ -289,7 +294,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code> </func> <func> - <name name="split" arity="2"/> + <name name="split" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Partitions <c><anno>List</anno></c> into a list of sublists and a @@ -310,7 +315,7 @@ split([{c, 2}, {e, 1}, a, {c, 3, 4}, d, {b, 5}, b], [a, b, c])</code> </func> <func> - <name name="substitute_aliases" arity="2"/> + <name name="substitute_aliases" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Substitutes keys of properties. For each entry in @@ -332,7 +337,7 @@ split([{c, 2}, {e, 1}, a, {c, 3, 4}, d, {b, 5}, b], [a, b, c])</code> </func> <func> - <name name="substitute_negations" arity="2"/> + <name name="substitute_negations" arity="2" since=""/> <fsummary></fsummary> <desc> <p>Substitutes keys of boolean-valued properties and @@ -360,7 +365,7 @@ split([{c, 2}, {e, 1}, a, {c, 3, 4}, d, {b, 5}, b], [a, b, c])</code> </func> <func> - <name name="unfold" arity="1"/> + <name name="unfold" arity="1" since=""/> <fsummary></fsummary> <desc> <p>Unfolds all occurrences of atoms in <c><anno>ListIn</anno></c> to diff --git a/lib/stdlib/doc/src/qlc.xml b/lib/stdlib/doc/src/qlc.xml index fe14a6334c..fe60c2e9bb 100644 --- a/lib/stdlib/doc/src/qlc.xml +++ b/lib/stdlib/doc/src/qlc.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>qlc.xml</file> </header> - <module>qlc</module> + <module since="">qlc</module> <modulesummary>Query interface to Mnesia, ETS, Dets, and so on. </modulesummary> <description> @@ -720,7 +720,7 @@ ets:match_spec_run(ets:lookup(86033, {2,2}), <funcs> <func> - <name name="append" arity="1"/> + <name name="append" arity="1" since=""/> <fsummary>Return a query handle.</fsummary> <desc> <p>Returns a query handle. When evaluating query handle @@ -731,7 +731,7 @@ ets:match_spec_run(ets:lookup(86033, {2,2}), </func> <func> - <name name="append" arity="2"/> + <name name="append" arity="2" since=""/> <fsummary>Return a query handle.</fsummary> <desc> <p>Returns a query handle. When evaluating query handle @@ -744,8 +744,8 @@ ets:match_spec_run(ets:lookup(86033, {2,2}), </func> <func> - <name name="cursor" arity="1"/> - <name name="cursor" arity="2"/> + <name name="cursor" arity="1" since=""/> + <name name="cursor" arity="2" since=""/> <fsummary>Create a query cursor.</fsummary> <desc> <p>Creates a query cursor and @@ -777,7 +777,7 @@ ok</pre> </func> <func> - <name name="delete_cursor" arity="1"/> + <name name="delete_cursor" arity="1" since=""/> <fsummary>Delete a query cursor.</fsummary> <desc> <p>Deletes a query cursor. Only the owner of the cursor can @@ -786,10 +786,10 @@ ok</pre> </func> <func> - <name name="e" arity="1"/> - <name name="e" arity="2"/> - <name name="eval" arity="1"/> - <name name="eval" arity="2"/> + <name name="e" arity="1" since=""/> + <name name="e" arity="2" since=""/> + <name name="eval" arity="1" since=""/> + <name name="eval" arity="2" since=""/> <fsummary>Return all answers to a query.</fsummary> <desc> <p>Evaluates a query handle in the @@ -805,8 +805,8 @@ ok</pre> </func> <func> - <name name="fold" arity="3"/> - <name name="fold" arity="4"/> + <name name="fold" arity="3" since=""/> + <name name="fold" arity="4" since=""/> <fsummary>Fold a function over the answers to a query.</fsummary> <desc> <p>Calls <c><anno>Function</anno></c> on successive answers to @@ -830,7 +830,7 @@ ok</pre> </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Return an English description of a an error tuple.</fsummary> <desc> <p>Returns a descriptive string in English of an error tuple @@ -841,8 +841,8 @@ ok</pre> </func> <func> - <name name="info" arity="1"/> - <name name="info" arity="2"/> + <name name="info" arity="1" since=""/> + <name name="info" arity="2" since=""/> <fsummary>Return code describing a query handle.</fsummary> <desc> <p>Returns information about a @@ -946,8 +946,8 @@ end</pre> </func> <func> - <name name="keysort" arity="2"/> - <name name="keysort" arity="3"/> + <name name="keysort" arity="2" since=""/> + <name name="keysort" arity="3" since=""/> <fsummary>Return a query handle.</fsummary> <desc> <p>Returns a query handle. When evaluating query handle @@ -967,8 +967,8 @@ end</pre> </func> <func> - <name name="next_answers" arity="1"/> - <name name="next_answers" arity="2"/> + <name name="next_answers" arity="1" since=""/> + <name name="next_answers" arity="2" since=""/> <fsummary>Return some or all answers to a query.</fsummary> <desc> <p>Returns some or all of the remaining answers to a query @@ -983,8 +983,8 @@ end</pre> </func> <func> - <name name="q" arity="1"/> - <name name="q" arity="2"/> + <name name="q" arity="1" since=""/> + <name name="q" arity="2" since=""/> <fsummary>Return a handle for a query list comprehension.</fsummary> <desc> <p>Returns a query handle for a QLC. @@ -1188,8 +1188,8 @@ ets:match_spec_run( </func> <func> - <name name="sort" arity="1"/> - <name name="sort" arity="2"/> + <name name="sort" arity="1" since=""/> + <name name="sort" arity="2" since=""/> <fsummary>Return a query handle.</fsummary> <desc> <p>Returns a query handle. When evaluating query handle @@ -1208,9 +1208,9 @@ ets:match_spec_run( </func> <func> - <name name="string_to_handle" arity="1"/> - <name name="string_to_handle" arity="2"/> - <name name="string_to_handle" arity="3"/> + <name name="string_to_handle" arity="1" since=""/> + <name name="string_to_handle" arity="2" since=""/> + <name name="string_to_handle" arity="3" since=""/> <fsummary>Return a handle for a query list comprehension.</fsummary> <desc> <p>A string version of <seealso marker="#q/1"><c>q/1,2</c></seealso>. @@ -1238,7 +1238,7 @@ ets:match_spec_run( </func> <func> - <name name="table" arity="2"/> + <name name="table" arity="2" since=""/> <fsummary>Return a query handle for a table.</fsummary> <desc> <p>Returns a query handle for a QLC table. diff --git a/lib/stdlib/doc/src/queue.xml b/lib/stdlib/doc/src/queue.xml index 9f3aff03a3..83a8afea81 100644 --- a/lib/stdlib/doc/src/queue.xml +++ b/lib/stdlib/doc/src/queue.xml @@ -32,7 +32,7 @@ <rev>B</rev> <file>queue.xml</file> </header> - <module>queue</module> + <module since="">queue</module> <modulesummary>Abstract data type for FIFO queues.</modulesummary> <description> <p>This module provides (double-ended) FIFO queues @@ -113,7 +113,7 @@ <funcs> <func> - <name name="filter" arity="2"/> + <name name="filter" arity="2" since=""/> <fsummary>Filter a queue.</fsummary> <desc> <p>Returns a queue <c><anno>Q2</anno></c> that is the result of calling @@ -134,7 +134,7 @@ </func> <func> - <name name="from_list" arity="1"/> + <name name="from_list" arity="1" since=""/> <fsummary>Convert a list to a queue.</fsummary> <desc> <p>Returns a queue containing the items in <c><anno>L</anno></c> in the @@ -144,7 +144,7 @@ </func> <func> - <name name="in" arity="2"/> + <name name="in" arity="2" since=""/> <fsummary>Insert an item at the rear of a queue.</fsummary> <desc> <p>Inserts <c><anno>Item</anno></c> at the rear of queue @@ -154,7 +154,7 @@ </func> <func> - <name name="in_r" arity="2"/> + <name name="in_r" arity="2" since=""/> <fsummary>Insert an item at the front of a queue.</fsummary> <desc> <p>Inserts <c><anno>Item</anno></c> at the front of queue @@ -164,7 +164,7 @@ </func> <func> - <name name="is_empty" arity="1"/> + <name name="is_empty" arity="1" since=""/> <fsummary>Test if a queue is empty.</fsummary> <desc> <p>Tests if <c><anno>Q</anno></c> is empty and returns <c>true</c> if @@ -173,7 +173,7 @@ </func> <func> - <name name="is_queue" arity="1"/> + <name name="is_queue" arity="1" since=""/> <fsummary>Test if a term is a queue.</fsummary> <desc> <p>Tests if <c><anno>Term</anno></c> is a queue and returns <c>true</c> @@ -182,7 +182,7 @@ </func> <func> - <name name="join" arity="2"/> + <name name="join" arity="2" since=""/> <fsummary>Join two queues.</fsummary> <desc> <p>Returns a queue <c><anno>Q3</anno></c> that is the result of joining @@ -192,7 +192,7 @@ </func> <func> - <name name="len" arity="1"/> + <name name="len" arity="1" since=""/> <fsummary>Get the length of a queue.</fsummary> <desc> <p>Calculates and returns the length of queue <c><anno>Q</anno></c>.</p> @@ -200,7 +200,7 @@ </func> <func> - <name name="member" arity="2"/> + <name name="member" arity="2" since=""/> <fsummary>Test if an item is in a queue.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Item</anno></c> matches some element @@ -209,7 +209,7 @@ </func> <func> - <name name="new" arity="0"/> + <name name="new" arity="0" since=""/> <fsummary>Create an empty queue.</fsummary> <desc> <p>Returns an empty queue.</p> @@ -217,7 +217,7 @@ </func> <func> - <name name="out" arity="1"/> + <name name="out" arity="1" since=""/> <fsummary>Remove the front item from a queue.</fsummary> <desc> <p>Removes the item at the front of queue <c><anno>Q1</anno></c>. @@ -230,7 +230,7 @@ </func> <func> - <name name="out_r" arity="1"/> + <name name="out_r" arity="1" since=""/> <fsummary>Remove the rear item from a queue.</fsummary> <desc> <p>Removes the item at the rear of queue <c><anno>Q1</anno></c>. @@ -242,7 +242,7 @@ </func> <func> - <name name="reverse" arity="1"/> + <name name="reverse" arity="1" since=""/> <fsummary>Reverse a queue.</fsummary> <desc> <p>Returns a queue <c><anno>Q2</anno></c> containing the items of @@ -251,7 +251,7 @@ </func> <func> - <name name="split" arity="2"/> + <name name="split" arity="2" since=""/> <fsummary>Split a queue in two.</fsummary> <desc> <p>Splits <c><anno>Q1</anno></c> in two. The <c><anno>N</anno></c> @@ -261,7 +261,7 @@ </func> <func> - <name name="to_list" arity="1"/> + <name name="to_list" arity="1" since=""/> <fsummary>Convert a queue to a list.</fsummary> <desc> <p>Returns a list of the items in the queue in the same order; @@ -276,7 +276,7 @@ <funcs> <func> - <name name="drop" arity="1"/> + <name name="drop" arity="1" since=""/> <fsummary>Remove the front item from a queue.</fsummary> <desc> <p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing @@ -286,7 +286,7 @@ </func> <func> - <name name="drop_r" arity="1"/> + <name name="drop_r" arity="1" since=""/> <fsummary>Remove the rear item from a queue.</fsummary> <desc> <p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing @@ -296,7 +296,7 @@ </func> <func> - <name name="get" arity="1"/> + <name name="get" arity="1" since=""/> <fsummary>Return the front item of a queue.</fsummary> <desc> <p>Returns <c><anno>Item</anno></c> at the front of queue @@ -306,7 +306,7 @@ </func> <func> - <name name="get_r" arity="1"/> + <name name="get_r" arity="1" since=""/> <fsummary>Return the rear item of a queue.</fsummary> <desc> <p>Returns <c><anno>Item</anno></c> at the rear of queue @@ -316,7 +316,7 @@ </func> <func> - <name name="peek" arity="1"/> + <name name="peek" arity="1" since=""/> <fsummary>Return the front item of a queue.</fsummary> <desc> <p>Returns tuple <c>{value, <anno>Item</anno>}</c>, where @@ -326,7 +326,7 @@ </func> <func> - <name name="peek_r" arity="1"/> + <name name="peek_r" arity="1" since=""/> <fsummary>Return the rear item of a queue.</fsummary> <desc> <p>Returns tuple <c>{value, <anno>Item</anno>}</c>, where @@ -342,7 +342,7 @@ <funcs> <func> - <name name="cons" arity="2"/> + <name name="cons" arity="2" since=""/> <fsummary>Insert an item at the head of a queue.</fsummary> <desc> <p>Inserts <c><anno>Item</anno></c> at the head of queue @@ -352,7 +352,7 @@ </func> <func> - <name name="daeh" arity="1"/> + <name name="daeh" arity="1" since=""/> <fsummary>Return the tail item of a queue.</fsummary> <desc> <p>Returns the tail item of queue <c><anno>Q</anno></c>.</p> @@ -361,7 +361,7 @@ </func> <func> - <name name="head" arity="1"/> + <name name="head" arity="1" since=""/> <fsummary>Return the item at the head of a queue.</fsummary> <desc> <p>Returns <c><anno>Item</anno></c> from the head of queue @@ -371,7 +371,7 @@ </func> <func> - <name name="init" arity="1"/> + <name name="init" arity="1" since=""/> <fsummary>Remove the tail item from a queue.</fsummary> <desc> <p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing @@ -381,7 +381,7 @@ </func> <func> - <name name="lait" arity="1"/> + <name name="lait" arity="1" since=""/> <fsummary>Remove the tail item from a queue.</fsummary> <desc> <p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing @@ -392,7 +392,7 @@ </func> <func> - <name name="last" arity="1"/> + <name name="last" arity="1" since=""/> <fsummary>Return the tail item of a queue.</fsummary> <desc> <p>Returns the tail item of queue <c><anno>Q</anno></c>.</p> @@ -401,7 +401,7 @@ </func> <func> - <name name="liat" arity="1"/> + <name name="liat" arity="1" since=""/> <fsummary>Remove the tail item from a queue.</fsummary> <desc> <p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing @@ -411,7 +411,7 @@ </func> <func> - <name name="snoc" arity="2"/> + <name name="snoc" arity="2" since=""/> <fsummary>Insert an item at the tail of a queue.</fsummary> <desc> <p>Inserts <c><anno>Item</anno></c> as the tail item of queue @@ -421,7 +421,7 @@ </func> <func> - <name name="tail" arity="1"/> + <name name="tail" arity="1" since=""/> <fsummary>Remove the head item from a queue.</fsummary> <desc> <p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml index 21f680a0ee..27d2d99f3c 100644 --- a/lib/stdlib/doc/src/rand.xml +++ b/lib/stdlib/doc/src/rand.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>rand.xml</file> </header> - <module>rand</module> + <module since="OTP 18.0">rand</module> <modulesummary>Pseudo random number generation.</modulesummary> <description> <p> @@ -273,7 +273,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> <funcs> <func> - <name name="export_seed" arity="0"/> + <name name="export_seed" arity="0" since="OTP 18.0"/> <fsummary>Export the random number generation state.</fsummary> <desc><marker id="export_seed-0"/> <p>Returns the random number state in an external format. @@ -282,7 +282,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="export_seed_s" arity="1"/> + <name name="export_seed_s" arity="1" since="OTP 18.0"/> <fsummary>Export the random number generation state.</fsummary> <desc><marker id="export_seed_s-1"/> <p>Returns the random number generator state in an external format. @@ -291,7 +291,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="jump" arity="0"/> + <name name="jump" arity="0" since="OTP 20.0"/> <fsummary>Return the seed after performing jump calculation to the state in the process dictionary.</fsummary> <desc><marker id="jump-0" /> @@ -306,7 +306,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="jump" arity="1"/> + <name name="jump" arity="1" since="OTP 20.0"/> <fsummary>Return the seed after performing jump calculation.</fsummary> <desc><marker id="jump-1" /> <p>Returns the state after performing jump calculation @@ -318,7 +318,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="normal" arity="0"/> + <name name="normal" arity="0" since="OTP 18.0"/> <fsummary>Return a standard normal distributed random float.</fsummary> <desc> <p>Returns a standard normal deviate float (that is, the mean @@ -328,7 +328,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="normal" arity="2"/> + <name name="normal" arity="2" since="OTP 20.0"/> <fsummary>Return a normal distributed random float.</fsummary> <desc> <p>Returns a normal N(Mean, Variance) deviate float @@ -337,7 +337,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="normal_s" arity="1"/> + <name name="normal_s" arity="1" since="OTP 18.0"/> <fsummary>Return a standard normal distributed random float.</fsummary> <desc> <p>Returns, for a specified state, a standard normal @@ -347,7 +347,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="normal_s" arity="3"/> + <name name="normal_s" arity="3" since="OTP 20.0"/> <fsummary>Return a normal distributed random float.</fsummary> <desc> <p>Returns, for a specified state, a normal N(Mean, Variance) @@ -356,7 +356,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="seed" arity="1"/> + <name name="seed" arity="1" since="OTP 18.0"/> <fsummary>Seed random number generator.</fsummary> <desc> <marker id="seed-1"/> @@ -372,7 +372,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="seed" arity="2"/> + <name name="seed" arity="2" since="OTP 18.0"/> <fsummary>Seed the random number generation.</fsummary> <desc> <p>Seeds random number generation with the specified algorithm and @@ -381,7 +381,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="seed_s" arity="1"/> + <name name="seed_s" arity="1" since="OTP 18.0"/> <fsummary>Seed random number generator.</fsummary> <desc> <p> @@ -396,7 +396,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="seed_s" arity="2"/> + <name name="seed_s" arity="2" since="OTP 18.0"/> <fsummary>Seed the random number generation.</fsummary> <desc> <p>Seeds random number generation with the specified algorithm and @@ -405,7 +405,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre> </func> <func> - <name name="uniform" arity="0"/> + <name name="uniform" arity="0" since="OTP 18.0"/> <fsummary>Return a random float.</fsummary> <desc><marker id="uniform-0"/> <p> @@ -441,7 +441,7 @@ end.</pre> </func> <func> - <name name="uniform_real" arity="0"/> + <name name="uniform_real" arity="0" since="OTP 21.0"/> <fsummary>Return a random float.</fsummary> <desc><marker id="uniform_real-0"/> <p> @@ -477,7 +477,7 @@ end.</pre> </func> <func> - <name name="uniform" arity="1"/> + <name name="uniform" arity="1" since="OTP 18.0"/> <fsummary>Return a random integer.</fsummary> <desc><marker id="uniform-1"/> <p>Returns, for a specified integer <c><anno>N</anno> >= 1</c>, @@ -488,7 +488,7 @@ end.</pre> </func> <func> - <name name="uniform_s" arity="1"/> + <name name="uniform_s" arity="1" since="OTP 18.0"/> <fsummary>Return a random float.</fsummary> <desc> <p> @@ -524,7 +524,7 @@ end.</pre> </func> <func> - <name name="uniform_real_s" arity="1"/> + <name name="uniform_real_s" arity="1" since="OTP 21.0"/> <fsummary>Return a random float.</fsummary> <desc> <p> @@ -586,7 +586,7 @@ end.</pre> </func> <func> - <name name="uniform_s" arity="2"/> + <name name="uniform_s" arity="2" since="OTP 18.0"/> <fsummary>Return a random integer.</fsummary> <desc> <p>Returns, for a specified integer <c><anno>N</anno> >= 1</c> diff --git a/lib/stdlib/doc/src/random.xml b/lib/stdlib/doc/src/random.xml index 8d090d20b3..f0261ed009 100644 --- a/lib/stdlib/doc/src/random.xml +++ b/lib/stdlib/doc/src/random.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>random.xml</file> </header> - <module>random</module> + <module since="">random</module> <modulesummary>Pseudo-random number generation.</modulesummary> <description> <p>This module provides a random number generator. The method is attributed @@ -73,7 +73,7 @@ <funcs> <func> - <name name="seed" arity="0"/> + <name name="seed" arity="0" since=""/> <fsummary>Seed random number generation with default values.</fsummary> <desc> <p>Seeds random number generation with default (fixed) values @@ -82,7 +82,7 @@ </func> <func> - <name name="seed" arity="1"/> + <name name="seed" arity="1" since=""/> <fsummary>Seed random number generator.</fsummary> <desc> <p><c>seed({<anno>A1</anno>, <anno>A2</anno>, <anno>A3</anno>})</c> @@ -92,7 +92,7 @@ </func> <func> - <name name="seed" arity="3"/> + <name name="seed" arity="3" since=""/> <fsummary>Seed random number generator.</fsummary> <desc> <p>Seeds random number generation with integer values in the process @@ -116,7 +116,7 @@ random:seed(erlang:phash2([node()]), </func> <func> - <name name="seed0" arity="0"/> + <name name="seed0" arity="0" since=""/> <fsummary>Return default state for random number generation.</fsummary> <desc> <p>Returns the default state.</p> @@ -124,7 +124,7 @@ random:seed(erlang:phash2([node()]), </func> <func> - <name name="uniform" arity="0"/> + <name name="uniform" arity="0" since=""/> <fsummary>Return a random float.</fsummary> <desc> <p>Returns a random float uniformly distributed between <c>0.0</c> @@ -133,7 +133,7 @@ random:seed(erlang:phash2([node()]), </func> <func> - <name name="uniform" arity="1"/> + <name name="uniform" arity="1" since=""/> <fsummary>Return a random integer.</fsummary> <desc> <p>Returns, for a specified integer <c><anno>N</anno> >= 1</c>, @@ -144,7 +144,7 @@ random:seed(erlang:phash2([node()]), </func> <func> - <name name="uniform_s" arity="1"/> + <name name="uniform_s" arity="1" since=""/> <fsummary>Return a random float.</fsummary> <desc> <p>Returns, for a specified state, a random float uniformly @@ -153,7 +153,7 @@ random:seed(erlang:phash2([node()]), </func> <func> - <name name="uniform_s" arity="2"/> + <name name="uniform_s" arity="2" since=""/> <fsummary>Return a random integer.</fsummary> <desc> <p>Returns, for a specified integer <c><anno>N</anno> >= 1</c> and a diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml index 078ca0e38c..b04434492d 100644 --- a/lib/stdlib/doc/src/re.xml +++ b/lib/stdlib/doc/src/re.xml @@ -34,7 +34,7 @@ <rev>A</rev> <file>re.xml</file> </header> - <module>re</module> + <module since="">re</module> <modulesummary>Perl-like regular expressions for Erlang.</modulesummary> <description> <p>This module contains regular expression matching functions for @@ -79,7 +79,7 @@ <funcs> <func> - <name name="version" arity="0"/> + <name name="version" arity="0" since="OTP 20.0"/> <fsummary>Gives the PCRE version of the system in a string format</fsummary> <desc> <p>The return of this function is a string with the PCRE version of the system that was used in the Erlang/OTP compilation.</p> @@ -87,7 +87,7 @@ </func> <func> - <name name="compile" arity="1"/> + <name name="compile" arity="1" since=""/> <fsummary>Compile a regular expression into a match program</fsummary> <desc> <p>The same as <c>compile(<anno>Regexp</anno>,[])</c></p> @@ -95,7 +95,7 @@ </func> <func> - <name name="compile" arity="2"/> + <name name="compile" arity="2" since=""/> <fsummary>Compile a regular expression into a match program.</fsummary> <desc> <p>Compiles a regular expression, with the syntax @@ -304,7 +304,7 @@ </func> <func> - <name name="inspect" arity="2"/> + <name name="inspect" arity="2" since="OTP 17.0"/> <fsummary>Inspects a compiled regular expression.</fsummary> <desc> <p>Takes a compiled regular expression and an item, and returns the @@ -348,7 +348,7 @@ </func> <func> - <name name="replace" arity="3"/> + <name name="replace" arity="3" since=""/> <fsummary>Match a subject against regular expression and replace matching elements with Replacement.</fsummary> <desc> @@ -358,7 +358,7 @@ </func> <func> - <name name="replace" arity="4"/> + <name name="replace" arity="4" since=""/> <fsummary>Match a subject against regular expression and replace matching elements with Replacement.</fsummary> <desc> @@ -408,7 +408,7 @@ re:replace("abcd","c","[\\&]",[{return,list}]).</code> </func> <func> - <name name="run" arity="2"/> + <name name="run" arity="2" since=""/> <fsummary>Match a subject against regular expression and capture subpatterns.</fsummary> <desc> @@ -417,7 +417,7 @@ re:replace("abcd","c","[\\&]",[{return,list}]).</code> </func> <func> - <name name="run" arity="3"/> + <name name="run" arity="3" since=""/> <fsummary>Match a subject against regular expression and capture subpatterns.</fsummary> <type_desc variable="CompileOpt">See <seealso marker="#compile_options"> @@ -992,7 +992,7 @@ re:run("cacb","c(a|b)",[global,{capture,[1],list}]).</code> </func> <func> - <name name="split" arity="2"/> + <name name="split" arity="2" since=""/> <fsummary>Split a string by tokens specified as a regular expression. </fsummary> <desc> @@ -1001,7 +1001,7 @@ re:run("cacb","c(a|b)",[global,{capture,[1],list}]).</code> </func> <func> - <name name="split" arity="3"/> + <name name="split" arity="3" since=""/> <fsummary>Split a string by tokens specified as a regular expression</fsummary> <type_desc variable="CompileOpt">See <seealso marker="#compile_options"> <c>compile/2</c></seealso>.</type_desc> diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml index 8db3e1e623..07ce41b7a7 100644 --- a/lib/stdlib/doc/src/sets.xml +++ b/lib/stdlib/doc/src/sets.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>sets.xml</file> </header> - <module>sets</module> + <module since="">sets</module> <modulesummary>Functions for set manipulation.</modulesummary> <description> <p>Sets are collections of elements with no duplicate elements. @@ -59,7 +59,7 @@ <funcs> <func> - <name name="add_element" arity="2"/> + <name name="add_element" arity="2" since=""/> <fsummary>Add an element to a <c>Set</c>.</fsummary> <desc> <p>Returns a new set formed from <c><anno>Set1</anno></c> with @@ -68,7 +68,7 @@ </func> <func> - <name name="del_element" arity="2"/> + <name name="del_element" arity="2" since=""/> <fsummary>Remove an element from a <c>Set</c>.</fsummary> <desc> <p>Returns <c><anno>Set1</anno></c>, but with @@ -77,7 +77,7 @@ </func> <func> - <name name="filter" arity="2"/> + <name name="filter" arity="2" since=""/> <fsummary>Filter set elements.</fsummary> <desc> <p>Filters elements in <c><anno>Set1</anno></c> with boolean function @@ -86,7 +86,7 @@ </func> <func> - <name name="fold" arity="3"/> + <name name="fold" arity="3" since=""/> <fsummary>Fold over set elements.</fsummary> <desc> <p>Folds <c><anno>Function</anno></c> over every element in @@ -96,7 +96,7 @@ </func> <func> - <name name="from_list" arity="1"/> + <name name="from_list" arity="1" since=""/> <fsummary>Convert a list into a <c>Set</c>.</fsummary> <desc> <p>Returns a set of the elements in <c><anno>List</anno></c>.</p> @@ -104,7 +104,7 @@ </func> <func> - <name name="intersection" arity="1"/> + <name name="intersection" arity="1" since=""/> <fsummary>Return the intersection of a list of <c>Sets</c>.</fsummary> <desc> <p>Returns the intersection of the non-empty list of sets.</p> @@ -112,7 +112,7 @@ </func> <func> - <name name="intersection" arity="2"/> + <name name="intersection" arity="2" since=""/> <fsummary>Return the intersection of two <c>Sets</c>.</fsummary> <desc> <p>Returns the intersection of <c><anno>Set1</anno></c> and @@ -121,7 +121,7 @@ </func> <func> - <name name="is_disjoint" arity="2"/> + <name name="is_disjoint" arity="2" since=""/> <fsummary>Check whether two <c>Sets</c> are disjoint.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Set1</anno></c> and @@ -131,7 +131,7 @@ </func> <func> - <name name="is_element" arity="2"/> + <name name="is_element" arity="2" since=""/> <fsummary>Test for membership of a <c>Set</c>.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Element</anno></c> is an element of @@ -140,7 +140,7 @@ </func> <func> - <name name="is_empty" arity="1"/> + <name name="is_empty" arity="1" since="OTP 21.0"/> <fsummary>Test for empty set.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Set</anno></c> is an empty set, @@ -149,7 +149,7 @@ </func> <func> - <name name="is_set" arity="1"/> + <name name="is_set" arity="1" since=""/> <fsummary>Test for a <c>Set</c>.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Set</anno></c> is a set of @@ -158,7 +158,7 @@ </func> <func> - <name name="is_subset" arity="2"/> + <name name="is_subset" arity="2" since=""/> <fsummary>Test for subset.</fsummary> <desc> <p>Returns <c>true</c> when every element of <c><anno>Set1</anno></c> is @@ -167,7 +167,7 @@ </func> <func> - <name name="new" arity="0"/> + <name name="new" arity="0" since=""/> <fsummary>Return an empty set.</fsummary> <desc> <p>Returns a new empty set.</p> @@ -175,7 +175,7 @@ </func> <func> - <name name="size" arity="1"/> + <name name="size" arity="1" since=""/> <fsummary>Return the number of elements in a set.</fsummary> <desc> <p>Returns the number of elements in <c><anno>Set</anno></c>.</p> @@ -183,7 +183,7 @@ </func> <func> - <name name="subtract" arity="2"/> + <name name="subtract" arity="2" since=""/> <fsummary>Return the difference of two <c>Sets</c>.</fsummary> <desc> <p>Returns only the elements of <c><anno>Set1</anno></c> that are not @@ -192,7 +192,7 @@ </func> <func> - <name name="to_list" arity="1"/> + <name name="to_list" arity="1" since=""/> <fsummary>Convert a <c>Set</c>into a list.</fsummary> <desc> <p>Returns the elements of <c><anno>Set</anno></c> as a list. @@ -201,7 +201,7 @@ </func> <func> - <name name="union" arity="1"/> + <name name="union" arity="1" since=""/> <fsummary>Return the union of a list of <c>Sets</c>.</fsummary> <desc> <p>Returns the merged (union) set of the list of sets.</p> @@ -209,7 +209,7 @@ </func> <func> - <name name="union" arity="2"/> + <name name="union" arity="2" since=""/> <fsummary>Return the union of two <c>Sets</c>.</fsummary> <desc> <p>Returns the merged (union) set of <c><anno>Set1</anno></c> and diff --git a/lib/stdlib/doc/src/shell.xml b/lib/stdlib/doc/src/shell.xml index 2593d3690b..50a0968531 100644 --- a/lib/stdlib/doc/src/shell.xml +++ b/lib/stdlib/doc/src/shell.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>shell.xml</file> </header> - <module>shell</module> + <module since="">shell</module> <modulesummary>The Erlang shell.</modulesummary> <description> <p>This module provides an Erlang shell.</p> @@ -874,7 +874,7 @@ q - quit erlang <funcs> <func> - <name>catch_exception(Bool) -> boolean()</name> + <name since="">catch_exception(Bool) -> boolean()</name> <fsummary>Set the exception handling of the shell.</fsummary> <type> <v>Bool = boolean()</v> @@ -892,7 +892,7 @@ q - quit erlang </func> <func> - <name name="history" arity="1"/> + <name name="history" arity="1" since=""/> <fsummary>Set the number of previous commands to keep.</fsummary> <desc> <p>Sets the number of previous commands to keep in the @@ -902,7 +902,7 @@ q - quit erlang </func> <func> - <name name="prompt_func" arity="1"/> + <name name="prompt_func" arity="1" since="OTP R13B04"/> <fsummary>Set the shell prompt.</fsummary> <desc> <p>Sets the shell prompt function to <c><anno>PromptFunc</anno></c>. @@ -911,7 +911,7 @@ q - quit erlang </func> <func> - <name name="results" arity="1"/> + <name name="results" arity="1" since=""/> <fsummary>Set the number of previous results to keep.</fsummary> <desc> <p>Sets the number of results from previous commands to keep in @@ -921,7 +921,7 @@ q - quit erlang </func> <func> - <name name="start_restricted" arity="1"/> + <name name="start_restricted" arity="1" since=""/> <fsummary>Exit a normal shell and starts a restricted shell.</fsummary> <desc> <p>Exits a normal shell and starts a restricted shell. @@ -936,7 +936,7 @@ q - quit erlang </func> <func> - <name name="stop_restricted" arity="0"/> + <name name="stop_restricted" arity="0" since=""/> <fsummary>Exit a restricted shell and starts a normal shell.</fsummary> <desc> <p>Exits a restricted shell and starts a normal shell. The function @@ -945,7 +945,7 @@ q - quit erlang </func> <func> - <name name="strings" arity="1"/> + <name name="strings" arity="1" since="OTP R16B"/> <fsummary>Set the shell's string recognition flag.</fsummary> <desc> <p>Sets pretty printing of lists to <c><anno>Strings</anno></c>. diff --git a/lib/stdlib/doc/src/slave.xml b/lib/stdlib/doc/src/slave.xml index e53ec8231b..80fb28b548 100644 --- a/lib/stdlib/doc/src/slave.xml +++ b/lib/stdlib/doc/src/slave.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>slave</module> + <module since="">slave</module> <modulesummary>Functions for starting and controlling slave nodes. </modulesummary> <description> @@ -68,7 +68,7 @@ <funcs> <func> - <name>pseudo([Master | ServerList]) -> ok</name> + <name since="">pseudo([Master | ServerList]) -> ok</name> <fsummary>Start a number of pseudo servers.</fsummary> <type> <v>Master = node()</v> @@ -84,7 +84,7 @@ </func> <func> - <name name="pseudo" arity="2"/> + <name name="pseudo" arity="2" since=""/> <fsummary>Start a number of pseudo servers.</fsummary> <desc> <p>Starts a number of pseudo servers. A pseudo server is a @@ -102,7 +102,7 @@ rpc:call(N, slave, pseudo, [node(), [pxw_server]]).</code> </func> <func> - <name name="relay" arity="1"/> + <name name="relay" arity="1" since=""/> <fsummary>Run a pseudo server.</fsummary> <desc> <p>Runs a pseudo server. This function never returns any value @@ -113,9 +113,9 @@ rpc:call(N, slave, pseudo, [node(), [pxw_server]]).</code> </func> <func> - <name name="start" arity="1"/> - <name name="start" arity="2"/> - <name name="start" arity="3"/> + <name name="start" arity="1" since=""/> + <name name="start" arity="2" since=""/> + <name name="start" arity="3" since=""/> <fsummary>Start a slave node on a host.</fsummary> <desc> <p>Starts a slave node on host <c><anno>Host</anno></c>. Host names @@ -178,9 +178,9 @@ slave:start(H, Name, Arg).</code> </func> <func> - <name name="start_link" arity="1"/> - <name name="start_link" arity="2"/> - <name name="start_link" arity="3"/> + <name name="start_link" arity="1" since=""/> + <name name="start_link" arity="2" since=""/> + <name name="start_link" arity="3" since=""/> <fsummary>Start and link to a slave node on a host.</fsummary> <desc> <p>Starts a slave node in the same way as <c>start/1,2,3</c>, @@ -193,7 +193,7 @@ slave:start(H, Name, Arg).</code> </func> <func> - <name name="stop" arity="1"/> + <name name="stop" arity="1" since=""/> <fsummary>Stop (kill) a node.</fsummary> <desc> <p>Stops (kills) a node.</p> diff --git a/lib/stdlib/doc/src/sofs.xml b/lib/stdlib/doc/src/sofs.xml index 4cf1984d46..a0759d2f52 100644 --- a/lib/stdlib/doc/src/sofs.xml +++ b/lib/stdlib/doc/src/sofs.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>sofs.xml</file> </header> - <module>sofs</module> + <module since="">sofs</module> <modulesummary>Functions for manipulating sets of sets.</modulesummary> <description> <p>This module provides operations on finite sets and @@ -456,8 +456,8 @@ fun(S) -> sofs:partition(1, S) end <funcs> <func> - <name name="a_function" arity="1"/> - <name name="a_function" arity="2"/> + <name name="a_function" arity="1" since=""/> + <name name="a_function" arity="2" since=""/> <fsummary>Create a function.</fsummary> <desc> <p>Creates a <seealso marker="#function">function</seealso>. @@ -470,7 +470,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="canonical_relation" arity="1"/> + <name name="canonical_relation" arity="1" since=""/> <fsummary>Return the canonical map.</fsummary> <desc> <p>Returns the binary relation containing the elements @@ -490,7 +490,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="composite" arity="2"/> + <name name="composite" arity="2" since=""/> <fsummary>Return the composite of two functions.</fsummary> <desc> <p>Returns the <seealso marker="#composite">composite</seealso> of @@ -506,7 +506,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="constant_function" arity="2"/> + <name name="constant_function" arity="2" since=""/> <fsummary>Create the function that maps each element of a set onto another set.</fsummary> <desc> @@ -522,7 +522,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="converse" arity="1"/> + <name name="converse" arity="1" since=""/> <fsummary>Return the converse of a binary relation.</fsummary> <desc> <p>Returns the <seealso marker="#converse">converse</seealso> @@ -536,7 +536,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="difference" arity="2"/> + <name name="difference" arity="2" since=""/> <fsummary>Return the difference of two sets.</fsummary> <desc> <p>Returns the <seealso marker="#difference">difference</seealso> of @@ -545,8 +545,8 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="digraph_to_family" arity="1"/> - <name name="digraph_to_family" arity="2"/> + <name name="digraph_to_family" arity="1" since=""/> + <name name="digraph_to_family" arity="2" since=""/> <fsummary>Create a family from a directed graph.</fsummary> <desc> <p>Creates a <seealso marker="#family">family</seealso> from @@ -565,7 +565,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="domain" arity="1"/> + <name name="domain" arity="1" since=""/> <fsummary>Return the domain of a binary relation.</fsummary> <desc> <p>Returns the <seealso marker="#domain">domain</seealso> of @@ -579,7 +579,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="drestriction" arity="2"/> + <name name="drestriction" arity="2" since=""/> <fsummary>Return a restriction of a binary relation.</fsummary> <desc> <p>Returns the difference between the binary relation @@ -598,7 +598,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="drestriction" arity="3"/> + <name name="drestriction" arity="3" since=""/> <fsummary>Return a restriction of a relation.</fsummary> <desc> <p>Returns a subset of <c><anno>Set1</anno></c> containing those @@ -618,7 +618,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="empty_set" arity="0"/> + <name name="empty_set" arity="0" since=""/> <fsummary>Return the untyped empty set.</fsummary> <desc> <p>Returns the <seealso marker="#sets_definition">untyped empty @@ -628,7 +628,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="extension" arity="3"/> + <name name="extension" arity="3" since=""/> <fsummary>Extend the domain of a binary relation.</fsummary> <desc> <p>Returns the <seealso marker="#extension">extension</seealso> of @@ -648,8 +648,8 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family" arity="1"/> - <name name="family" arity="2"/> + <name name="family" arity="1" since=""/> + <name name="family" arity="2" since=""/> <fsummary>Create a family of subsets.</fsummary> <desc> <p>Creates a <seealso marker="#family">family of subsets</seealso>. @@ -662,7 +662,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_difference" arity="2"/> + <name name="family_difference" arity="2" since=""/> <fsummary>Return the difference of two families.</fsummary> <desc> <p>If <c><anno>Family1</anno></c> and <c><anno>Family2</anno></c> @@ -683,7 +683,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_domain" arity="1"/> + <name name="family_domain" arity="1" since=""/> <fsummary>Return a family of domains.</fsummary> <desc> <p>If <c><anno>Family1</anno></c> is @@ -704,7 +704,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_field" arity="1"/> + <name name="family_field" arity="1" since=""/> <fsummary>Return a family of fields.</fsummary> <desc> <p>If <c><anno>Family1</anno></c> is @@ -728,7 +728,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_intersection" arity="1"/> + <name name="family_intersection" arity="1" since=""/> <fsummary>Return the intersection of a family of sets of sets.</fsummary> <desc> @@ -752,7 +752,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_intersection" arity="2"/> + <name name="family_intersection" arity="2" since=""/> <fsummary>Return the intersection of two families.</fsummary> <desc> <p>If <c><anno>Family1</anno></c> and <c><anno>Family2</anno></c> @@ -772,7 +772,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_projection" arity="2"/> + <name name="family_projection" arity="2" since=""/> <fsummary>Return a family of modified subsets.</fsummary> <desc> <p>If <c><anno>Family1</anno></c> is @@ -791,7 +791,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_range" arity="1"/> + <name name="family_range" arity="1" since=""/> <fsummary>Return a family of ranges.</fsummary> <desc> <p>If <c><anno>Family1</anno></c> is @@ -812,7 +812,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_specification" arity="2"/> + <name name="family_specification" arity="2" since=""/> <fsummary>Select a subset of a family using a predicate.</fsummary> <desc> <p>If <c><anno>Family1</anno></c> is @@ -837,8 +837,8 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_to_digraph" arity="1"/> - <name name="family_to_digraph" arity="2"/> + <name name="family_to_digraph" arity="1" since=""/> + <name name="family_to_digraph" arity="2" since=""/> <fsummary>Create a directed graph from a family.</fsummary> <desc> <p>Creates a directed graph from @@ -863,7 +863,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_to_relation" arity="1"/> + <name name="family_to_relation" arity="1" since=""/> <fsummary>Create a binary relation from a family.</fsummary> <desc> <p>If <c><anno>Family</anno></c> is @@ -881,7 +881,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_union" arity="1"/> + <name name="family_union" arity="1" since=""/> <fsummary>Return the union of a family of sets of sets.</fsummary> <desc> <p>If <c><anno>Family1</anno></c> is @@ -904,7 +904,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="family_union" arity="2"/> + <name name="family_union" arity="2" since=""/> <fsummary>Return the union of two families.</fsummary> <desc> <p>If <c><anno>Family1</anno></c> and <c><anno>Family2</anno></c> @@ -926,7 +926,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="field" arity="1"/> + <name name="field" arity="1" since=""/> <fsummary>Return the field of a binary relation.</fsummary> <desc> <p>Returns the <seealso marker="#field">field</seealso> of the @@ -942,7 +942,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="from_external" arity="2"/> + <name name="from_external" arity="2" since=""/> <fsummary>Create a set.</fsummary> <desc> <p>Creates a set from the <seealso marker="#external_set">external @@ -955,7 +955,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="from_sets" arity="1" clause_i="1"/> + <name name="from_sets" arity="1" clause_i="1" since=""/> <fsummary>Create a set out of a list of sets.</fsummary> <desc> <p>Returns the <seealso marker="#sets_definition">unordered @@ -971,7 +971,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="from_sets" arity="1" clause_i="2"/> + <name name="from_sets" arity="1" clause_i="2" since=""/> <fsummary>Create an ordered set out of a tuple of sets.</fsummary> <desc> <p>Returns the <seealso marker="#sets_definition">ordered @@ -981,8 +981,8 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="from_term" arity="1"/> - <name name="from_term" arity="2"/> + <name name="from_term" arity="1" since=""/> + <name name="from_term" arity="2" since=""/> <fsummary>Create a set.</fsummary> <desc> <p><marker id="from_term"></marker>Creates an element @@ -1031,7 +1031,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="image" arity="2"/> + <name name="image" arity="2" since=""/> <fsummary>Return the image of a set under a binary relation.</fsummary> <desc> <p>Returns the <seealso marker="#image">image</seealso> of @@ -1047,7 +1047,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="intersection" arity="1"/> + <name name="intersection" arity="1" since=""/> <fsummary>Return the intersection of a set of sets.</fsummary> <desc> <p>Returns @@ -1059,7 +1059,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="intersection" arity="2"/> + <name name="intersection" arity="2" since=""/> <fsummary>Return the intersection of two sets.</fsummary> <desc> <p>Returns @@ -1069,7 +1069,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="intersection_of_family" arity="1"/> + <name name="intersection_of_family" arity="1" since=""/> <fsummary>Return the intersection of a family.</fsummary> <desc> <p>Returns the intersection of @@ -1086,7 +1086,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="inverse" arity="1"/> + <name name="inverse" arity="1" since=""/> <fsummary>Return the inverse of a function.</fsummary> <desc> <p>Returns the <seealso marker="#inverse">inverse</seealso> @@ -1100,7 +1100,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="inverse_image" arity="2"/> + <name name="inverse_image" arity="2" since=""/> <fsummary>Return the inverse image of a set under a binary relation.</fsummary> <desc> @@ -1117,7 +1117,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="is_a_function" arity="1"/> + <name name="is_a_function" arity="1" since=""/> <fsummary>Test for a function.</fsummary> <desc> <p>Returns <c>true</c> if the binary relation <c><anno>BinRel</anno></c> @@ -1127,7 +1127,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="is_disjoint" arity="2"/> + <name name="is_disjoint" arity="2" since=""/> <fsummary>Test for disjoint sets.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Set1</anno></c> @@ -1138,7 +1138,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="is_empty_set" arity="1"/> + <name name="is_empty_set" arity="1" since=""/> <fsummary>Test for an empty set.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>AnySet</anno></c> is an empty @@ -1147,7 +1147,7 @@ fun(S) -> sofs:partition(1, S) end </func> <func> - <name name="is_equal" arity="2"/> + <name name="is_equal" arity="2" since=""/> <fsummary>Test two sets for equality.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>AnySet1</anno></c> @@ -1164,7 +1164,7 @@ true</pre> </func> <func> - <name name="is_set" arity="1"/> + <name name="is_set" arity="1" since=""/> <fsummary>Test for an unordered set.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>AnySet</anno></c> is @@ -1175,7 +1175,7 @@ true</pre> </func> <func> - <name name="is_sofs_set" arity="1"/> + <name name="is_sofs_set" arity="1" since=""/> <fsummary>Test for an unordered set.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is @@ -1185,7 +1185,7 @@ true</pre> </func> <func> - <name name="is_subset" arity="2"/> + <name name="is_subset" arity="2" since=""/> <fsummary>Test two sets for subset.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Set1</anno></c> is @@ -1195,7 +1195,7 @@ true</pre> </func> <func> - <name name="is_type" arity="1"/> + <name name="is_type" arity="1" since=""/> <fsummary>Test for a type.</fsummary> <desc> <p>Returns <c>true</c> if term <c><anno>Term</anno></c> is @@ -1204,7 +1204,7 @@ true</pre> </func> <func> - <name name="join" arity="4"/> + <name name="join" arity="4" since=""/> <fsummary>Return the join of two relations.</fsummary> <desc> <p>Returns the <seealso marker="#natural_join">natural @@ -1221,7 +1221,7 @@ true</pre> </func> <func> - <name name="multiple_relative_product" arity="2"/> + <name name="multiple_relative_product" arity="2" since=""/> <fsummary>Return the multiple relative product of a tuple of binary relations and a relation.</fsummary> <desc> @@ -1242,7 +1242,7 @@ true</pre> </func> <func> - <name name="no_elements" arity="1"/> + <name name="no_elements" arity="1" since=""/> <fsummary>Return the number of elements of a set.</fsummary> <desc> <p>Returns the number of elements of the ordered or unordered @@ -1251,7 +1251,7 @@ true</pre> </func> <func> - <name name="partition" arity="1"/> + <name name="partition" arity="1" since=""/> <fsummary>Return the coarsest partition given a set of sets.</fsummary> <desc> <p>Returns the <seealso marker="#partition">partition</seealso> of @@ -1268,7 +1268,7 @@ true</pre> </func> <func> - <name name="partition" arity="2"/> + <name name="partition" arity="2" since=""/> <fsummary>Return a partition of a set.</fsummary> <desc> <p>Returns the <seealso marker="#partition">partition</seealso> of @@ -1284,7 +1284,7 @@ true</pre> </func> <func> - <name name="partition" arity="3"/> + <name name="partition" arity="3" since=""/> <fsummary>Return a partition of a set.</fsummary> <desc> <p>Returns a pair of sets that, regarded as constituting a @@ -1307,7 +1307,7 @@ true</pre> </func> <func> - <name name="partition_family" arity="2"/> + <name name="partition_family" arity="2" since=""/> <fsummary>Return a family indexing a partition.</fsummary> <desc> <p>Returns <seealso marker="#family">family</seealso> @@ -1328,7 +1328,7 @@ true</pre> </func> <func> - <name name="product" arity="1"/> + <name name="product" arity="1" since=""/> <fsummary>Return the Cartesian product of a tuple of sets.</fsummary> <desc> <p>Returns the <seealso marker="#Cartesian_product_tuple">Cartesian @@ -1347,7 +1347,7 @@ true</pre> </func> <func> - <name name="product" arity="2"/> + <name name="product" arity="2" since=""/> <fsummary>Return the Cartesian product of two sets.</fsummary> <desc> <p>Returns the <seealso marker="#Cartesian_product">Cartesian @@ -1365,7 +1365,7 @@ true</pre> </func> <func> - <name name="projection" arity="2"/> + <name name="projection" arity="2" since=""/> <fsummary>Return a set of substituted elements.</fsummary> <desc> <p>Returns the set created by substituting each element of @@ -1384,7 +1384,7 @@ true</pre> </func> <func> - <name name="range" arity="1"/> + <name name="range" arity="1" since=""/> <fsummary>Return the range of a binary relation.</fsummary> <desc> <p>Returns the <seealso marker="#range">range</seealso> of the @@ -1398,8 +1398,8 @@ true</pre> </func> <func> - <name name="relation" arity="1"/> - <name name="relation" arity="2"/> + <name name="relation" arity="1" since=""/> + <name name="relation" arity="2" since=""/> <fsummary>Create a relation.</fsummary> <desc> <p>Creates a <seealso marker="#relation">relation</seealso>. @@ -1417,7 +1417,7 @@ true</pre> </func> <func> - <name name="relation_to_family" arity="1"/> + <name name="relation_to_family" arity="1" since=""/> <fsummary>Create a family from a binary relation.</fsummary> <desc> <p>Returns <seealso marker="#family">family</seealso> @@ -1435,8 +1435,8 @@ true</pre> </func> <func> - <name name="relative_product" arity="1"/> - <name name="relative_product" arity="2" clause_i="1"/> + <name name="relative_product" arity="1" since=""/> + <name name="relative_product" arity="2" clause_i="1" since=""/> <fsummary>Return the relative product of a list of binary relations and a binary relation.</fsummary> <desc> @@ -1466,7 +1466,7 @@ true</pre> </func> <func> - <name name="relative_product" arity="2" clause_i="2"/> + <name name="relative_product" arity="2" clause_i="2" since=""/> <fsummary>Return the relative product of two binary relations.</fsummary> <desc> @@ -1477,7 +1477,7 @@ true</pre> </func> <func> - <name name="relative_product1" arity="2"/> + <name name="relative_product1" arity="2" since=""/> <fsummary>Return the relative_product of two binary relations.</fsummary> <desc> @@ -1498,7 +1498,7 @@ true</pre> </func> <func> - <name name="restriction" arity="2"/> + <name name="restriction" arity="2" since=""/> <fsummary>Return a restriction of a binary relation.</fsummary> <desc> <p>Returns the <seealso marker="#restriction">restriction</seealso> of @@ -1514,7 +1514,7 @@ true</pre> </func> <func> - <name name="restriction" arity="3"/> + <name name="restriction" arity="3" since=""/> <fsummary>Return a restriction of a set.</fsummary> <desc> <p>Returns a subset of <c><anno>Set1</anno></c> containing those @@ -1530,8 +1530,8 @@ true</pre> </func> <func> - <name name="set" arity="1"/> - <name name="set" arity="2"/> + <name name="set" arity="1" since=""/> + <name name="set" arity="2" since=""/> <fsummary>Create a set of atoms or any type of sets.</fsummary> <desc> <p>Creates an <seealso marker="#sets_definition">unordered @@ -1543,7 +1543,7 @@ true</pre> </func> <func> - <name name="specification" arity="2"/> + <name name="specification" arity="2" since=""/> <fsummary>Select a subset using a predicate.</fsummary> <desc> <p>Returns the set containing every element @@ -1564,7 +1564,7 @@ true</pre> </func> <func> - <name name="strict_relation" arity="1"/> + <name name="strict_relation" arity="1" since=""/> <fsummary>Return the strict relation corresponding to a given relation.</fsummary> <desc> @@ -1580,7 +1580,7 @@ true</pre> </func> <func> - <name name="substitution" arity="2"/> + <name name="substitution" arity="2" since=""/> <fsummary>Return a function with a given set as domain.</fsummary> <desc> <p>Returns a function, the domain of which @@ -1629,7 +1629,7 @@ images2(SetOfSets, BinRel) -> </func> <func> - <name name="symdiff" arity="2"/> + <name name="symdiff" arity="2" since=""/> <fsummary>Return the symmetric difference of two sets.</fsummary> <desc> <p>Returns the <seealso marker="#symmetric_difference">symmetric @@ -1645,7 +1645,7 @@ images2(SetOfSets, BinRel) -> </func> <func> - <name name="symmetric_partition" arity="2"/> + <name name="symmetric_partition" arity="2" since=""/> <fsummary>Return a partition of two sets.</fsummary> <desc> <p>Returns a triple of sets:</p> @@ -1666,7 +1666,7 @@ images2(SetOfSets, BinRel) -> </func> <func> - <name name="to_external" arity="1"/> + <name name="to_external" arity="1" since=""/> <fsummary>Return the elements of a set.</fsummary> <desc> <p>Returns the <seealso marker="#external_set">external @@ -1675,7 +1675,7 @@ images2(SetOfSets, BinRel) -> </func> <func> - <name name="to_sets" arity="1"/> + <name name="to_sets" arity="1" since=""/> <fsummary>Return a list or a tuple of the elements of a set.</fsummary> <desc> <p>Returns the elements of the ordered set <c><anno>ASet</anno></c> @@ -1686,7 +1686,7 @@ images2(SetOfSets, BinRel) -> </func> <func> - <name name="type" arity="1"/> + <name name="type" arity="1" since=""/> <fsummary>Return the type of a set.</fsummary> <desc> <p>Returns the <seealso marker="#type">type</seealso> of an @@ -1695,7 +1695,7 @@ images2(SetOfSets, BinRel) -> </func> <func> - <name name="union" arity="1"/> + <name name="union" arity="1" since=""/> <fsummary>Return the union of a set of sets.</fsummary> <desc> <p>Returns the <seealso marker="#union_n">union</seealso> of the @@ -1704,7 +1704,7 @@ images2(SetOfSets, BinRel) -> </func> <func> - <name name="union" arity="2"/> + <name name="union" arity="2" since=""/> <fsummary>Return the union of two sets.</fsummary> <desc> <p>Returns the <seealso marker="#union">union</seealso> of @@ -1713,7 +1713,7 @@ images2(SetOfSets, BinRel) -> </func> <func> - <name name="union_of_family" arity="1"/> + <name name="union_of_family" arity="1" since=""/> <fsummary>Return the union of a family.</fsummary> <desc> <p>Returns the union of <seealso marker="#family">family</seealso> @@ -1727,7 +1727,7 @@ images2(SetOfSets, BinRel) -> </func> <func> - <name name="weak_relation" arity="1"/> + <name name="weak_relation" arity="1" since=""/> <fsummary>Return the weak relation corresponding to a given relation.</fsummary> <desc> diff --git a/lib/stdlib/doc/src/string.xml b/lib/stdlib/doc/src/string.xml index 3348464eba..d102191a57 100644 --- a/lib/stdlib/doc/src/string.xml +++ b/lib/stdlib/doc/src/string.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>string.xml</file> </header> - <module>string</module> + <module since="">string</module> <modulesummary>String processing functions.</modulesummary> <description> <p>This module provides functions for string processing.</p> @@ -130,7 +130,7 @@ <funcs> <func> - <name name="casefold" arity="1"/> + <name name="casefold" arity="1" since="OTP 20.0"/> <fsummary>Convert a string to a comparable string.</fsummary> <desc> <p> @@ -147,7 +147,7 @@ </func> <func> - <name name="chomp" arity="1"/> + <name name="chomp" arity="1" since="OTP 20.0"/> <fsummary>Remove trailing end of line control characters.</fsummary> <desc> <p> @@ -164,9 +164,9 @@ </func> <func> - <name name="equal" arity="2"/> - <name name="equal" arity="3"/> - <name name="equal" arity="4"/> + <name name="equal" arity="2" since=""/> + <name name="equal" arity="3" since="OTP 20.0"/> + <name name="equal" arity="4" since="OTP 20.0"/> <fsummary>Test string equality.</fsummary> <desc> <p> @@ -201,8 +201,8 @@ true</pre> </func> <func> - <name name="find" arity="2"/> - <name name="find" arity="3"/> + <name name="find" arity="2" since="OTP 20.0"/> + <name name="find" arity="3" since="OTP 20.0"/> <fsummary>Find start of substring.</fsummary> <desc> <p> @@ -230,7 +230,7 @@ nomatch</pre> </func> <func> - <name name="is_empty" arity="1"/> + <name name="is_empty" arity="1" since="OTP 20.0"/> <fsummary>Check if the string is empty.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>String</anno></c> is the @@ -245,7 +245,7 @@ true</pre> </func> <func> - <name name="length" arity="1"/> + <name name="length" arity="1" since="OTP 20.0"/> <fsummary>Calculate length of the string.</fsummary> <desc> <p> @@ -261,7 +261,7 @@ true</pre> </func> <func> - <name name="lexemes" arity="2"/> + <name name="lexemes" arity="2" since="OTP 20.0"/> <fsummary>Split string into lexemes.</fsummary> <desc> <p> @@ -287,7 +287,7 @@ true</pre> </func> <func> - <name name="lowercase" arity="1"/> + <name name="lowercase" arity="1" since="OTP 20.0"/> <fsummary>Convert a string to lowercase</fsummary> <desc> <p> @@ -306,7 +306,7 @@ true</pre> </func> <func> - <name name="next_codepoint" arity="1"/> + <name name="next_codepoint" arity="1" since="OTP 20.0"/> <fsummary>Pick the first codepoint.</fsummary> <desc> <p> @@ -323,7 +323,7 @@ true</pre> </func> <func> - <name name="next_grapheme" arity="1"/> + <name name="next_grapheme" arity="1" since="OTP 20.0"/> <fsummary>Pick the first grapheme cluster.</fsummary> <desc> <p> @@ -340,7 +340,7 @@ true</pre> </func> <func> - <name name="nth_lexeme" arity="3"/> + <name name="nth_lexeme" arity="3" since="OTP 20.0"/> <fsummary>Pick the nth lexeme.</fsummary> <desc> <p>Returns lexeme number <c><anno>N</anno></c> in @@ -355,9 +355,9 @@ true</pre> </func> <func> - <name name="pad" arity="2"/> - <name name="pad" arity="3"/> - <name name="pad" arity="4"/> + <name name="pad" arity="2" since="OTP 20.0"/> + <name name="pad" arity="3" since="OTP 20.0"/> + <name name="pad" arity="4" since="OTP 20.0"/> <fsummary>Pad a string to given length.</fsummary> <desc> <p> @@ -381,7 +381,7 @@ true</pre> </func> <func> - <name name="prefix" arity="2"/> + <name name="prefix" arity="2" since="OTP 20.0"/> <fsummary>Remove prefix from string.</fsummary> <desc> <p> @@ -400,8 +400,8 @@ nomatch</pre> </func> <func> - <name name="replace" arity="3"/> - <name name="replace" arity="4"/> + <name name="replace" arity="3" since="OTP 20.0"/> + <name name="replace" arity="4" since="OTP 20.0"/> <fsummary>Replace a pattern in string.</fsummary> <desc> <p> @@ -423,7 +423,7 @@ nomatch</pre> </func> <func> - <name name="reverse" arity="1"/> + <name name="reverse" arity="1" since="OTP 20.0"/> <fsummary>Reverses a string</fsummary> <desc> <p> @@ -439,8 +439,8 @@ ÖÄÅ</pre> </func> <func> - <name name="slice" arity="2"/> - <name name="slice" arity="3"/> + <name name="slice" arity="2" since="OTP 20.0"/> + <name name="slice" arity="3" since="OTP 20.0"/> <fsummary>Extract a part of string</fsummary> <desc> <p>Returns a substring of <c><anno>String</anno></c> of @@ -459,8 +459,8 @@ ÖÄÅ</pre> </func> <func> - <name name="split" arity="2"/> - <name name="split" arity="3"/> + <name name="split" arity="2" since="OTP 20.0"/> + <name name="split" arity="3" since="OTP 20.0"/> <fsummary>Split a string into substrings.</fsummary> <desc> <p> @@ -482,9 +482,9 @@ ÖÄÅ</pre> </func> <func> - <name name="take" arity="2"/> - <name name="take" arity="3"/> - <name name="take" arity="4"/> + <name name="take" arity="2" since="OTP 20.0"/> + <name name="take" arity="3" since="OTP 20.0"/> + <name name="take" arity="4" since="OTP 20.0"/> <fsummary>Take leading or trailing parts.</fsummary> <desc> <p>Takes characters from <c><anno>String</anno></c> as long as @@ -508,7 +508,7 @@ ÖÄÅ</pre> </func> <func> - <name name="titlecase" arity="1"/> + <name name="titlecase" arity="1" since="OTP 20.0"/> <fsummary>Convert a string to titlecase.</fsummary> <desc> <p> @@ -522,7 +522,7 @@ ÖÄÅ</pre> </func> <func> - <name name="to_float" arity="1"/> + <name name="to_float" arity="1" since=""/> <fsummary>Return a float whose text representation is the integers (ASCII values) of a string.</fsummary> <desc> @@ -544,7 +544,7 @@ ÖÄÅ</pre> </func> <func> - <name name="to_integer" arity="1"/> + <name name="to_integer" arity="1" since=""/> <fsummary>Return an integer whose text representation is the integers (ASCII values) of a string.</fsummary> <desc> @@ -566,7 +566,7 @@ ÖÄÅ</pre> </func> <func> - <name name="to_graphemes" arity="1"/> + <name name="to_graphemes" arity="1" since="OTP 20.0"/> <fsummary>Convert a string to a list of grapheme clusters.</fsummary> <desc> <p> @@ -582,9 +582,9 @@ ÖÄÅ</pre> </func> <func> - <name name="trim" arity="1"/> - <name name="trim" arity="2"/> - <name name="trim" arity="3"/> + <name name="trim" arity="1" since="OTP 20.0"/> + <name name="trim" arity="2" since="OTP 20.0"/> + <name name="trim" arity="3" since="OTP 20.0"/> <fsummary>Trim leading or trailing, or both, characters.</fsummary> <desc> <p> @@ -616,7 +616,7 @@ ÖÄÅ</pre> </func> <func> - <name name="uppercase" arity="1"/> + <name name="uppercase" arity="1" since="OTP 20.0"/> <fsummary>Convert a string to uppercase.</fsummary> <desc> <p> @@ -649,8 +649,8 @@ ÖÄÅ</pre> <funcs> <func> - <name name="centre" arity="2"/> - <name name="centre" arity="3"/> + <name name="centre" arity="2" since=""/> + <name name="centre" arity="3" since=""/> <fsummary>Center a string.</fsummary> <desc> <p>Returns a string, where <c><anno>String</anno></c> is centered in the @@ -664,8 +664,8 @@ ÖÄÅ</pre> </func> <func> - <name name="chars" arity="2"/> - <name name="chars" arity="3"/> + <name name="chars" arity="2" since=""/> + <name name="chars" arity="3" since=""/> <fsummary>Return a string consisting of numbers of characters.</fsummary> <desc> <p>Returns a string consisting of <c><anno>Number</anno></c> characters @@ -678,7 +678,7 @@ ÖÄÅ</pre> </func> <func> - <name name="chr" arity="2"/> + <name name="chr" arity="2" since=""/> <fsummary>Return the index of the first occurrence of a character in a string.</fsummary> <desc> @@ -692,7 +692,7 @@ ÖÄÅ</pre> </func> <func> - <name name="concat" arity="2"/> + <name name="concat" arity="2" since=""/> <fsummary>Concatenate two strings.</fsummary> <desc> <p>Concatenates <c><anno>String1</anno></c> and @@ -712,7 +712,7 @@ ÖÄÅ</pre> </func> <func> - <name name="copies" arity="2"/> + <name name="copies" arity="2" since=""/> <fsummary>Copy a string.</fsummary> <desc> <p>Returns a string containing <c><anno>String</anno></c> repeated @@ -724,7 +724,7 @@ ÖÄÅ</pre> </func> <func> - <name name="cspan" arity="2"/> + <name name="cspan" arity="2" since=""/> <fsummary>Span characters at start of a string.</fsummary> <desc> <p>Returns the length of the maximum initial segment of @@ -741,7 +741,7 @@ ÖÄÅ</pre> </func> <func> - <name name="join" arity="2"/> + <name name="join" arity="2" since=""/> <fsummary>Join a list of strings with separator.</fsummary> <desc> <p>Returns a string with the elements of <c><anno>StringList</anno></c> @@ -757,8 +757,8 @@ ÖÄÅ</pre> </func> <func> - <name name="left" arity="2"/> - <name name="left" arity="3"/> + <name name="left" arity="2" since=""/> + <name name="left" arity="3" since=""/> <fsummary>Adjust left end of a string.</fsummary> <desc> <p>Returns <c><anno>String</anno></c> with the length adjusted in @@ -778,7 +778,7 @@ ÖÄÅ</pre> </func> <func> - <name name="len" arity="1"/> + <name name="len" arity="1" since=""/> <fsummary>Return the length of a string.</fsummary> <desc> <p>Returns the number of characters in <c><anno>String</anno></c>.</p> @@ -789,7 +789,7 @@ ÖÄÅ</pre> </func> <func> - <name name="rchr" arity="2"/> + <name name="rchr" arity="2" since=""/> <fsummary>Return the index of the last occurrence of a character in a string.</fsummary> <desc> @@ -803,8 +803,8 @@ ÖÄÅ</pre> </func> <func> - <name name="right" arity="2"/> - <name name="right" arity="3"/> + <name name="right" arity="2" since=""/> + <name name="right" arity="3" since=""/> <fsummary>Adjust right end of a string.</fsummary> <desc> <p>Returns <c><anno>String</anno></c> with the length adjusted in @@ -823,7 +823,7 @@ ÖÄÅ</pre> </func> <func> - <name name="rstr" arity="2"/> + <name name="rstr" arity="2" since=""/> <fsummary>Find the index of a substring.</fsummary> <desc> <p>Returns the position where the last occurrence of @@ -841,7 +841,7 @@ ÖÄÅ</pre> </func> <func> - <name name="span" arity="2"/> + <name name="span" arity="2" since=""/> <fsummary>Span characters at start of a string.</fsummary> <desc> <p>Returns the length of the maximum initial segment of @@ -858,7 +858,7 @@ ÖÄÅ</pre> </func> <func> - <name name="str" arity="2"/> + <name name="str" arity="2" since=""/> <fsummary>Find the index of a substring.</fsummary> <desc> <p>Returns the position where the first occurrence of @@ -876,9 +876,9 @@ ÖÄÅ</pre> </func> <func> - <name name="strip" arity="1"/> - <name name="strip" arity="2"/> - <name name="strip" arity="3"/> + <name name="strip" arity="1" since=""/> + <name name="strip" arity="2" since=""/> + <name name="strip" arity="3" since=""/> <fsummary>Strip leading or trailing characters.</fsummary> <desc> <p>Returns a string, where leading or trailing, or both, blanks or a @@ -898,8 +898,8 @@ ÖÄÅ</pre> </func> <func> - <name name="sub_string" arity="2"/> - <name name="sub_string" arity="3"/> + <name name="sub_string" arity="2" since=""/> + <name name="sub_string" arity="3" since=""/> <fsummary>Extract a substring.</fsummary> <desc> <p>Returns a substring of <c><anno>String</anno></c>, starting at @@ -916,8 +916,8 @@ sub_string("Hello World", 4, 8). </func> <func> - <name name="substr" arity="2"/> - <name name="substr" arity="3"/> + <name name="substr" arity="2" since=""/> + <name name="substr" arity="3" since=""/> <fsummary>Return a substring of a string.</fsummary> <desc> <p>Returns a substring of <c><anno>String</anno></c>, starting at @@ -934,8 +934,8 @@ sub_string("Hello World", 4, 8). </func> <func> - <name name="sub_word" arity="2"/> - <name name="sub_word" arity="3"/> + <name name="sub_word" arity="2" since=""/> + <name name="sub_word" arity="3" since=""/> <fsummary>Extract subword.</fsummary> <desc> <p>Returns the word in position <c><anno>Number</anno></c> of @@ -952,10 +952,10 @@ sub_string("Hello World", 4, 8). </func> <func> - <name name="to_lower" arity="1" clause_i="1"/> - <name name="to_lower" arity="1" clause_i="2"/> - <name name="to_upper" arity="1" clause_i="1"/> - <name name="to_upper" arity="1" clause_i="2"/> + <name name="to_lower" arity="1" clause_i="1" since=""/> + <name name="to_lower" arity="1" clause_i="2" since=""/> + <name name="to_upper" arity="1" clause_i="1" since=""/> + <name name="to_upper" arity="1" clause_i="2" since=""/> <fsummary>Convert case of string (ISO/IEC 8859-1).</fsummary> <type variable="String" name_i="1"/> <type variable="Result" name_i="1"/> @@ -974,7 +974,7 @@ sub_string("Hello World", 4, 8). </func> <func> - <name name="tokens" arity="2"/> + <name name="tokens" arity="2" since=""/> <fsummary>Split string into tokens.</fsummary> <desc> <p>Returns a list of tokens in <c><anno>String</anno></c>, separated @@ -994,8 +994,8 @@ sub_string("Hello World", 4, 8). </func> <func> - <name name="words" arity="1"/> - <name name="words" arity="2"/> + <name name="words" arity="1" since=""/> + <name name="words" arity="2" since=""/> <fsummary>Count blank separated words.</fsummary> <desc> <p>Returns the number of words in <c><anno>String</anno></c>, separated diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index 5fd5760499..f15b1a2dd3 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>supervisor</module> + <module since="">supervisor</module> <modulesummary>Generic supervisor behavior.</modulesummary> <description> <p>This behavior module provides a supervisor, a process that @@ -318,7 +318,7 @@ child_spec() = #{id => child_id(), % mandatory <funcs> <func> - <name name="check_childspecs" arity="1"/> + <name name="check_childspecs" arity="1" since=""/> <fsummary>Check if children specifications are syntactically correct. </fsummary> <desc> @@ -329,7 +329,7 @@ child_spec() = #{id => child_id(), % mandatory </func> <func> - <name name="count_children" arity="1"/> + <name name="count_children" arity="1" since="OTP R13B04"/> <fsummary>Return counts for the number of child specifications, active children, supervisors, and workers.</fsummary> <desc> @@ -366,7 +366,7 @@ child_spec() = #{id => child_id(), % mandatory </func> <func> - <name name="delete_child" arity="2"/> + <name name="delete_child" arity="2" since=""/> <fsummary>Delete a child specification from a supervisor.</fsummary> <desc> <p>Tells supervisor <c><anno>SupRef</anno></c> to delete the child @@ -387,7 +387,7 @@ child_spec() = #{id => child_id(), % mandatory </func> <func> - <name name="get_childspec" arity="2"/> + <name name="get_childspec" arity="2" since="OTP 18.0"/> <fsummary>Return the child specification map for the specified child.</fsummary> <desc> @@ -400,7 +400,7 @@ child_spec() = #{id => child_id(), % mandatory </func> <func> - <name name="restart_child" arity="2"/> + <name name="restart_child" arity="2" since=""/> <fsummary>Restart a terminated child process belonging to a supervisor. </fsummary> <desc> @@ -436,7 +436,7 @@ child_spec() = #{id => child_id(), % mandatory </func> <func> - <name name="start_child" arity="2"/> + <name name="start_child" arity="2" since=""/> <fsummary>Dynamically add a child process to a supervisor.</fsummary> <type name="startchild_ret"/> <type name="startchild_err"/> @@ -503,8 +503,8 @@ child_spec() = #{id => child_id(), % mandatory </func> <func> - <name name="start_link" arity="2"/> - <name name="start_link" arity="3"/> + <name name="start_link" arity="2" since=""/> + <name name="start_link" arity="3" since=""/> <fsummary>Create a supervisor process.</fsummary> <type name="startlink_ret"/> <type name="startlink_err"/> @@ -584,7 +584,7 @@ child_spec() = #{id => child_id(), % mandatory </func> <func> - <name name="terminate_child" arity="2"/> + <name name="terminate_child" arity="2" since=""/> <fsummary>Terminate a child process belonging to a supervisor.</fsummary> <desc> <p>Tells supervisor <c><anno>SupRef</anno></c> to terminate the @@ -621,7 +621,7 @@ child_spec() = #{id => child_id(), % mandatory </func> <func> - <name name="which_children" arity="1"/> + <name name="which_children" arity="1" since=""/> <fsummary>Return information about all children specifications and child processes belonging to a supervisor.</fsummary> <desc> @@ -666,7 +666,7 @@ child_spec() = #{id => child_id(), % mandatory <funcs> <func> - <name>Module:init(Args) -> Result</name> + <name since="">Module:init(Args) -> Result</name> <fsummary>Return a supervisor specification.</fsummary> <type> <v>Args = term()</v> diff --git a/lib/stdlib/doc/src/supervisor_bridge.xml b/lib/stdlib/doc/src/supervisor_bridge.xml index c4c1b37548..ee5d97fea1 100644 --- a/lib/stdlib/doc/src/supervisor_bridge.xml +++ b/lib/stdlib/doc/src/supervisor_bridge.xml @@ -30,7 +30,7 @@ <date></date> <rev></rev> </header> - <module>supervisor_bridge</module> + <module since="">supervisor_bridge</module> <modulesummary>Generic supervisor bridge behavior.</modulesummary> <description> <p>This behavior module provides a supervisor bridge, a process @@ -57,8 +57,8 @@ <funcs> <func> - <name name="start_link" arity="2"/> - <name name="start_link" arity="3"/> + <name name="start_link" arity="2" since=""/> + <name name="start_link" arity="3" since=""/> <fsummary>Create a supervisor bridge process.</fsummary> <desc> <p>Creates a supervisor bridge process, linked to the calling process, @@ -133,7 +133,7 @@ <funcs> <func> - <name>Module:init(Args) -> Result</name> + <name since="">Module:init(Args) -> Result</name> <fsummary>Initialize process and start subsystem.</fsummary> <type> <v>Args = term()</v> @@ -164,7 +164,7 @@ </func> <func> - <name>Module:terminate(Reason, State)</name> + <name since="">Module:terminate(Reason, State)</name> <fsummary>Clean up and stop subsystem.</fsummary> <type> <v>Reason = shutdown | term()</v> diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml index 9fe816e33a..6fc508b853 100644 --- a/lib/stdlib/doc/src/sys.xml +++ b/lib/stdlib/doc/src/sys.xml @@ -32,7 +32,7 @@ <rev></rev> <file>sys.xml</file> </header> - <module>sys</module> + <module since="">sys</module> <modulesummary>A functional interface to system messages.</modulesummary> <description> <p>This module contains functions for sending system messages used by @@ -129,8 +129,8 @@ <funcs> <func> - <name name="change_code" arity="4"/> - <name name="change_code" arity="5"/> + <name name="change_code" arity="4" since=""/> + <name name="change_code" arity="5" since=""/> <fsummary>Send the code change system message to the process.</fsummary> <desc> <p>Tells the process to change code. The process must be @@ -143,8 +143,8 @@ </func> <func> - <name name="get_state" arity="1"/> - <name name="get_state" arity="2"/> + <name name="get_state" arity="1" since="OTP R16B01"/> + <name name="get_state" arity="2" since="OTP R16B01"/> <fsummary>Get the state of the process.</fsummary> <desc> <p>Gets the state of the process.</p> @@ -227,8 +227,8 @@ </func> <func> - <name name="get_status" arity="1"/> - <name name="get_status" arity="2"/> + <name name="get_status" arity="1" since=""/> + <name name="get_status" arity="2" since=""/> <fsummary>Get the status of the process.</fsummary> <desc> <p>Gets the status of the process.</p> @@ -265,8 +265,8 @@ </func> <func> - <name name="install" arity="2"/> - <name name="install" arity="3"/> + <name name="install" arity="2" since=""/> + <name name="install" arity="3" since=""/> <fsummary>Install a debug function in the process.</fsummary> <desc> <p>Enables installation of alternative debug functions. An example of @@ -283,8 +283,8 @@ </func> <func> - <name name="log" arity="2"/> - <name name="log" arity="3"/> + <name name="log" arity="2" since=""/> + <name name="log" arity="3" since=""/> <fsummary>Log system events in memory.</fsummary> <desc> <p>Turns the logging of system events on or off. If on, a @@ -302,8 +302,8 @@ </func> <func> - <name name="log_to_file" arity="2"/> - <name name="log_to_file" arity="3"/> + <name name="log_to_file" arity="2" since=""/> + <name name="log_to_file" arity="3" since=""/> <fsummary>Log system events to the specified file.</fsummary> <desc> <p>Enables or disables the logging of all system events in text @@ -315,8 +315,8 @@ </func> <func> - <name name="no_debug" arity="1"/> - <name name="no_debug" arity="2"/> + <name name="no_debug" arity="1" since=""/> + <name name="no_debug" arity="2" since=""/> <fsummary>Turn off debugging.</fsummary> <desc> <p>Turns off all debugging for the process. This includes @@ -327,8 +327,8 @@ </func> <func> - <name name="remove" arity="2"/> - <name name="remove" arity="3"/> + <name name="remove" arity="2" since=""/> + <name name="remove" arity="3" since=""/> <fsummary>Remove a debug function from the process.</fsummary> <desc> <p>Removes an installed debug function from the @@ -338,8 +338,8 @@ </func> <func> - <name name="replace_state" arity="2"/> - <name name="replace_state" arity="3"/> + <name name="replace_state" arity="2" since="OTP R16B01"/> + <name name="replace_state" arity="3" since="OTP R16B01"/> <fsummary>Replace the state of the process.</fsummary> <desc> <p>Replaces the state of the process, and returns the new state.</p> @@ -451,8 +451,8 @@ </func> <func> - <name name="resume" arity="1"/> - <name name="resume" arity="2"/> + <name name="resume" arity="1" since=""/> + <name name="resume" arity="2" since=""/> <fsummary>Resume a suspended process.</fsummary> <desc> <p>Resumes a suspended process.</p> @@ -460,8 +460,8 @@ </func> <func> - <name name="statistics" arity="2"/> - <name name="statistics" arity="3"/> + <name name="statistics" arity="2" since=""/> + <name name="statistics" arity="3" since=""/> <fsummary>Enable or disable the collections of statistics.</fsummary> <desc> <p>Enables or disables the collection of statistics. If @@ -471,8 +471,8 @@ </func> <func> - <name name="suspend" arity="1"/> - <name name="suspend" arity="2"/> + <name name="suspend" arity="1" since=""/> + <name name="suspend" arity="2" since=""/> <fsummary>Suspend the process.</fsummary> <desc> <p>Suspends the process. When the process is suspended, it @@ -482,8 +482,8 @@ </func> <func> - <name name="terminate" arity="2"/> - <name name="terminate" arity="3"/> + <name name="terminate" arity="2" since="OTP 18.0"/> + <name name="terminate" arity="3" since="OTP 18.0"/> <fsummary>Terminate the process.</fsummary> <desc> <p>Orders the process to terminate with the @@ -494,8 +494,8 @@ </func> <func> - <name name="trace" arity="2"/> - <name name="trace" arity="3"/> + <name name="trace" arity="2" since=""/> + <name name="trace" arity="3" since=""/> <fsummary>Print all system events on <c>standard_io</c>.</fsummary> <desc> <p>Prints all system events on <c>standard_io</c>. The events are @@ -518,7 +518,7 @@ <funcs> <func> - <name name="debug_options" arity="1"/> + <name name="debug_options" arity="1" since=""/> <fsummary>Convert a list of options to a debug structure.</fsummary> <desc> <p>Can be used by a process that initiates a debug @@ -529,7 +529,7 @@ </func> <func> - <name name="get_debug" arity="3"/> + <name name="get_debug" arity="3" since=""/> <fsummary>Get the data associated with a debug option.</fsummary> <desc> <p>Gets the data associated with a debug option. @@ -541,7 +541,7 @@ </func> <func> - <name name="handle_debug" arity="4"/> + <name name="handle_debug" arity="4" since=""/> <fsummary>Generate a system event.</fsummary> <desc> <p>This function is called by a process when it generates a @@ -556,7 +556,7 @@ </func> <func> - <name name="handle_system_msg" arity="6"/> + <name name="handle_system_msg" arity="6" since=""/> <fsummary>Take care of system messages.</fsummary> <desc> <p>This function is used by a process module to take care of system @@ -594,7 +594,7 @@ </func> <func> - <name name="print_log" arity="1"/> + <name name="print_log" arity="1" since=""/> <fsummary>Print the logged events in the debug structure.</fsummary> <desc> <p>Prints the logged system events in the debug structure, @@ -605,7 +605,7 @@ </func> <func> - <name>Module:system_code_change(Misc, Module, OldVsn, Extra) -> + <name since="">Module:system_code_change(Misc, Module, OldVsn, Extra) -> {ok, NMisc}</name> <fsummary>Called when the process is to perform a code change.</fsummary> <type> @@ -628,7 +628,7 @@ </func> <func> - <name>Module:system_continue(Parent, Debug, Misc) -> none()</name> + <name since="">Module:system_continue(Parent, Debug, Misc) -> none()</name> <fsummary>Called when the process is to continue its execution.</fsummary> <type> <v>Parent = pid()</v> @@ -644,7 +644,7 @@ </func> <func> - <name>Module:system_get_state(Misc) -> {ok, State}</name> + <name since="OTP 17.0">Module:system_get_state(Misc) -> {ok, State}</name> <fsummary>Called when the process is to return its current state. </fsummary> <type> @@ -661,7 +661,7 @@ </func> <func> - <name>Module:system_replace_state(StateFun, Misc) -> + <name since="OTP 17.0">Module:system_replace_state(StateFun, Misc) -> {ok, NState, NMisc}</name> <fsummary>Called when the process is to replace its current state. </fsummary> @@ -681,7 +681,7 @@ </func> <func> - <name>Module:system_terminate(Reason, Parent, Debug, Misc) -> none()</name> + <name since="">Module:system_terminate(Reason, Parent, Debug, Misc) -> none()</name> <fsummary>Called when the process is to terminate.</fsummary> <type> <v>Reason = term()</v> diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml index e913e33589..165eecfbb0 100644 --- a/lib/stdlib/doc/src/timer.xml +++ b/lib/stdlib/doc/src/timer.xml @@ -32,7 +32,7 @@ <rev>D</rev> <file>timer.xml</file> </header> - <module>timer</module> + <module since="">timer</module> <modulesummary>Timer functions.</modulesummary> <description> <p>This module provides useful functions related to time. Unless otherwise @@ -62,7 +62,7 @@ <funcs> <func> - <name name="apply_after" arity="4"/> + <name name="apply_after" arity="4" since=""/> <fsummary>Apply <c>Module:Function(Arguments)</c> after a specified <c>Time</c>.</fsummary> <desc> @@ -75,7 +75,7 @@ </func> <func> - <name name="apply_interval" arity="4"/> + <name name="apply_interval" arity="4" since=""/> <fsummary>Evaluate <c>Module:Function(Arguments)</c> repeatedly at intervals of <c>Time</c>.</fsummary> <desc> @@ -88,7 +88,7 @@ </func> <func> - <name name="cancel" arity="1"/> + <name name="cancel" arity="1" since=""/> <fsummary>Cancel a previously requested time-out identified by <c>TRef</c>.</fsummary> <desc> @@ -101,8 +101,8 @@ </func> <func> - <name name="exit_after" arity="2"/> - <name name="exit_after" arity="3"/> + <name name="exit_after" arity="2" since=""/> + <name name="exit_after" arity="3" since=""/> <fsummary>Send an exit signal with <c>Reason</c> after a specified <c>Time</c>.</fsummary> <desc> @@ -117,7 +117,7 @@ </func> <func> - <name name="hms" arity="3"/> + <name name="hms" arity="3" since=""/> <fsummary>Convert <c>Hours</c>+<c>Minutes</c>+<c>Seconds</c> to <c>Milliseconds</c>.</fsummary> <desc> @@ -127,7 +127,7 @@ </func> <func> - <name name="hours" arity="1"/> + <name name="hours" arity="1" since=""/> <fsummary>Convert <c>Hours</c> to <c>Milliseconds</c>.</fsummary> <desc> <p>Returns the number of milliseconds in <c><anno>Hours</anno></c>.</p> @@ -135,8 +135,8 @@ </func> <func> - <name name="kill_after" arity="1"/> - <name name="kill_after" arity="2"/> + <name name="kill_after" arity="1" since=""/> + <name name="kill_after" arity="2" since=""/> <fsummary>Send an exit signal with <c>Reason</c> after a specified <c>Time</c>.</fsummary> <desc> @@ -148,7 +148,7 @@ </func> <func> - <name name="minutes" arity="1"/> + <name name="minutes" arity="1" since=""/> <fsummary>Converts <c>Minutes</c> to <c>Milliseconds</c>.</fsummary> <desc> <p>Returns the number of milliseconds in @@ -157,7 +157,7 @@ </func> <func> - <name name="now_diff" arity="2"/> + <name name="now_diff" arity="2" since=""/> <fsummary>Calculate time difference between time stamps.</fsummary> <type_desc variable="Tdiff">In microseconds</type_desc> <desc> @@ -173,7 +173,7 @@ </func> <func> - <name name="seconds" arity="1"/> + <name name="seconds" arity="1" since=""/> <fsummary>Convert <c>Seconds</c> to <c>Milliseconds</c>.</fsummary> <desc> <p>Returns the number of milliseconds in @@ -182,8 +182,8 @@ </func> <func> - <name name="send_after" arity="2"/> - <name name="send_after" arity="3"/> + <name name="send_after" arity="2" since=""/> + <name name="send_after" arity="3" since=""/> <fsummary>Send <c>Message</c> to <c>Pid</c> after a specified <c>Time</c>.</fsummary> <desc> @@ -206,8 +206,8 @@ </func> <func> - <name name="send_interval" arity="2"/> - <name name="send_interval" arity="3"/> + <name name="send_interval" arity="2" since=""/> + <name name="send_interval" arity="3" since=""/> <fsummary>Send <c>Message</c> repeatedly at intervals of <c>Time</c>. </fsummary> <desc> @@ -231,7 +231,7 @@ </func> <func> - <name name="sleep" arity="1"/> + <name name="sleep" arity="1" since=""/> <fsummary>Suspend the calling process for <c>Time</c> milliseconds. </fsummary> <desc> @@ -244,7 +244,7 @@ </func> <func> - <name name="start" arity="0"/> + <name name="start" arity="0" since=""/> <fsummary>Start a global timer server (named <c>timer_server</c>). </fsummary> <desc> @@ -258,9 +258,9 @@ </func> <func> - <name name="tc" arity="1"/> - <name name="tc" arity="2"/> - <name name="tc" arity="3"/> + <name name="tc" arity="1" since="OTP R14B03"/> + <name name="tc" arity="2" since="OTP R14B"/> + <name name="tc" arity="3" since=""/> <fsummary>Measure the real time it takes to evaluate <c>apply(Module, Function, Arguments)</c> or <c>apply(Fun, Arguments)</c>.</fsummary> <type_desc variable="Time">In microseconds</type_desc> diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml index d822aca89c..b7696a4b7e 100644 --- a/lib/stdlib/doc/src/unicode.xml +++ b/lib/stdlib/doc/src/unicode.xml @@ -30,7 +30,7 @@ <date></date> <rev></rev> </header> - <module>unicode</module> + <module since="">unicode</module> <modulesummary>Functions for converting Unicode characters.</modulesummary> <description> <p>This module contains functions for converting between different character @@ -139,7 +139,7 @@ <funcs> <func> - <name name="bom_to_encoding" arity="1"/> + <name name="bom_to_encoding" arity="1" since=""/> <fsummary>Identify UTF byte order marks in a binary.</fsummary> <type name="endian"/> <type_desc variable="Bin"> @@ -156,7 +156,7 @@ </func> <func> - <name name="characters_to_binary" arity="1"/> + <name name="characters_to_binary" arity="1" since=""/> <fsummary>Convert a collection of characters to a UTF-8 binary.</fsummary> <desc> <p>Same as <c>characters_to_binary(<anno>Data</anno>, unicode, @@ -165,7 +165,7 @@ </func> <func> - <name name="characters_to_binary" arity="2"/> + <name name="characters_to_binary" arity="2" since=""/> <fsummary>Convert a collection of characters to a UTF-8 binary.</fsummary> <desc> <p>Same as <c>characters_to_binary(<anno>Data</anno>, @@ -174,7 +174,7 @@ </func> <func> - <name name="characters_to_binary" arity="3"/> + <name name="characters_to_binary" arity="3" since=""/> <fsummary>Convert a collection of characters to a UTF-8 binary.</fsummary> <desc> <p>Behaves as <seealso marker="#characters_to_list/2"> @@ -211,7 +211,7 @@ </func> <func> - <name name="characters_to_list" arity="1"/> + <name name="characters_to_list" arity="1" since=""/> <fsummary>Convert a collection of characters to a list of Unicode characters.</fsummary> <desc> @@ -220,7 +220,7 @@ </func> <func> - <name name="characters_to_list" arity="2"/> + <name name="characters_to_list" arity="2" since=""/> <fsummary>Convert a collection of characters to a list of Unicode characters.</fsummary> <desc> @@ -367,7 +367,7 @@ decode_data(Data) -> </func> <func> - <name name="characters_to_nfc_list" arity="1"/> + <name name="characters_to_nfc_list" arity="1" since="OTP 20.0"/> <fsummary>Normalize characters to a list of canonical equivalent composed Unicode characters.</fsummary> <desc> @@ -386,7 +386,7 @@ decode_data(Data) -> </func> <func> - <name name="characters_to_nfc_binary" arity="1"/> + <name name="characters_to_nfc_binary" arity="1" since="OTP 20.0"/> <fsummary>Normalize characters to a utf8 binary of canonical equivalent composed Unicode characters.</fsummary> <desc> @@ -404,7 +404,7 @@ decode_data(Data) -> </func> <func> - <name name="characters_to_nfd_list" arity="1"/> + <name name="characters_to_nfd_list" arity="1" since="OTP 20.0"/> <fsummary>Normalize characters to a list of canonical equivalent decomposed Unicode characters.</fsummary> <desc> @@ -423,7 +423,7 @@ decode_data(Data) -> </func> <func> - <name name="characters_to_nfd_binary" arity="1"/> + <name name="characters_to_nfd_binary" arity="1" since="OTP 20.0"/> <fsummary>Normalize characters to a utf8 binary of canonical equivalent decomposed Unicode characters.</fsummary> <desc> @@ -441,7 +441,7 @@ decode_data(Data) -> </func> <func> - <name name="characters_to_nfkc_list" arity="1"/> + <name name="characters_to_nfkc_list" arity="1" since="OTP 20.0"/> <fsummary>Normalize characters to a list of canonical equivalent composed Unicode characters.</fsummary> <desc> @@ -460,7 +460,7 @@ decode_data(Data) -> </func> <func> - <name name="characters_to_nfkc_binary" arity="1"/> + <name name="characters_to_nfkc_binary" arity="1" since="OTP 20.0"/> <fsummary>Normalize characters to a utf8 binary of compatibly equivalent composed Unicode characters.</fsummary> <desc> @@ -478,7 +478,7 @@ decode_data(Data) -> </func> <func> - <name name="characters_to_nfkd_list" arity="1"/> + <name name="characters_to_nfkd_list" arity="1" since="OTP 20.0"/> <fsummary>Normalize characters to a list of compatibly equivalent decomposed Unicode characters.</fsummary> <desc> @@ -497,7 +497,7 @@ decode_data(Data) -> </func> <func> - <name name="characters_to_nfkd_binary" arity="1"/> + <name name="characters_to_nfkd_binary" arity="1" since="OTP 20.0"/> <fsummary>Normalize characters to a utf8 binary of compatibly equivalent decomposed Unicode characters.</fsummary> <desc> @@ -515,7 +515,7 @@ decode_data(Data) -> </func> <func> - <name name="encoding_to_bom" arity="1"/> + <name name="encoding_to_bom" arity="1" since=""/> <fsummary>Create a binary UTF byte order mark from encoding.</fsummary> <type_desc variable="Bin"> A <c>binary()</c> such that <c>byte_size(<anno>Bin</anno>) >= 4</c>. diff --git a/lib/stdlib/doc/src/uri_string.xml b/lib/stdlib/doc/src/uri_string.xml index 88d4600611..ad443486c5 100644 --- a/lib/stdlib/doc/src/uri_string.xml +++ b/lib/stdlib/doc/src/uri_string.xml @@ -27,7 +27,7 @@ <date>2018-02-07</date> <rev>A</rev> </header> - <module>uri_string</module> + <module since="OTP 21.0">uri_string</module> <modulesummary>URI processing functions.</modulesummary> <description> <p>This module contains functions for parsing and handling URIs @@ -150,7 +150,7 @@ <funcs> <func> - <name name="compose_query" arity="1"/> + <name name="compose_query" arity="1" since="OTP 21.0"/> <fsummary>Compose urlencoded query string.</fsummary> <desc> <p>Composes a form-urlencoded <c><anno>QueryString</anno></c> based on a @@ -176,7 +176,7 @@ </func> <func> - <name name="compose_query" arity="2"/> + <name name="compose_query" arity="2" since="OTP 21.0"/> <fsummary>Compose urlencoded query string.</fsummary> <desc> <p>Same as <c>compose_query/1</c> but with an additional @@ -210,7 +210,7 @@ </func> <func> - <name name="dissect_query" arity="1"/> + <name name="dissect_query" arity="1" since="OTP 21.0"/> <fsummary>Dissect query string.</fsummary> <desc> <p>Dissects an urlencoded <c><anno>QueryString</anno></c> and returns a @@ -236,7 +236,7 @@ </func> <func> - <name name="normalize" arity="1"/> + <name name="normalize" arity="1" since="OTP 21.0"/> <fsummary>Syntax-based normalization.</fsummary> <desc> <p>Transforms an <c><anno>URI</anno></c> into a normalized form @@ -261,7 +261,7 @@ </func> <func> - <name name="normalize" arity="2"/> + <name name="normalize" arity="2" since="OTP 21.0"/> <fsummary>Syntax-based normalization.</fsummary> <desc> <p>Same as <c>normalize/1</c> but with an additional @@ -285,7 +285,7 @@ </func> <func> - <name name="parse" arity="1"/> + <name name="parse" arity="1" since="OTP 21.0"/> <fsummary>Parse URI into a map.</fsummary> <desc> <p>Parses an <url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url> @@ -309,7 +309,7 @@ </func> <func> - <name name="recompose" arity="1"/> + <name name="recompose" arity="1" since="OTP 21.0"/> <fsummary>Recompose URI.</fsummary> <desc> <p>Creates an <url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url> compliant @@ -332,7 +332,7 @@ </func> <func> - <name name="transcode" arity="2"/> + <name name="transcode" arity="2" since="OTP 21.0"/> <fsummary>Transcode URI.</fsummary> <desc> <p>Transcodes an <url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url> diff --git a/lib/stdlib/doc/src/win32reg.xml b/lib/stdlib/doc/src/win32reg.xml index f4a4fa1626..5e2aed6062 100644 --- a/lib/stdlib/doc/src/win32reg.xml +++ b/lib/stdlib/doc/src/win32reg.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>win32reg.xml</file> </header> - <module>win32reg</module> + <module since="">win32reg</module> <modulesummary>Provides access to the registry on Windows.</modulesummary> <description> <p>This module provides read and write access to the @@ -112,7 +112,7 @@ hkdd HKEY_DYN_DATA</pre> <funcs> <func> - <name name="change_key" arity="2"/> + <name name="change_key" arity="2" since=""/> <fsummary>Move to a key in the registry.</fsummary> <desc> <p>Changes the current key to another key. Works like <c>cd</c>. @@ -122,7 +122,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="change_key_create" arity="2"/> + <name name="change_key_create" arity="2" since=""/> <fsummary>Move to a key, create it if it is not there.</fsummary> <desc> <p>Creates a key, or just changes to it, if it is already there. Works @@ -133,7 +133,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close the registry.</fsummary> <desc> <p>Closes the registry. After that, the <c><anno>RegHandle</anno></c> @@ -142,7 +142,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="current_key" arity="1"/> + <name name="current_key" arity="1" since=""/> <fsummary>Return the path to the current key.</fsummary> <desc> <p>Returns the path to the current key. This is the equivalent of @@ -153,7 +153,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="delete_key" arity="1"/> + <name name="delete_key" arity="1" since=""/> <fsummary>Delete the current key.</fsummary> <desc> <p>Deletes the current key, if it is valid. Calls the Win32 API @@ -166,7 +166,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="delete_value" arity="2"/> + <name name="delete_value" arity="2" since=""/> <fsummary>Delete the named value on the current key.</fsummary> <desc> <p>Deletes a named value on the current key. The atom <c>default</c> is @@ -176,7 +176,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="expand" arity="1"/> + <name name="expand" arity="1" since=""/> <fsummary>Expand a string with environment variables.</fsummary> <desc> <p>Expands a string containing environment variables between percent @@ -189,7 +189,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Convert a POSIX error code to a string.</fsummary> <desc> <p>Converts a POSIX error code to a string @@ -198,7 +198,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="open" arity="1"/> + <name name="open" arity="1" since=""/> <fsummary>Open the registry for reading or writing.</fsummary> <desc> <p>Opens the registry for reading or writing. The current key is the @@ -211,7 +211,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="set_value" arity="3"/> + <name name="set_value" arity="3" since=""/> <fsummary>Set value at the current registry key with specified name. </fsummary> <desc> @@ -230,7 +230,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="sub_keys" arity="1"/> + <name name="sub_keys" arity="1" since=""/> <fsummary>Get subkeys to the current key.</fsummary> <desc> <p>Returns a list of subkeys to the current key. Calls the Win32 @@ -240,7 +240,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="value" arity="2"/> + <name name="value" arity="2" since=""/> <fsummary>Get the named value on the current key.</fsummary> <desc> <p>Retrieves the named value (or default) on the current key. @@ -251,7 +251,7 @@ hkdd HKEY_DYN_DATA</pre> </func> <func> - <name name="values" arity="1"/> + <name name="values" arity="1" since=""/> <fsummary>Get all values on the current key.</fsummary> <desc> <p>Retrieves a list of all values on the current key. The values diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml index 0b5eac1e16..bb2ed7727a 100644 --- a/lib/stdlib/doc/src/zip.xml +++ b/lib/stdlib/doc/src/zip.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>zip.xml</file> </header> - <module>zip</module> + <module since="">zip</module> <modulesummary>Utility for reading and creating 'zip' archives. </modulesummary> <description> @@ -180,7 +180,7 @@ <funcs> <func> - <name name="foldl" arity="3"/> + <name name="foldl" arity="3" since="OTP R14B"/> <fsummary>Fold a function over all files in a zip archive.</fsummary> <desc> <p>Calls <c><anno>Fun</anno>(<anno>FileInArchive</anno>, <anno>GetInfo @@ -234,10 +234,10 @@ </func> <func> - <name name="list_dir" arity="1"/> - <name name="list_dir" arity="2"/> - <name name="table" arity="1" /> - <name name="table" arity="2"/> + <name name="list_dir" arity="1" since=""/> + <name name="list_dir" arity="2" since=""/> + <name name="table" arity="1" since=""/> + <name name="table" arity="2" since=""/> <fsummary>Retrieve the name of all files in a zip archive.</fsummary> <desc> <p><c>list_dir/1</c> retrieves all filenames in the zip archive @@ -263,7 +263,7 @@ </func> <func> - <name name="t" arity="1"/> + <name name="t" arity="1" since=""/> <fsummary>Print the name of each file in a zip archive.</fsummary> <desc> <p>Prints all filenames in the zip archive <c><anno>Archive</anno></c> @@ -272,7 +272,7 @@ </func> <func> - <name name="tt" arity="1"/> + <name name="tt" arity="1" since=""/> <fsummary>Print name and information for each file in a zip archive. </fsummary> <desc> @@ -283,10 +283,10 @@ </func> <func> - <name name="unzip" arity="1"/> - <name name="unzip" arity="2"/> - <name name="extract" arity="1"/> - <name name="extract" arity="2"/> + <name name="unzip" arity="1" since=""/> + <name name="unzip" arity="2" since=""/> + <name name="extract" arity="1" since=""/> + <name name="extract" arity="2" since=""/> <fsummary>Extract files from a zip archive.</fsummary> <desc> <p><c>unzip/1</c> extracts all files from a zip archive.</p> @@ -353,10 +353,10 @@ </func> <func> - <name name="zip" arity="2"/> - <name name="zip" arity="3"/> - <name name="create" arity="2"/> - <name name="create" arity="3"/> + <name name="zip" arity="2" since=""/> + <name name="zip" arity="3" since=""/> + <name name="create" arity="2" since=""/> + <name name="create" arity="3" since=""/> <fsummary>Create a zip archive with options.</fsummary> <desc> <p>Creates a zip archive containing the files specified in @@ -481,7 +481,7 @@ </func> <func> - <name name="zip_close" arity="1"/> + <name name="zip_close" arity="1" since=""/> <fsummary>Close an open archive.</fsummary> <desc> <p>Closes a zip archive, previously opened with @@ -492,8 +492,8 @@ </func> <func> - <name name="zip_get" arity="1"/> - <name name="zip_get" arity="2"/> + <name name="zip_get" arity="1" since=""/> + <name name="zip_get" arity="2" since=""/> <fsummary>Extract files from an open archive.</fsummary> <desc> <p>Extracts one or all files from an open archive.</p> @@ -505,7 +505,7 @@ </func> <func> - <name name="zip_list_dir" arity="1"/> + <name name="zip_list_dir" arity="1" since=""/> <fsummary>Return a table of files in open zip archive.</fsummary> <desc> <p>Returns the file list of an open zip archive. The first returned @@ -514,8 +514,8 @@ </func> <func> - <name name="zip_open" arity="1"/> - <name name="zip_open" arity="2"/> + <name name="zip_open" arity="1" since=""/> + <name name="zip_open" arity="2" since=""/> <fsummary>Open an archive and return a handle to it.</fsummary> <desc> <p>Opens a zip archive, and reads and saves its directory. This diff --git a/lib/stdlib/src/calendar.erl b/lib/stdlib/src/calendar.erl index bb5d450cd6..3a083d9fda 100644 --- a/lib/stdlib/src/calendar.erl +++ b/lib/stdlib/src/calendar.erl @@ -529,24 +529,41 @@ valid_date({Y, M, D}) -> %% day_to_year(DayOfEpoch) = {Year, DayOfYear} %% -%% The idea here is to first guess a year, and then adjust. Although -%% the implementation is recursive, at most 1 or 2 recursive steps +%% The idea here is to first set the upper and lower bounds for a year, +%% and then adjust a range by interpolation search. Although complexity +%% of the algorithm is log(log(n)), at most 1 or 2 recursive steps %% are taken. -%% If DayOfEpoch is very large, we need far more than 1 or 2 iterations, -%% since we just subtract a yearful of days at a time until we're there. %% -spec day_to_year(non_neg_integer()) -> {year(), day_of_year()}. day_to_year(DayOfEpoch) when DayOfEpoch >= 0 -> - Y0 = DayOfEpoch div ?DAYS_PER_YEAR, - {Y1, D1} = dty(Y0, DayOfEpoch, dy(Y0)), + YMax = DayOfEpoch div ?DAYS_PER_YEAR, + YMin = DayOfEpoch div ?DAYS_PER_LEAP_YEAR, + {Y1, D1} = dty(YMin, YMax, DayOfEpoch, dy(YMin), dy(YMax)), {Y1, DayOfEpoch - D1}. --spec dty(year(), non_neg_integer(), non_neg_integer()) -> +-spec dty(year(), year(), non_neg_integer(), non_neg_integer(), + non_neg_integer()) -> {year(), non_neg_integer()}. -dty(Y, D1, D2) when D1 < D2 -> - dty(Y-1, D1, dy(Y-1)); -dty(Y, _D1, D2) -> - {Y, D2}. +dty(Min, Max, _D1, DMin, _DMax) when Min == Max -> + {Min, DMin}; +dty(Min, Max, D1, DMin, DMax) -> + Diff = Max - Min, + Mid = Min + (Diff * (D1 - DMin)) div (DMax - DMin), + MidLength = + case is_leap_year(Mid) of + true -> ?DAYS_PER_LEAP_YEAR; + false -> ?DAYS_PER_YEAR + end, + case dy(Mid) of + D2 when D1 < D2 -> + NewMax = Mid - 1, + dty(Min, NewMax, D1, DMin, dy(NewMax)); + D2 when D1 - D2 >= MidLength -> + NewMin = Mid + 1, + dty(NewMin, Max, D1, dy(NewMin), DMax); + D2 -> + {Mid, D2} + end. %% %% The Gregorian days of the iso week 01 day 1 for a given year. diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 9602f0bcd9..5fa9c4f75c 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -872,7 +872,7 @@ Erlang code. -type af_fun_type() :: {'type', anno(), 'fun', []} | {'type', anno(), 'fun', [{'type', anno(), 'any'} | abstract_type()]} - | {'type', anno(), 'fun', af_function_type()}. + | af_function_type(). -type af_integer_range_type() :: {'type', anno(), 'range', [af_singleton_integer_type()]}. @@ -924,10 +924,11 @@ Erlang code. -type af_function_constraint() :: [af_constraint()]. -type af_constraint() :: {'type', anno(), 'constraint', - af_lit_atom('is_subtype'), - [af_type_variable() | abstract_type()]}. % [V, T] + [af_lit_atom('is_subtype') | + [af_type_variable() | abstract_type()]]}. % [IsSubtype, [V, T]] -type af_singleton_integer_type() :: af_integer() + | af_character() | af_unary_op(af_singleton_integer_type()) | af_binary_op(af_singleton_integer_type()). diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl index 8223a52873..2b5a374cf2 100644 --- a/lib/stdlib/src/io_lib.erl +++ b/lib/stdlib/src/io_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-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. @@ -87,6 +87,8 @@ -export([limit_term/2]). +-export([chars_length/1]). + -export_type([chars/0, latin1_string/0, continuation/0, fread_error/0, fread_item/0, format_spec/0, chars_limit/0]). @@ -1131,3 +1133,17 @@ test_limit_map_assoc(K, V, D) -> test_limit(V, D - 1). test_limit_bitstring(_, _) -> ok. + +-spec chars_length(chars()) -> non_neg_integer(). +%% Optimized for deep lists S such that deep_latin1_char_list(S) is +%% true. No binaries allowed! It is assumed that $\r is never followed +%% by $\n if S is an iolist() (string:length() assigns such a +%% sub-sequence length 1). +chars_length(S) -> + try + %% true = deep_latin1_char_list(S), + iolist_size(S) + catch + _:_ -> + string:length(S) + end. diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl index ab9031573b..d1aa4cd157 100644 --- a/lib/stdlib/src/io_lib_format.erl +++ b/lib/stdlib/src/io_lib_format.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-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. @@ -248,7 +248,7 @@ count_small([#{control_char := $s}|Cs], #{w := W} = Cnts) -> count_small(Cs, Cnts#{w := W + 1}); count_small([S|Cs], #{other := Other} = Cnts) when is_list(S); is_binary(S) -> - count_small(Cs, Cnts#{other := Other + string:length(S)}); + count_small(Cs, Cnts#{other := Other + io_lib:chars_length(S)}); count_small([C|Cs], #{other := Other} = Cnts) when is_integer(C) -> count_small(Cs, Cnts#{other := Other + 1}); count_small([], #{p := P, s := S, w := W, other := Other}) -> @@ -280,10 +280,15 @@ build_limited([#{control_char := C, args := As, width := F, adjust := Ad, true -> MaxLen0 div Count0 end, S = control_limited(C, As, F, Ad, P, Pad, Enc, Str, MaxChars, I), - Len = string:length(S), NumOfPs = decr_pc(C, NumOfPs0), Count = Count0 - 1, - MaxLen = sub(MaxLen0, Len), + MaxLen = if + MaxLen0 < 0 -> % optimization + MaxLen0; + true -> + Len = io_lib:chars_length(S), + sub(MaxLen0, Len) + end, if NumOfPs > 0 -> [S|build_limited(Cs, NumOfPs, Count, MaxLen, indentation(S, I))]; @@ -406,7 +411,7 @@ base(B) when is_integer(B) -> term(T, none, _Adj, none, _Pad) -> T; term(T, none, Adj, P, Pad) -> term(T, P, Adj, P, Pad); term(T, F, Adj, P0, Pad) -> - L = string:length(T), + L = io_lib:chars_length(T), P = erlang:min(L, case P0 of none -> F; _ -> min(P0, F) end), if L > P -> @@ -713,7 +718,7 @@ fwrite_g(Fl, F, Adj, P, Pad) when P >= 1 -> end. -%% iolist_to_chars(iolist()) -> deep_char_list() +%% iolist_to_chars(iolist()) -> io_lib:chars() iolist_to_chars([C|Cs]) when is_integer(C), C >= $\000, C =< $\377 -> [C | iolist_to_chars(Cs)]; @@ -729,7 +734,7 @@ iolist_to_chars(B) when is_binary(B) -> %% cbinary() | nil()) %% cbinary() :: unicode:unicode_binary() | unicode:latin1_binary() -%% cdata_to_chars(cdata()) -> io_lib:deep_char_list() +%% cdata_to_chars(cdata()) -> io_lib:chars() cdata_to_chars([C|Cs]) when is_integer(C), C >= $\000 -> [C | cdata_to_chars(Cs)]; @@ -745,7 +750,7 @@ cdata_to_chars(B) when is_binary(B) -> limit_string(S, F, CharsLimit) when CharsLimit < 0; CharsLimit >= F -> S; limit_string(S, _F, CharsLimit) -> - case string:length(S) =< CharsLimit of + case io_lib:chars_length(S) =< CharsLimit of true -> S; false -> [string:slice(S, 0, sub(CharsLimit, 3)), "..."] end. @@ -759,11 +764,11 @@ limit_field(F, CharsLimit) -> string(S, none, _Adj, none, _Pad) -> S; string(S, F, Adj, none, Pad) -> - string_field(S, F, Adj, string:length(S), Pad); + string_field(S, F, Adj, io_lib:chars_length(S), Pad); string(S, none, _Adj, P, Pad) -> - string_field(S, P, left, string:length(S), Pad); + string_field(S, P, left, io_lib:chars_length(S), Pad); string(S, F, Adj, P, Pad) when F >= P -> - N = string:length(S), + N = io_lib:chars_length(S), if F > P -> if N > P -> adjust(flat_trunc(S, P), chars(Pad, F-P), Adj); diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl index ba9d9e8434..5483ea87b5 100644 --- a/lib/stdlib/src/io_lib_pretty.erl +++ b/lib/stdlib/src/io_lib_pretty.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-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. @@ -507,20 +507,20 @@ print_length(#{}=M, _D, _T, _RF, _Enc, _Str) when map_size(M) =:= 0 -> {"#{}", 3, 0, no_more}; print_length(Atom, _D, _T, _RF, Enc, _Str) when is_atom(Atom) -> S = write_atom(Atom, Enc), - {S, string:length(S), 0, no_more}; + {S, io_lib:chars_length(S), 0, no_more}; print_length(List, D, T, RF, Enc, Str) when is_list(List) -> %% only flat lists are "printable" case Str andalso printable_list(List, D, T, Enc) of true -> %% print as string, escaping double-quotes in the list S = write_string(List, Enc), - {S, string:length(S), 0, no_more}; + {S, io_lib:chars_length(S), 0, no_more}; {true, Prefix} -> %% Truncated lists when T < 0 could break some existing code. S = write_string(Prefix, Enc), %% NumOfDots = 0 to avoid looping--increasing the depth %% does not make Prefix longer. - {[S | "..."], 3 + string:length(S), 0, no_more}; + {[S | "..."], 3 + io_lib:chars_length(S), 0, no_more}; false -> case print_length_list(List, D, T, RF, Enc, Str) of {What, Len, Dots, _More} when Dots > 0 -> @@ -564,7 +564,7 @@ print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) -> {[$<,$<,S,$>,$>], 4 + length(S), 0, no_more}; {false, List} when is_list(List) -> S = io_lib:write_string(List, $"), %" - {[$<,$<,S,"/utf8>>"], 9 + string:length(S), 0, no_more}; + {[$<,$<,S,"/utf8>>"], 9 + io_lib:chars_length(S), 0, no_more}; {true, true, Prefix} -> S = io_lib:write_string(Prefix, $"), %" More = fun(T1, Dd) -> @@ -576,7 +576,7 @@ print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) -> More = fun(T1, Dd) -> ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str) end, - {[$<,$<,S|"/utf8...>>"], 12 + string:length(S), 3, More}; + {[$<,$<,S|"/utf8...>>"], 12 + io_lib:chars_length(S), 3, More}; false -> case io_lib:write_binary(Bin, D, T) of {S, <<>>} -> @@ -591,7 +591,7 @@ print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) -> print_length(Term, _D, _T, _RF, _Enc, _Str) -> S = io_lib:write(Term), %% S can contain unicode, so iolist_size(S) cannot be used here - {S, string:length(S), 0, no_more}. + {S, io_lib:chars_length(S), 0, no_more}. print_length_map(Map, 1, _T, RF, Enc, Str) -> More = fun(T1, Dd) -> ?FUNCTION_NAME(Map, 1+Dd, T1, RF, Enc, Str) end, @@ -651,7 +651,7 @@ print_length_record(Tuple, 1, _T, RF, RDefs, Enc, Str) -> {"{...}", 5, 3, More}; print_length_record(Tuple, D, T, RF, RDefs, Enc, Str) -> Name = [$# | write_atom(element(1, Tuple), Enc)], - NameL = string:length(Name), + NameL = io_lib:chars_length(Name), T1 = tsub(T, NameL+2), L = print_length_fields(RDefs, D - 1, T1, Tuple, 2, RF, Enc, Str), {Len, Dots} = list_length(L, NameL + 2, 0), @@ -677,7 +677,7 @@ print_length_fields([Def | Defs], D, T, Tuple, I, RF, Enc, Str) -> print_length_field(Def, D, T, E, RF, Enc, Str) -> Name = write_atom(Def, Enc), - NameL = string:length(Name) + 3, + NameL = io_lib:chars_length(Name) + 3, {_, Len, Dots, _} = Field = print_length(E, D, tsub(T, NameL), RF, Enc, Str), {{field, Name, NameL, Field}, NameL + Len, Dots, no_more}. @@ -738,7 +738,7 @@ printable_list(L, _D, T, _Uni) when T < 0-> io_lib:printable_list(L). slice(L, N) -> - try string:length(L) =< N of + try io_lib:chars_length(L) =< N of true -> all; false -> diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl index 6d243e1bec..97ec785c62 100644 --- a/lib/stdlib/src/ms_transform.erl +++ b/lib/stdlib/src/ms_transform.erl @@ -556,8 +556,8 @@ tg({call, Line, {remote,_,{atom,_,erlang},{atom, Line2, FunName}},ParaList}, FunName,length(ParaList)}}) end; tg({call, Line, {remote,_,{atom,_,ModuleName}, - {atom, _, FunName}},_ParaList},B) -> - throw({error,Line,{?ERR_GENREMOTECALL+B#tgd.eb,ModuleName,FunName}}); + {atom, _, FunName}},ParaList},B) -> + throw({error,Line,{?ERR_GENREMOTECALL+B#tgd.eb,ModuleName,FunName,length(ParaList)}}); tg({cons,Line, H, T},B) -> {cons, Line, tg(H,B), tg(T,B)}; tg({nil, Line},_B) -> diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl index c5cfea5e9e..e0811f19cf 100644 --- a/lib/stdlib/test/binary_module_SUITE.erl +++ b/lib/stdlib/test/binary_module_SUITE.erl @@ -22,7 +22,8 @@ -export([all/0, suite/0, interesting/1,scope_return/1,random_ref_comp/1,random_ref_sr_comp/1, random_ref_fla_comp/1,parts/1, bin_to_list/1, list_to_bin/1, - copy/1, referenced/1,guard/1,encode_decode/1,badargs/1,longest_common_trap/1]). + copy/1, referenced/1,guard/1,encode_decode/1,badargs/1,longest_common_trap/1, + check_no_invalid_read_bug/1]). -export([random_number/1, make_unaligned/1]). @@ -36,7 +37,7 @@ all() -> [scope_return,interesting, random_ref_fla_comp, random_ref_sr_comp, random_ref_comp, parts, bin_to_list, list_to_bin, copy, referenced, guard, encode_decode, badargs, - longest_common_trap]. + longest_common_trap, check_no_invalid_read_bug]. -define(MASK_ERROR(EXPR),mask_error((catch (EXPR)))). @@ -1361,3 +1362,13 @@ make_unaligned2(Bin0) when is_binary(Bin0) -> Bin. id(I) -> I. + +check_no_invalid_read_bug(Config) when is_list(Config) -> + check_no_invalid_read_bug(24); +check_no_invalid_read_bug(60) -> + ok; +check_no_invalid_read_bug(I) -> + N = 1 bsl I, + binary:encode_unsigned(N+N), + binary:encode_unsigned(N+N, little), + check_no_invalid_read_bug(I+1). diff --git a/lib/stdlib/test/calendar_SUITE.erl b/lib/stdlib/test/calendar_SUITE.erl index df62c0921d..c6d9dbca4a 100644 --- a/lib/stdlib/test/calendar_SUITE.erl +++ b/lib/stdlib/test/calendar_SUITE.erl @@ -24,6 +24,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, gregorian_days/1, + big_gregorian_days/1, gregorian_seconds/1, day_of_the_week/1, day_of_the_week_calibrate/1, @@ -36,13 +37,16 @@ -define(START_YEAR, 1947). -define(END_YEAR, 2012). +-define(BIG_START_YEAR, 20000000). +-define(BIG_END_YEAR, 20000020). + suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [gregorian_days, gregorian_seconds, day_of_the_week, day_of_the_week_calibrate, leap_years, last_day_of_the_month, local_time_to_universal_time_dst, - iso_week_number, system_time, rfc3339]. + iso_week_number, system_time, rfc3339, big_gregorian_days]. groups() -> []. @@ -67,6 +71,14 @@ gregorian_days(Config) when is_list(Config) -> MaxDays = calendar:date_to_gregorian_days({?END_YEAR, 1, 1}), check_gregorian_days(Days, MaxDays). +%% Tests that date_to_gregorian_days and gregorian_days_to_date +%% are each others inverses from ?BIG_START_YEAR-01-01 up to ?BIG_END_YEAR-01-01. +%% At the same time valid_date is tested. +big_gregorian_days(Config) when is_list(Config) -> + Days = calendar:date_to_gregorian_days({?BIG_START_YEAR, 1, 1}), + MaxDays = calendar:date_to_gregorian_days({?BIG_END_YEAR, 1, 1}), + check_gregorian_days(Days, MaxDays). + %% Tests that datetime_to_gregorian_seconds and %% gregorian_seconds_to_date are each others inverses for a sampled %% number of seconds from ?START_YEAR-01-01 up to ?END_YEAR-01-01: We check diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl index 6906ef1553..6ad9bec2e6 100644 --- a/lib/syntax_tools/src/erl_prettypr.erl +++ b/lib/syntax_tools/src/erl_prettypr.erl @@ -1101,8 +1101,9 @@ lay_2(Node, Ctxt) -> Ctxt1 = reset_prec(Ctxt), D1 = lay(erl_syntax:constrained_function_type_body(Node), Ctxt1), + Ctxt2 = Ctxt1#ctxt{clause = undefined}, D2 = lay(erl_syntax:constrained_function_type_argument(Node), - Ctxt1), + Ctxt2), beside(D1, beside(floating(text(" when ")), D2)); @@ -1113,7 +1114,7 @@ lay_2(Node, Ctxt) -> _ -> {"fun(", ")"} end, - Ctxt1 = reset_prec(Ctxt), + Ctxt1 = (reset_prec(Ctxt))#ctxt{clause = undefined}, D1 = case erl_syntax:function_type_arguments(Node) of any_arity -> text("(...)"); diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl index 9dbd0e302a..6b42f7a0a1 100644 --- a/lib/syntax_tools/test/syntax_tools_SUITE.erl +++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl @@ -26,14 +26,14 @@ -export([app_test/1,appup_test/1,smoke_test/1,revert/1,revert_map/1, revert_map_type/1, t_abstract_type/1,t_erl_parse_type/1,t_type/1, t_epp_dodger/1, - t_comment_scan/1,t_igor/1,t_erl_tidy/1]). + t_comment_scan/1,t_igor/1,t_erl_tidy/1,t_prettypr/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [app_test,appup_test,smoke_test,revert,revert_map,revert_map_type, t_abstract_type,t_erl_parse_type,t_type,t_epp_dodger, - t_comment_scan,t_igor,t_erl_tidy]. + t_comment_scan,t_igor,t_erl_tidy,t_prettypr]. groups() -> []. @@ -300,6 +300,14 @@ t_comment_scan(Config) when is_list(Config) -> ok = test_comment_scan(Filenames,DataDir), ok. +t_prettypr(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + Filenames = ["type_specs.erl", + "specs_and_funs.erl"], + ok = test_prettypr(Filenames,DataDir,PrivDir), + ok. + test_files(Config) -> DataDir = ?config(data_dir, Config), [ filename:join(DataDir,Filename) || Filename <- test_files() ]. @@ -307,7 +315,8 @@ test_files(Config) -> test_files() -> ["syntax_tools_SUITE_test_module.erl", "syntax_tools_test.erl", - "type_specs.erl"]. + "type_specs.erl", + "specs_and_funs.erl"]. t_igor(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), @@ -359,6 +368,27 @@ test_comment_scan([File|Files],DataDir) -> test_comment_scan(Files,DataDir). +test_prettypr([],_,_) -> ok; +test_prettypr([File|Files],DataDir,PrivDir) -> + Filename = filename:join(DataDir,File), + io:format("Parsing ~p~n", [Filename]), + {ok, Fs0} = epp:parse_file(Filename, [], []), + Fs = erl_syntax:form_list(Fs0), + PP = erl_prettypr:format(Fs, [{paper, 120}, {ribbon, 110}]), + io:put_chars(PP), + OutFile = filename:join(PrivDir, File), + ok = file:write_file(OutFile,iolist_to_binary(PP)), + io:format("Parsing OutFile: ~s~n", [OutFile]), + {ok, Fs2} = epp:parse_file(OutFile, [], []), + case [Error || {error, _} = Error <- Fs2] of + [] -> + ok; + Errors -> + ?t:fail(Errors) + end, + test_prettypr(Files,DataDir,PrivDir). + + test_epp_dodger([], _, _) -> ok; test_epp_dodger([Filename|Files],DataDir,PrivDir) -> io:format("Parsing ~p~n", [Filename]), diff --git a/lib/syntax_tools/test/syntax_tools_SUITE_data/specs_and_funs.erl b/lib/syntax_tools/test/syntax_tools_SUITE_data/specs_and_funs.erl new file mode 100644 index 0000000000..8dfeaf5a6b --- /dev/null +++ b/lib/syntax_tools/test/syntax_tools_SUITE_data/specs_and_funs.erl @@ -0,0 +1,18 @@ +-module(specs_and_funs). + +-export([my_apply/3, two/1]). + +%% OTP-15519, ERL-815 + +-spec my_apply(Fun, Arg, fun((A) -> A)) -> Result when + Fun :: fun((Arg) -> Result), + Arg :: any(), + Result :: any(). + +my_apply(Fun, Arg, _) -> + Fun(Arg). + +-spec two(fun((A) -> A)) -> fun((B) -> B). + +two(F) -> + F(fun(X) -> X end). diff --git a/lib/tftp/doc/src/tftp.xml b/lib/tftp/doc/src/tftp.xml index 4ed54bc462..57d64b7379 100644 --- a/lib/tftp/doc/src/tftp.xml +++ b/lib/tftp/doc/src/tftp.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>tftp</module> + <module since="">tftp</module> <modulesummary>Trivial FTP.</modulesummary> <description> <p>Interface module for the <c>tftp</c> application.</p> @@ -172,7 +172,7 @@ <funcs> <func> - <name>change_config(daemons, Options) -> [{Pid, Result}]</name> + <name since="">change_config(daemons, Options) -> [{Pid, Result}]</name> <fsummary>Changes configuration for all daemons. </fsummary> <type> @@ -187,7 +187,7 @@ </func> <func> - <name>change_config(servers, Options) -> [{Pid, Result}]</name> + <name since="">change_config(servers, Options) -> [{Pid, Result}]</name> <fsummary>Changes configuration for all servers. </fsummary> <type> @@ -202,7 +202,7 @@ </func> <func> - <name>change_config(Pid, Options) -> Result</name> + <name since="">change_config(Pid, Options) -> Result</name> <fsummary>Changes configuration for a TFTP daemon, server, or client process.</fsummary> <type> @@ -217,7 +217,7 @@ </func> <func> - <name>info(daemons) -> [{Pid, Options}]</name> + <name since="">info(daemons) -> [{Pid, Options}]</name> <fsummary>Returns information about all daemons.</fsummary> <type> <v>Pid = [pid()]</v> @@ -230,7 +230,7 @@ </func> <func> - <name>info(servers) -> [{Pid, Options}]</name> + <name since="">info(servers) -> [{Pid, Options}]</name> <fsummary>Returns information about all servers.</fsummary> <type> <v>Pid = [pid()]</v> @@ -243,7 +243,7 @@ </func> <func> - <name>info(Pid) -> {ok, Options} | {error, Reason}</name> + <name since="">info(Pid) -> {ok, Options} | {error, Reason}</name> <fsummary>Returns information about a daemon, server, or client process.</fsummary> <type> <v>Options = [option()]</v> @@ -255,7 +255,7 @@ </func> <func> - <name>read_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> + <name since="">read_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> <fsummary>Reads a (virtual) file from a TFTP server.</fsummary> <type> <v>RemoteFilename = string()</v> @@ -285,7 +285,7 @@ </func> <func> - <name>start(Options) -> {ok, Pid} | {error, Reason}</name> + <name since="">start(Options) -> {ok, Pid} | {error, Reason}</name> <fsummary>Starts a daemon process.</fsummary> <type> <v>Options = [option()]</v> @@ -301,7 +301,7 @@ </func> <func> - <name>write_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> + <name since="">write_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> <fsummary>Writes a (virtual) file to a TFTP server.</fsummary> <type> <v>RemoteFilename = string()</v> @@ -389,7 +389,7 @@ <funcs> <func> - <name>Module:abort(Code, Text, State) -> ok</name> + <name since="OTP 18.1">Module:abort(Code, Text, State) -> ok</name> <fsummary>Aborts the file transfer.</fsummary> <type> <v>Code = undef | enoent | eacces | enospc</v> @@ -413,7 +413,7 @@ </func> <func> - <name>Module:open(Peer, Access, Filename, Mode, SuggestedOptions, State) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name> + <name since="OTP 18.1">Module:open(Peer, Access, Filename, Mode, SuggestedOptions, State) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name> <fsummary>Opens a file for read or write access.</fsummary> <type> <v>Peer = {PeerType, PeerHost, PeerPort}</v> @@ -448,7 +448,7 @@ </func> <func> - <name>Module:prepare(Peer, Access, Filename, Mode, SuggestedOptions, InitialState) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name> + <name since="OTP 18.1">Module:prepare(Peer, Access, Filename, Mode, SuggestedOptions, InitialState) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name> <fsummary>Prepares to open a file on the client side.</fsummary> <type> <v>Peer = {PeerType, PeerHost, PeerPort}</v> @@ -483,7 +483,7 @@ </func> <func> - <name>Module:read(State) -> {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}}</name> + <name since="OTP 18.1">Module:read(State) -> {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}}</name> <fsummary>Reads a chunk from the file.</fsummary> <type> <v>State = NewState = term()</v> @@ -510,7 +510,7 @@ </func> <func> - <name>Module:write(Bin, State) -> {more, NewState} | {last, FileSize} | {error, {Code, Text}}</name> + <name since="OTP 18.1">Module:write(Bin, State) -> {more, NewState} | {last, FileSize} | {error, {Code, Text}}</name> <fsummary>Writes a chunk to the file.</fsummary> <type> <v>Bin = binary()</v> @@ -549,7 +549,7 @@ <funcs> <func> - <name>Logger:error_msg(Format, Data) -> ok | exit(Reason)</name> + <name since="OTP 18.1">Logger:error_msg(Format, Data) -> ok | exit(Reason)</name> <fsummary>Logs an error message.</fsummary> <type> <v>Format = string()</v> @@ -565,7 +565,7 @@ </func> <func> - <name>Logger:info_msg(Format, Data) -> ok | exit(Reason)</name> + <name since="OTP 18.1">Logger:info_msg(Format, Data) -> ok | exit(Reason)</name> <fsummary>Logs an info message.</fsummary> <type> <v>Format = string()</v> @@ -579,7 +579,7 @@ </func> <func> - <name>Logger:warning_msg(Format, Data) -> ok | exit(Reason)</name> + <name since="OTP 18.1">Logger:warning_msg(Format, Data) -> ok | exit(Reason)</name> <fsummary>Logs a warning message.</fsummary> <type> <v>Format = string()</v> diff --git a/lib/tools/doc/src/cover.xml b/lib/tools/doc/src/cover.xml index 15cd784253..64c24cea2a 100644 --- a/lib/tools/doc/src/cover.xml +++ b/lib/tools/doc/src/cover.xml @@ -30,7 +30,7 @@ <date></date> <rev></rev> </header> - <module>cover</module> + <module since="">cover</module> <modulesummary>A Coverage Analysis Tool for Erlang</modulesummary> <description> <p>The module <c>cover</c> provides a set of functions for coverage @@ -115,7 +115,7 @@ </description> <funcs> <func> - <name>start() -> {ok,Pid} | {error,Reason}</name> + <name since="">start() -> {ok,Pid} | {error,Reason}</name> <fsummary>Start Cover.</fsummary> <type> <v>Pid = pid()</v> @@ -128,7 +128,7 @@ </desc> </func> <func> - <name>start(Nodes) -> {ok,StartedNodes} | {error,not_main_node}</name> + <name since="">start(Nodes) -> {ok,StartedNodes} | {error,not_main_node}</name> <fsummary>Start Cover on remote nodes.</fsummary> <type> <v>Nodes = StartedNodes = [atom()]</v> @@ -139,10 +139,10 @@ </desc> </func> <func> - <name>compile(ModFiles) -> Result | [Result]</name> - <name>compile(ModFiles, Options) -> Result | [Result]</name> - <name>compile_module(ModFiles) -> Result | [Result]</name> - <name>compile_module(ModFiles, Options) -> Result | [Result]</name> + <name since="">compile(ModFiles) -> Result | [Result]</name> + <name since="">compile(ModFiles, Options) -> Result | [Result]</name> + <name since="">compile_module(ModFiles) -> Result | [Result]</name> + <name since="">compile_module(ModFiles, Options) -> Result | [Result]</name> <fsummary>Compile one or more modules for Cover analysis.</fsummary> <type> <v>ModFiles = ModFile | [ModFile]</v> @@ -176,9 +176,9 @@ </desc> </func> <func> - <name>compile_directory() -> [Result] | {error,Reason}</name> - <name>compile_directory(Dir) -> [Result] | {error,Reason}</name> - <name>compile_directory(Dir, Options) -> [Result] | {error,Reason}</name> + <name since="">compile_directory() -> [Result] | {error,Reason}</name> + <name since="">compile_directory(Dir) -> [Result] | {error,Reason}</name> + <name since="">compile_directory(Dir, Options) -> [Result] | {error,Reason}</name> <fsummary>Compile all modules in a directory for Cover analysis.</fsummary> <type> <v>Dir = string()</v> @@ -199,7 +199,7 @@ </desc> </func> <func> - <name>compile_beam(ModFiles) -> Result | [Result]</name> + <name since="">compile_beam(ModFiles) -> Result | [Result]</name> <fsummary>Compile one or more modules for Cover analysis, using existing beam(s).</fsummary> <type> <v>ModFiles = ModFile | [ModFile]</v> @@ -241,8 +241,8 @@ </desc> </func> <func> - <name>compile_beam_directory() -> [Result] | {error,Reason}</name> - <name>compile_beam_directory(Dir) -> [Result] | {error,Reason}</name> + <name since="">compile_beam_directory() -> [Result] | {error,Reason}</name> + <name since="">compile_beam_directory(Dir) -> [Result] | {error,Reason}</name> <fsummary>Compile all .beam files in a directory for Cover analysis.</fsummary> <type> <v>Dir = string()</v> @@ -260,14 +260,14 @@ </desc> </func> <func> - <name>analyse() -> {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse(Modules) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse(Analysis) -> {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse(Level) -> {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse(Modules, Analysis) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse(Modules, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse(Analysis, Level) -> {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse(Modules, Analysis, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> + <name since="OTP 18.0">analyse() -> {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse(Modules) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse(Analysis) -> {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse(Level) -> {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse(Modules, Analysis) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse(Modules, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse(Analysis, Level) -> {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse(Modules, Analysis, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> <fsummary>Analyse one or more Cover compiled modules.</fsummary> <type> <v>Modules = Module | [Module]</v> @@ -305,10 +305,10 @@ </desc> </func> <func> - <name>analyse_to_file() -> {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse_to_file(Modules) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse_to_file(Options) -> {result,Ok,Fail} | {error,not_main_node}</name> - <name>analyse_to_file(Modules,Options) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name> + <name since="OTP 18.0">analyse_to_file() -> {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse_to_file(Modules) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse_to_file(Options) -> {result,Ok,Fail} | {error,not_main_node}</name> + <name since="">analyse_to_file(Modules,Options) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name> <fsummary>Detailed coverage analysis of one or more Cover compiled modules.</fsummary> <type> <v>Modules = Module | [Module]</v> @@ -359,10 +359,10 @@ </desc> </func> <func> - <name>async_analyse_to_file(Module) -> </name> - <name>async_analyse_to_file(Module,Options) -> </name> - <name>async_analyse_to_file(Module, OutFile) -> </name> - <name>async_analyse_to_file(Module, OutFile, Options) -> pid()</name> + <name since="OTP R14B02">async_analyse_to_file(Module) -> </name> + <name since="OTP R14B02">async_analyse_to_file(Module,Options) -> </name> + <name since="OTP R14B02">async_analyse_to_file(Module, OutFile) -> </name> + <name since="OTP R14B02">async_analyse_to_file(Module, OutFile, Options) -> pid()</name> <fsummary>Asynchronous call to analyse_to_file.</fsummary> <type> <v>Module = atom()</v> @@ -384,7 +384,7 @@ </desc> </func> <func> - <name>modules() -> [Module] | {error,not_main_node}</name> + <name since="">modules() -> [Module] | {error,not_main_node}</name> <fsummary>Return all Cover compiled modules.</fsummary> <type> <v>Module = atom()</v> @@ -395,7 +395,7 @@ </desc> </func> <func> - <name>imported_modules() -> [Module] | {error,not_main_node}</name> + <name since="">imported_modules() -> [Module] | {error,not_main_node}</name> <fsummary>Return all modules for which there are imported data.</fsummary> <type> <v>Module = atom()</v> @@ -406,7 +406,7 @@ </desc> </func> <func> - <name>imported() -> [File] | {error,not_main_node}</name> + <name since="">imported() -> [File] | {error,not_main_node}</name> <fsummary>Return all imported files.</fsummary> <type> <v>File = string()</v> @@ -416,7 +416,7 @@ </desc> </func> <func> - <name>which_nodes() -> [Node] | {error,not_main_node}</name> + <name since="">which_nodes() -> [Node] | {error,not_main_node}</name> <fsummary>Return all nodes that are part of the coverage analysis.</fsummary> <type> <v>Node = atom()</v> @@ -428,7 +428,7 @@ </desc> </func> <func> - <name>is_compiled(Module) -> {file,File} | false | {error,not_main_node}</name> + <name since="">is_compiled(Module) -> {file,File} | false | {error,not_main_node}</name> <fsummary>Check if a module is Cover compiled.</fsummary> <type> <v>Module = atom()</v> @@ -442,8 +442,8 @@ </desc> </func> <func> - <name>reset(Module) -></name> - <name>reset() -> ok | {error,not_main_node}</name> + <name since="">reset(Module) -></name> + <name since="">reset() -> ok | {error,not_main_node}</name> <fsummary>Reset coverage data for Cover compiled modules.</fsummary> <type> <v>Module = atom()</v> @@ -458,8 +458,8 @@ </desc> </func> <func> - <name>export(ExportFile)</name> - <name>export(ExportFile,Module) -> ok | {error,Reason}</name> + <name since="">export(ExportFile)</name> + <name since="">export(ExportFile,Module) -> ok | {error,Reason}</name> <fsummary>Reset coverage data for Cover compiled modules.</fsummary> <type> <v>ExportFile = string()</v> @@ -480,7 +480,7 @@ </desc> </func> <func> - <name>import(ExportFile) -> ok | {error,Reason}</name> + <name since="">import(ExportFile) -> ok | {error,Reason}</name> <fsummary>Reset coverage data for Cover compiled modules.</fsummary> <type> <v>ExportFile = string()</v> @@ -504,14 +504,14 @@ </desc> </func> <func> - <name>stop() -> ok | {error,not_main_node}</name> + <name since="">stop() -> ok | {error,not_main_node}</name> <fsummary>Stop Cover.</fsummary> <desc> <p>Stops the Cover server and unloads all Cover compiled code.</p> </desc> </func> <func> - <name>stop(Nodes) -> ok | {error,not_main_node}</name> + <name since="">stop(Nodes) -> ok | {error,not_main_node}</name> <fsummary>Stop Cover on remote nodes.</fsummary> <type> <v>Nodes = [atom()]</v> @@ -523,7 +523,7 @@ </desc> </func> <func> - <name>flush(Nodes) -> ok | {error,not_main_node}</name> + <name since="OTP R16B">flush(Nodes) -> ok | {error,not_main_node}</name> <fsummary>Collect cover data from remote nodes.</fsummary> <type> <v>Nodes = [atom()]</v> diff --git a/lib/tools/doc/src/cprof.xml b/lib/tools/doc/src/cprof.xml index df0acbe617..b6af8b6d28 100644 --- a/lib/tools/doc/src/cprof.xml +++ b/lib/tools/doc/src/cprof.xml @@ -34,7 +34,7 @@ <rev>PA1</rev> <file>cprof.sgml</file> </header> - <module>cprof</module> + <module since="">cprof</module> <modulesummary>A simple Call Count Profiling Tool using breakpoints for minimal runtime performance impact.</modulesummary> <description> <p>The <c>cprof</c> module is used to profile a program @@ -65,10 +65,10 @@ </description> <funcs> <func> - <name>analyse() -> {AllCallCount, ModAnalysisList}</name> - <name>analyse(Limit) -> {AllCallCount, ModAnalysisList}</name> - <name>analyse(Mod) -> ModAnalysis</name> - <name>analyse(Mod, Limit) -> ModAnalysis</name> + <name since="">analyse() -> {AllCallCount, ModAnalysisList}</name> + <name since="">analyse(Limit) -> {AllCallCount, ModAnalysisList}</name> + <name since="">analyse(Mod) -> ModAnalysis</name> + <name since="">analyse(Mod, Limit) -> ModAnalysis</name> <fsummary>Collect and analyse call counters.</fsummary> <type> <v>Limit = integer()</v> @@ -122,7 +122,7 @@ </desc> </func> <func> - <name>pause() -> integer()</name> + <name since="">pause() -> integer()</name> <fsummary>Pause running call count trace for all functions.</fsummary> <desc> <p>Pause call count tracing for all functions in all modules @@ -137,9 +137,9 @@ </desc> </func> <func> - <name>pause(FuncSpec) -> integer()</name> - <name>pause(Mod, Func) -> integer()</name> - <name>pause(Mod, Func, Arity) -> integer()</name> + <name since="">pause(FuncSpec) -> integer()</name> + <name since="">pause(Mod, Func) -> integer()</name> + <name since="">pause(Mod, Func, Arity) -> integer()</name> <fsummary>Pause running call count trace for matching functions.</fsummary> <type> <v>FuncSpec = Mod | {Mod,Func,Arity}, {FS}</v> @@ -167,10 +167,10 @@ </desc> </func> <func> - <name>restart() -> integer()</name> - <name>restart(FuncSpec) -> integer()</name> - <name>restart(Mod, Func) -> integer()</name> - <name>restart(Mod, Func, Arity) -> integer()</name> + <name since="">restart() -> integer()</name> + <name since="">restart(FuncSpec) -> integer()</name> + <name since="">restart(Mod, Func) -> integer()</name> + <name since="">restart(Mod, Func, Arity) -> integer()</name> <fsummary>Restart existing call counters for matching functions.</fsummary> <type> <v>FuncSpec = Mod | {Mod,Func,Arity}, {FS}</v> @@ -197,7 +197,7 @@ </desc> </func> <func> - <name>start() -> integer()</name> + <name since="">start() -> integer()</name> <fsummary>Start call count tracing for all functions.</fsummary> <desc> <p>Start call count tracing for all functions in all modules, @@ -212,9 +212,9 @@ </desc> </func> <func> - <name>start(FuncSpec) -> integer()</name> - <name>start(Mod, Func) -> integer()</name> - <name>start(Mod, Func, Arity) -> integer()</name> + <name since="">start(FuncSpec) -> integer()</name> + <name since="">start(Mod, Func) -> integer()</name> + <name since="">start(Mod, Func, Arity) -> integer()</name> <fsummary>Start call count tracing for matching functions.</fsummary> <type> <v>FuncSpec = Mod | {Mod,Func,Arity}, {FS}</v> @@ -240,7 +240,7 @@ </desc> </func> <func> - <name>stop() -> integer()</name> + <name since="">stop() -> integer()</name> <fsummary>Stop call count tracing for all functions.</fsummary> <desc> <p>Stop call count tracing for all functions in all modules, @@ -255,9 +255,9 @@ </desc> </func> <func> - <name>stop(FuncSpec) -> integer()</name> - <name>stop(Mod, Func) -> integer()</name> - <name>stop(Mod, Func, Arity) -> integer()</name> + <name since="">stop(FuncSpec) -> integer()</name> + <name since="">stop(Mod, Func) -> integer()</name> + <name since="">stop(Mod, Func, Arity) -> integer()</name> <fsummary>Stop call count tracing for matching functions.</fsummary> <type> <v>FuncSpec = Mod | {Mod,Func,Arity}, {FS}</v> diff --git a/lib/tools/doc/src/eprof.xml b/lib/tools/doc/src/eprof.xml index f098b7d39e..c9e4edd991 100644 --- a/lib/tools/doc/src/eprof.xml +++ b/lib/tools/doc/src/eprof.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>eprof</module> + <module since="">eprof</module> <modulesummary>A Time Profiling Tool for Erlang</modulesummary> <description> <p>The module <c>eprof</c> provides a set of functions for time @@ -40,7 +40,7 @@ </description> <funcs> <func> - <name>start() -> {ok,Pid} | {error,Reason}</name> + <name since="">start() -> {ok,Pid} | {error,Reason}</name> <fsummary>Start Eprof.</fsummary> <type> <v>Pid = pid()</v> @@ -51,9 +51,9 @@ </desc> </func> <func> - <name>start_profiling(Rootset) -> profiling | {error, Reason}</name> - <name>start_profiling(Rootset,Pattern) -> profiling | {error, Reason}</name> - <name>start_profiling(Rootset,Pattern,Options) -> profiling | {error, Reason}</name> + <name since="">start_profiling(Rootset) -> profiling | {error, Reason}</name> + <name since="OTP R14B">start_profiling(Rootset,Pattern) -> profiling | {error, Reason}</name> + <name since="OTP R16B01">start_profiling(Rootset,Pattern,Options) -> profiling | {error, Reason}</name> <fsummary>Start profiling.</fsummary> <type> <v>Rootset = [atom() | pid()]</v> @@ -79,7 +79,7 @@ </desc> </func> <func> - <name>stop_profiling() -> profiling_stopped | profiling_already_stopped</name> + <name since="">stop_profiling() -> profiling_stopped | profiling_already_stopped</name> <fsummary>Stop profiling.</fsummary> <desc> <p>Stops profiling started with <c>start_profiling/1</c> or @@ -87,14 +87,14 @@ </desc> </func> <func> - <name>profile(Fun) -> profiling | {error, Reason}</name> - <name>profile(Fun, Options) -> profiling | {error, Reason}</name> - <name>profile(Rootset) -> profiling | {error, Reason}</name> - <name>profile(Rootset,Fun) -> {ok, Value} | {error,Reason}</name> - <name>profile(Rootset,Fun,Pattern) -> {ok, Value} | {error, Reason}</name> - <name>profile(Rootset,Module,Function,Args) -> {ok, Value} | {error, Reason}</name> - <name>profile(Rootset,Module,Function,Args,Pattern) -> {ok, Value} | {error, Reason}</name> - <name>profile(Rootset,Module,Function,Args,Pattern,Options) -> {ok, Value} | {error, Reason}</name> + <name since="">profile(Fun) -> profiling | {error, Reason}</name> + <name since="">profile(Fun, Options) -> profiling | {error, Reason}</name> + <name since="">profile(Rootset) -> profiling | {error, Reason}</name> + <name since="">profile(Rootset,Fun) -> {ok, Value} | {error,Reason}</name> + <name since="OTP R14B">profile(Rootset,Fun,Pattern) -> {ok, Value} | {error, Reason}</name> + <name since="">profile(Rootset,Module,Function,Args) -> {ok, Value} | {error, Reason}</name> + <name since="OTP R14B">profile(Rootset,Module,Function,Args,Pattern) -> {ok, Value} | {error, Reason}</name> + <name since="OTP R16B01">profile(Rootset,Module,Function,Args,Pattern,Options) -> {ok, Value} | {error, Reason}</name> <fsummary>Start profiling.</fsummary> <type> <v>Rootset = [atom() | pid()]</v> @@ -128,9 +128,9 @@ </desc> </func> <func> - <name>analyze() -> ok</name> - <name>analyze(Type) -> ok</name> - <name>analyze(Type,Options) -> ok</name> + <name since="OTP R14B">analyze() -> ok</name> + <name since="OTP R14B">analyze(Type) -> ok</name> + <name since="OTP R14B">analyze(Type,Options) -> ok</name> <fsummary>Display profiling results per process.</fsummary> <type> <v>Type = procs | total</v> @@ -152,7 +152,7 @@ </desc> </func> <func> - <name>log(File) -> ok</name> + <name since="">log(File) -> ok</name> <fsummary>Activate logging of <c>eprof</c>printouts.</fsummary> <type> <v>File = atom() | string()</v> @@ -164,7 +164,7 @@ </desc> </func> <func> - <name>stop() -> stopped</name> + <name since="">stop() -> stopped</name> <fsummary>Stop Eprof.</fsummary> <desc> <p>Stops the Eprof server.</p> diff --git a/lib/tools/doc/src/fprof.xml b/lib/tools/doc/src/fprof.xml index 1fd828d127..4bb8862016 100644 --- a/lib/tools/doc/src/fprof.xml +++ b/lib/tools/doc/src/fprof.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>fprof.sgml</file> </header> - <module>fprof</module> + <module since="">fprof</module> <modulesummary>A Time Profiling Tool using trace to file for minimal runtime performance impact.</modulesummary> <description> <p>This module is used to profile a program @@ -101,7 +101,7 @@ </description> <funcs> <func> - <name>start() -> {ok, Pid} | {error, {already_started, Pid}}</name> + <name since="">start() -> {ok, Pid} | {error, {already_started, Pid}}</name> <fsummary>Starts the <c>fprof</c> server.</fsummary> <type> <v>Pid = pid()</v> @@ -117,14 +117,14 @@ </desc> </func> <func> - <name>stop() -> ok</name> + <name since="">stop() -> ok</name> <fsummary>Same as <c>stop(normal)</c>.</fsummary> <desc> <p>Same as <c>stop(normal)</c>.</p> </desc> </func> <func> - <name>stop(Reason) -> ok</name> + <name since="">stop(Reason) -> ok</name> <fsummary>Stops the <c>fprof</c> server.</fsummary> <type> <v>Reason = term()</v> @@ -149,7 +149,7 @@ </desc> </func> <func> - <name>apply(Func, Args) -> term()</name> + <name since="">apply(Func, Args) -> term()</name> <fsummary>Same as <c>apply(Func, Args, [])</c>.</fsummary> <type> <v>Func = function() | {Module, Function}</v> @@ -162,7 +162,7 @@ </desc> </func> <func> - <name>apply(Module, Function, Args) -> term()</name> + <name since="">apply(Module, Function, Args) -> term()</name> <fsummary>Same as <c>apply({Module, Function}, Args, [])</c>.</fsummary> <type> <v>Args = [term()]</v> @@ -174,7 +174,7 @@ </desc> </func> <func> - <name>apply(Func, Args, OptionList) -> term()</name> + <name since="">apply(Func, Args, OptionList) -> term()</name> <fsummary>Calls <c>erlang:apply(Func, Args)</c>surrounded by<c>trace([start | OptionList])</c>and<c>trace(stop)</c>.</fsummary> <type> <v>Func = function() | {Module, Function}</v> @@ -210,7 +210,7 @@ </desc> </func> <func> - <name>apply(Module, Function, Args, OptionList) -> term()</name> + <name since="">apply(Module, Function, Args, OptionList) -> term()</name> <fsummary>Same as <c>apply({Module, Function}, Args, OptionList)</c>.</fsummary> <type> <v>Module = atom()</v> @@ -228,7 +228,7 @@ </desc> </func> <func> - <name>trace(start, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">trace(start, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>trace([start, {file, Filename}])</c>.</fsummary> <type> <v>Reason = term()</v> @@ -238,7 +238,7 @@ </desc> </func> <func> - <name>trace(verbose, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">trace(verbose, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>trace([start, verbose, {file, Filename}])</c>.</fsummary> <type> <v>Reason = term()</v> @@ -249,7 +249,7 @@ </desc> </func> <func> - <name>trace(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">trace(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>trace([{OptionName, OptionValue}])</c>.</fsummary> <type> <v>OptionName = atom()</v> @@ -262,7 +262,7 @@ </desc> </func> <func> - <name>trace(verbose) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">trace(verbose) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>trace([start, verbose])</c>.</fsummary> <type> <v>Reason = term()</v> @@ -272,7 +272,7 @@ </desc> </func> <func> - <name>trace(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">trace(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>trace([OptionName])</c>.</fsummary> <type> <v>OptionName = atom()</v> @@ -283,7 +283,7 @@ </desc> </func> <func> - <name>trace({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">trace({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>trace([{OptionName, OptionValue}])</c>.</fsummary> <type> <v>OptionName = atom()</v> @@ -296,7 +296,7 @@ </desc> </func> <func> - <name>trace([Option]) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">trace([Option]) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Starts or stops tracing.</fsummary> <type> <v>Option = start | stop | {procs, PidSpec} | {procs, [PidSpec]} | verbose | {verbose, bool()} | file | {file, Filename} | {tracer, Tracer}</v> @@ -360,7 +360,7 @@ </desc> </func> <func> - <name>profile() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">profile() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>profile([])</c>.</fsummary> <type> <v>Reason = term()</v> @@ -370,7 +370,7 @@ </desc> </func> <func> - <name>profile(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">profile(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>profile([{OptionName, OptionValue}])</c>.</fsummary> <type> <v>OptionName = atom()</v> @@ -383,7 +383,7 @@ </desc> </func> <func> - <name>profile(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">profile(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>profile([OptionName])</c>.</fsummary> <type> <v>OptionName = atom()</v> @@ -394,7 +394,7 @@ </desc> </func> <func> - <name>profile({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">profile({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>profile([{OptionName, OptionValue}])</c>.</fsummary> <type> <v>OptionName = atom()</v> @@ -407,7 +407,7 @@ </desc> </func> <func> - <name>profile([Option]) -> ok | {ok, Tracer} | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">profile([Option]) -> ok | {ok, Tracer} | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Compiles a trace into raw profile data held by the <c>fprof</c> server.</fsummary> <type> <v>Option = file | {file, Filename} | dump | {dump, Dump} | append | start | stop</v> @@ -465,7 +465,7 @@ </desc> </func> <func> - <name>analyse() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">analyse() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>analyse([])</c>.</fsummary> <type> <v>Reason = term()</v> @@ -475,7 +475,7 @@ </desc> </func> <func> - <name>analyse(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">analyse(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>analyse([{OptionName, OptionValue}])</c>.</fsummary> <type> <v>OptionName = atom()</v> @@ -488,7 +488,7 @@ </desc> </func> <func> - <name>analyse(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">analyse(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>analyse([OptionName])</c>.</fsummary> <type> <v>OptionName = atom()</v> @@ -499,7 +499,7 @@ </desc> </func> <func> - <name>analyse({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">analyse({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Same as <c>analyse([{OptionName, OptionValue}])</c>.</fsummary> <type> <v>OptionName = atom()</v> @@ -512,7 +512,7 @@ </desc> </func> <func> - <name>analyse([Option]) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> + <name since="">analyse([Option]) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name> <fsummary>Analyses raw profile data in the <c>fprof</c> server.</fsummary> <type> <v>Option = dest | {dest, Dest} | append | {cols, Cols} | callers | {callers, bool()} | no_callers | {sort, SortSpec} | totals | {totals, bool()} | details | {details, bool()} | no_details</v> diff --git a/lib/tools/doc/src/instrument.xml b/lib/tools/doc/src/instrument.xml index 9fd9332373..75be22de9b 100644 --- a/lib/tools/doc/src/instrument.xml +++ b/lib/tools/doc/src/instrument.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>instrument.sgml</file> </header> - <module>instrument</module> + <module since="">instrument</module> <modulesummary>Analysis and Utility Functions for Instrumentation</modulesummary> <description> <p>The module <c>instrument</c> contains support for studying the resource @@ -92,7 +92,7 @@ <funcs> <func> - <name name="allocations" arity="0"/> + <name name="allocations" arity="0" since="OTP 21.0"/> <fsummary>Return a summary of all allocations in the system.</fsummary> <desc> <p>Shorthand for @@ -101,7 +101,7 @@ </func> <func> - <name name="allocations" arity="1"/> + <name name="allocations" arity="1" since="OTP 21.0"/> <fsummary>Return a summary of all allocations filtered by allocator type and scheduler id.</fsummary> <desc> @@ -170,7 +170,7 @@ </func> <func> - <name name="carriers" arity="0"/> + <name name="carriers" arity="0" since="OTP 21.0"/> <fsummary>Return a list of all carriers in the system.</fsummary> <desc> <p>Shorthand for @@ -179,7 +179,7 @@ </func> <func> - <name name="carriers" arity="1"/> + <name name="carriers" arity="1" since="OTP 21.0"/> <fsummary>Return a list of all carriers filtered by allocator type and scheduler id.</fsummary> <desc> diff --git a/lib/tools/doc/src/lcnt.xml b/lib/tools/doc/src/lcnt.xml index d2595cdb60..1d434decfc 100644 --- a/lib/tools/doc/src/lcnt.xml +++ b/lib/tools/doc/src/lcnt.xml @@ -34,7 +34,7 @@ <rev>PA1</rev> <file>lcnt.xml</file> </header> - <module>lcnt</module> + <module since="OTP R13B04">lcnt</module> <modulesummary>A runtime system Lock Profiling tool.</modulesummary> <description> <p>The <c>lcnt</c> module is used to profile the internal ethread locks in the @@ -71,7 +71,7 @@ <funcs> <func> - <name>start() -> {ok, Pid} | {error, {already_started, Pid}} </name> + <name since="OTP R13B04">start() -> {ok, Pid} | {error, {already_started, Pid}} </name> <fsummary>Starts the lock profiler server.</fsummary> <type> <v>Pid = pid()</v> @@ -84,7 +84,7 @@ </func> <func> - <name>stop() -> ok</name> + <name since="OTP R13B04">stop() -> ok</name> <fsummary>Stops the lock profiler server.</fsummary> <desc> <p>Stops the lock profiler server.</p> @@ -92,13 +92,13 @@ </func> <func> - <name>collect() -> ok</name> + <name since="OTP R13B04">collect() -> ok</name> <fsummary>Same as <c>collect(node())</c>.</fsummary> <desc><p>Same as <c>collect(node())</c>.</p></desc> </func> <func> - <name>collect(Node) -> ok</name> + <name since="OTP R13B04">collect(Node) -> ok</name> <fsummary>Collects lock statistics from the runtime system.</fsummary> <type> <v>Node = node()</v> @@ -113,13 +113,13 @@ </func> <func> - <name>clear() -> ok</name> + <name since="OTP R13B04">clear() -> ok</name> <fsummary>Same as <c>clear(node())</c>.</fsummary> <desc><p>Same as <c>clear(node())</c>.</p></desc> </func> <func> - <name>clear(Node) -> ok</name> + <name since="OTP R13B04">clear(Node) -> ok</name> <fsummary>Clears the internal lock statistics from runtime system.</fsummary> <type> <v>Node = node()</v> @@ -133,12 +133,12 @@ </desc> </func> <func> - <name>conflicts() -> ok</name> + <name since="OTP R13B04">conflicts() -> ok</name> <fsummary>Same as <c>conflicts([])</c>.</fsummary> <desc><p>Same as <c>conflicts([])</c>.</p></desc> </func> <func> - <name>conflicts([Option]) -> ok</name> + <name since="OTP R13B04">conflicts([Option]) -> ok</name> <fsummary>Prints a list of internal lock counters.</fsummary> <type> <v>Option = {sort, Sort} | {reverse, bool()} | {thresholds, [Thresholds]} | {print, [Print | {Print, integer()}]} | {max_locks, MaxLocks} | {combine, bool()}</v> @@ -154,14 +154,14 @@ </func> <func> - <name>locations() -> ok</name> + <name since="OTP R13B04">locations() -> ok</name> <fsummary>Same as <c>locations([])</c>.</fsummary> <desc> <p>Same as <c>locations([])</c>.</p> </desc> </func> <func> - <name>locations([Option]) -> ok</name> + <name since="OTP R13B04">locations([Option]) -> ok</name> <fsummary>Prints a list of internal lock counters by source code locations.</fsummary> <type> <v>Option = {sort, Sort} | {thresholds, [Thresholds]} | {print, [Print | {Print, integer()}]} | {max_locks, MaxLocks} | {combine, bool()}</v> @@ -177,12 +177,12 @@ </func> <func> - <name>inspect(Lock) -> ok</name> + <name since="OTP R13B04">inspect(Lock) -> ok</name> <fsummary>Same as <c>inspect(Lock, [])</c>.</fsummary> <desc><p>Same as <c>inspect(Lock, [])</c>.</p></desc> </func> <func> - <name>inspect(Lock, [Option]) -> ok</name> + <name since="OTP R13B04">inspect(Lock, [Option]) -> ok</name> <fsummary>Prints a list of internal lock counters for a specific lock.</fsummary> <type> <v>Lock = Name | {Name, Id | [Id]}</v> @@ -268,7 +268,7 @@ </func> <func> - <name>information() -> ok</name> + <name since="OTP R13B04">information() -> ok</name> <fsummary>Prints lcnt server state and generic information about collected lock statistics.</fsummary> <desc> <p>Prints lcnt server state and generic information about collected lock statistics.</p> @@ -276,7 +276,7 @@ </func> <func> - <name>swap_pid_keys() -> ok</name> + <name since="OTP R13B04">swap_pid_keys() -> ok</name> <fsummary>Swaps places on <c>Name</c> and <c>Id</c> space for ports and processes.</fsummary> <desc> <p>Swaps places on <c>Name</c> and <c>Id</c> space for ports and processes.</p> @@ -284,7 +284,7 @@ </func> <func> - <name>load(Filename) -> ok</name> + <name since="OTP R13B04">load(Filename) -> ok</name> <fsummary>Restores previously saved data to the server.</fsummary> <type> <v>Filename = filename()</v> @@ -295,7 +295,7 @@ </func> <func> - <name>save(Filename) -> ok</name> + <name since="OTP R13B04">save(Filename) -> ok</name> <fsummary>Saves the collected data to file.</fsummary> <type> <v>Filename = filename()</v> @@ -312,7 +312,7 @@ </section> <funcs> <func> - <name>apply(Fun) -> term()</name> + <name since="OTP R13B04">apply(Fun) -> term()</name> <fsummary>Same as <c>apply(Fun, [])</c>.</fsummary> <type> <v>Fun = fun()</v> @@ -322,7 +322,7 @@ </desc> </func> <func> - <name>apply(Fun, Args) -> term()</name> + <name since="OTP R13B04">apply(Fun, Args) -> term()</name> <fsummary>Same as <c>apply(Module, Function, Args)</c>.</fsummary> <type> <v>Fun = fun()</v> @@ -333,7 +333,7 @@ </desc> </func> <func> - <name>apply(Module, Function, Args) -> term()</name> + <name since="OTP R13B04">apply(Module, Function, Args) -> term()</name> <fsummary>Clears counters, applies function and collects the profiling results.</fsummary> <type> <v>Module = atom()</v> @@ -358,12 +358,12 @@ </func> <func> - <name>pid(Id, Serial) -> pid()</name> + <name since="OTP R13B04">pid(Id, Serial) -> pid()</name> <fsummary>Same as <c>pid(node(), Id, Serial)</c>.</fsummary> <desc><p>Same as <c>pid(node(), Id, Serial)</c>.</p></desc> </func> <func> - <name>pid(Node, Id, Serial) -> pid()</name> + <name since="OTP R13B04">pid(Node, Id, Serial) -> pid()</name> <fsummary>Creates a process id with creation 0.</fsummary> <type> <v>Node = node()</v> @@ -376,12 +376,12 @@ </func> <func> - <name>port(Id) -> port()</name> + <name since="OTP R13B04">port(Id) -> port()</name> <fsummary>Same as <c>port(node(), Id)</c>.</fsummary> <desc><p>Same as <c>port(node(), Id)</c>.</p></desc> </func> <func> - <name>port(Node, Id) -> port()</name> + <name since="OTP R13B04">port(Node, Id) -> port()</name> <fsummary>Creates a port id with creation 0.</fsummary> <type> <v>Node = node()</v> @@ -399,12 +399,12 @@ <funcs> <func> - <name>rt_collect() -> [lock_counter_data()]</name> + <name since="OTP R13B04">rt_collect() -> [lock_counter_data()]</name> <fsummary>Same as <c>rt_collect(node())</c>.</fsummary> <desc> <p>Same as <c>rt_collect(node())</c>.</p> </desc> </func> <func> - <name>rt_collect(Node) -> [lock_counter_data()]</name> + <name since="OTP R13B04">rt_collect(Node) -> [lock_counter_data()]</name> <fsummary>Returns a list of raw lock counter data.</fsummary> <type> <v>Node = node()</v> @@ -413,12 +413,12 @@ </func> <func> - <name>rt_clear() -> ok</name> + <name since="OTP R13B04">rt_clear() -> ok</name> <fsummary>Same as <c>rt_clear(node())</c>.</fsummary> <desc> <p>Same as <c>rt_clear(node())</c>.</p> </desc> </func> <func> - <name>rt_clear(Node) -> ok</name> + <name since="OTP R13B04">rt_clear(Node) -> ok</name> <fsummary>Clears the internal counters.</fsummary> <type> <v>Node = node()</v> @@ -427,13 +427,13 @@ </func> <func> - <name>rt_mask() -> [category_atom()]</name> + <name since="OTP 20.1">rt_mask() -> [category_atom()]</name> <fsummary>Same as <c>rt_mask(node())</c>.</fsummary> <desc><p>Same as <c>rt_mask(node())</c>.</p></desc> </func> <func> - <name>rt_mask(Node) -> [category_atom()]</name> + <name since="OTP 20.1">rt_mask(Node) -> [category_atom()]</name> <fsummary>Returns the current lock category mask.</fsummary> <type> <v>Node = node()</v> @@ -447,7 +447,7 @@ </func> <func> - <name>rt_mask(Categories) -> ok | {error, copy_save_enabled}</name> + <name since="OTP 20.1">rt_mask(Categories) -> ok | {error, copy_save_enabled}</name> <fsummary>Same as <c>rt_mask(node(), Categories)</c>.</fsummary> <type> <v>Categories = [atom()]</v> @@ -456,7 +456,7 @@ </func> <func> - <name>rt_mask(Node, Categories) -> ok | {error, copy_save_enabled}</name> + <name since="OTP 20.1">rt_mask(Node, Categories) -> ok | {error, copy_save_enabled}</name> <fsummary>Changes the lock category mask.</fsummary> <type> <v>Node = node()</v> @@ -489,12 +489,12 @@ </func> <func> - <name>rt_opt({Type, bool()}) -> bool()</name> + <name since="OTP R13B04">rt_opt({Type, bool()}) -> bool()</name> <fsummary>Same as <c>rt_opt(node(), {Type, Opt})</c>.</fsummary> <desc> <p>Same as <c>rt_opt(node(), {Type, Opt})</c>.</p> </desc> </func> <func> - <name>rt_opt(Node, {Type, bool()}) -> bool()</name> + <name since="OTP R13B04">rt_opt(Node, {Type, bool()}) -> bool()</name> <fsummary>Changes the lock counter behavior and returns the previous behaviour.</fsummary> <type> <v>Node = node()</v> diff --git a/lib/tools/doc/src/make.xml b/lib/tools/doc/src/make.xml index 123fcd4afc..af2404707f 100644 --- a/lib/tools/doc/src/make.xml +++ b/lib/tools/doc/src/make.xml @@ -30,7 +30,7 @@ <date></date> <rev></rev> </header> - <module>make</module> + <module since="">make</module> <modulesummary>A Make Utility for Erlang</modulesummary> <description> <p>The module <c>make</c> provides a set of functions similar to @@ -38,8 +38,8 @@ </description> <funcs> <func> - <name>all() -> up_to_date | error</name> - <name>all(Options) -> up_to_date | error</name> + <name since="">all() -> up_to_date | error</name> + <name since="">all(Options) -> up_to_date | error</name> <fsummary>Compile a set of modules.</fsummary> <type> <v>Options = [Option]</v> @@ -87,8 +87,8 @@ </desc> </func> <func> - <name>files(ModFiles) -> up_to_date | error</name> - <name>files(ModFiles, Options) -> up_to_date | error</name> + <name since="">files(ModFiles) -> up_to_date | error</name> + <name since="">files(ModFiles, Options) -> up_to_date | error</name> <fsummary>Compile a set of modules.</fsummary> <type> <v>ModFiles = [Module | File]</v> diff --git a/lib/tools/doc/src/tags.xml b/lib/tools/doc/src/tags.xml index ea0ae5cc4d..90a8b28177 100644 --- a/lib/tools/doc/src/tags.xml +++ b/lib/tools/doc/src/tags.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>tags.sgml</file> </header> - <module>tags</module> + <module since="">tags</module> <modulesummary>Generate Emacs TAGS file from Erlang source files</modulesummary> <description> <p>A <c>TAGS</c> file is used by Emacs to find function and variable @@ -42,14 +42,14 @@ </description> <funcs> <func> - <name>file(File [, Options])</name> + <name since="">file(File [, Options])</name> <fsummary>Create a <c>TAGS</c>file for the file <c>File</c>.</fsummary> <desc> <p>Create a <c>TAGS</c> file for the file <c>File</c>.</p> </desc> </func> <func> - <name>files(FileList [, Options])</name> + <name since="">files(FileList [, Options])</name> <fsummary>Create a TAGS file for the files in the list<c>FileList</c>.</fsummary> <desc> <p>Create a TAGS file for the files in the list @@ -57,7 +57,7 @@ </desc> </func> <func> - <name>dir(Dir [, Options])</name> + <name since="">dir(Dir [, Options])</name> <fsummary>Create a TAGS file for all files in directory<c>Dir</c>.</fsummary> <desc> <p>Create a TAGS file for all files in directory @@ -65,7 +65,7 @@ </desc> </func> <func> - <name>dirs(DirList [, Options])</name> + <name since="">dirs(DirList [, Options])</name> <fsummary>Create a TAGS file for all files in any directory in<c>DirList</c>.</fsummary> <desc> <p>Create a TAGS file for all files in any directory in @@ -73,7 +73,7 @@ </desc> </func> <func> - <name>subdir(Dir [, Options])</name> + <name since="">subdir(Dir [, Options])</name> <fsummary>Descend recursively down the directory <c>Dir</c>and create a <c>TAGS</c>file based on all files found.</fsummary> <desc> <p>Descend recursively down the directory <c>Dir</c> and @@ -81,7 +81,7 @@ </desc> </func> <func> - <name>subdirs(DirList [, Options])</name> + <name since="">subdirs(DirList [, Options])</name> <fsummary>Descend recursively down all the directories in<c>DirList</c>and create a <c>TAGS</c>file based on all files found.</fsummary> <desc> <p>Descend recursively down all the directories in @@ -90,7 +90,7 @@ </desc> </func> <func> - <name>root([Options])</name> + <name since="">root([Options])</name> <fsummary>Create a <c>TAGS</c>file covering all files in the Erlang distribution.</fsummary> <desc> <p>Create a <c>TAGS</c> file covering all files in diff --git a/lib/tools/doc/src/xref.xml b/lib/tools/doc/src/xref.xml index 6f833246ad..ab3641a52f 100644 --- a/lib/tools/doc/src/xref.xml +++ b/lib/tools/doc/src/xref.xml @@ -32,7 +32,7 @@ <rev>PA1</rev> <file>xref.sgml</file> </header> - <module>xref</module> + <module since="">xref</module> <modulesummary>A Cross Reference Tool for analyzing dependencies between functions, modules, applications and releases.</modulesummary> <description> <p>Xref is a cross reference tool that can be used for finding @@ -729,7 +729,7 @@ xref() = atom() | pid() </pre> </description> <funcs> <func> - <name>add_application(Xref, Directory [, Options]) -> {ok, application()} | Error</name> + <name since="">add_application(Xref, Directory [, Options]) -> {ok, application()} | Error</name> <fsummary>Add the modules of an application.</fsummary> <type> <v>Directory = directory()</v> @@ -761,7 +761,7 @@ xref() = atom() | pid() </pre> </desc> </func> <func> - <name>add_directory(Xref, Directory [, Options]) -> {ok, Modules} | Error</name> + <name since="">add_directory(Xref, Directory [, Options]) -> {ok, Modules} | Error</name> <fsummary>Add the modules in a directory.</fsummary> <type> <v>Directory = directory()</v> @@ -791,7 +791,7 @@ xref() = atom() | pid() </pre> </desc> </func> <func> - <name>add_module(Xref, File [, Options]) -> {ok, module()} | Error</name> + <name since="">add_module(Xref, File [, Options]) -> {ok, module()} | Error</name> <fsummary>Add a module.</fsummary> <type> <v>Error = {error, module(), Reason}</v> @@ -814,7 +814,7 @@ xref() = atom() | pid() </pre> </desc> </func> <func> - <name>add_release(Xref, Directory [, Options]) -> {ok, release()} | Error</name> + <name since="">add_release(Xref, Directory [, Options]) -> {ok, release()} | Error</name> <fsummary>Add the modules of a release.</fsummary> <type> <v>Directory = directory()</v> @@ -849,7 +849,7 @@ xref() = atom() | pid() </pre> </desc> </func> <func> - <name>analyze(Xref, Analysis [, Options]) -> {ok, Answer} | Error</name> + <name since="">analyze(Xref, Analysis [, Options]) -> {ok, Answer} | Error</name> <fsummary>Evaluate a predefined analysis.</fsummary> <type> <v>Analysis = undefined_function_calls | undefined_functions | locals_not_used | exports_not_used | deprecated_function_calls | {deprecated_function_calls, DeprFlag} | deprecated_functions | {deprecated_functions, DeprFlag} | {call, FuncSpec} | {use, FuncSpec} | {module_call, ModSpec} | {module_use, ModSpec} | {application_call, AppSpec} | {application_use, AppSpec} | {release_call, RelSpec} | {release_use, RelSpec}</v> @@ -939,7 +939,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>d(Directory) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name> + <name since="">d(Directory) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name> <fsummary>Check the modules in a directory using the code path.</fsummary> <type> <v>Directory = directory()</v> @@ -979,8 +979,8 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>forget(Xref) -> ok</name> - <name>forget(Xref, Variables) -> ok | Error</name> + <name since="">forget(Xref) -> ok</name> + <name since="">forget(Xref, Variables) -> ok | Error</name> <fsummary>Remove user variables and their values.</fsummary> <type> <v>Error = {error, module(), Reason}</v> @@ -994,7 +994,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>format_error(Error) -> Chars</name> + <name since="">format_error(Error) -> Chars</name> <fsummary>Return an English description of an Xref error reply.</fsummary> <type> <v>Error = {error, module(), term()}</v> @@ -1008,8 +1008,8 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>get_default(Xref) -> [{Option, Value}]</name> - <name>get_default(Xref, Option) -> {ok, Value} | Error</name> + <name since="">get_default(Xref) -> [{Option, Value}]</name> + <name since="">get_default(Xref, Option) -> {ok, Value} | Error</name> <fsummary>Return the default values of options.</fsummary> <type> <v>Error = {error, module(), Reason}</v> @@ -1023,7 +1023,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>get_library_path(Xref) -> {ok, LibraryPath}</name> + <name since="">get_library_path(Xref) -> {ok, LibraryPath}</name> <fsummary>Return the library path.</fsummary> <type> <v>LibraryPath = library_path()</v> @@ -1034,9 +1034,9 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>info(Xref) -> [Info]</name> - <name>info(Xref, Category) -> [{Item, [Info]}]</name> - <name>info(Xref, Category, Items) -> [{Item, [Info]}]</name> + <name since="">info(Xref) -> [Info]</name> + <name since="">info(Xref, Category) -> [{Item, [Info]}]</name> + <name since="">info(Xref, Category, Items) -> [{Item, [Info]}]</name> <fsummary>Return information about an Xref server.</fsummary> <type> <v>Application = [] | [application()]</v> @@ -1220,8 +1220,8 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>m(Module) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name> - <name>m(File) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name> + <name since="">m(Module) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name> + <name since="">m(File) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name> <fsummary>Check a module using the code path.</fsummary> <type> <v>DebugInfoResult = {deprecated, [funcall()]} | {undefined, [funcall()]} | {unused, [mfa()]}</v> @@ -1263,7 +1263,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>q(Xref, Query [, Options]) -> {ok, Answer} | Error</name> + <name since="">q(Xref, Query [, Options]) -> {ok, Answer} | Error</name> <fsummary>Evaluate a query.</fsummary> <type> <v>Answer = false | [constant()] | [Call] | [Component] | int() | [DefineAt] | [CallAt] | [AllLines]</v> @@ -1322,7 +1322,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>remove_application(Xref, Applications) -> ok | Error</name> + <name since="">remove_application(Xref, Applications) -> ok | Error</name> <fsummary>Remove applications and their modules.</fsummary> <type> <v>Applications = application() | [application()]</v> @@ -1335,7 +1335,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>remove_module(Xref, Modules) -> ok | Error</name> + <name since="">remove_module(Xref, Modules) -> ok | Error</name> <fsummary>Remove analyzed modules.</fsummary> <type> <v>Error = {error, module(), Reason}</v> @@ -1348,7 +1348,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>remove_release(Xref, Releases) -> ok | Error</name> + <name since="">remove_release(Xref, Releases) -> ok | Error</name> <fsummary>Remove releases and their applications and modules.</fsummary> <type> <v>Error = {error, module(), Reason}</v> @@ -1363,7 +1363,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>replace_application(Xref, Application, Directory [, Options]) -> {ok, application()} | Error</name> + <name since="">replace_application(Xref, Application, Directory [, Options]) -> {ok, application()} | Error</name> <fsummary>Replace an application's modules.</fsummary> <type> <v>Application = application()</v> @@ -1384,7 +1384,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>replace_module(Xref, Module, File [, Options]) -> {ok, module()} | Error</name> + <name since="">replace_module(Xref, Module, File [, Options]) -> {ok, module()} | Error</name> <fsummary>Replace an analyzed module.</fsummary> <type> <v>Error = {error, module(), Reason}</v> @@ -1409,8 +1409,8 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>set_default(Xref, Option, Value) -> {ok, OldValue} | Error</name> - <name>set_default(Xref, OptionValues) -> ok | Error</name> + <name since="">set_default(Xref, Option, Value) -> {ok, OldValue} | Error</name> + <name since="">set_default(Xref, OptionValues) -> ok | Error</name> <fsummary>Set the default values of options.</fsummary> <type> <v>Error = {error, module(), Reason}</v> @@ -1435,7 +1435,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>set_library_path(Xref, LibraryPath [, Options]) -> ok | Error</name> + <name since="">set_library_path(Xref, LibraryPath [, Options]) -> ok | Error</name> <fsummary>Set the library path and finds the library modules.</fsummary> <type> <v>Error = {error, module(), Reason}</v> @@ -1469,7 +1469,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>start(NameOrOptions) -> Return</name> + <name since="">start(NameOrOptions) -> Return</name> <fsummary>Create an Xref server.</fsummary> <type> <v>NameOrOptions = Name | Options</v> @@ -1487,7 +1487,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>start(Name, Options) -> Return</name> + <name since="">start(Name, Options) -> Return</name> <fsummary>Create an Xref server.</fsummary> <type> <v>Name = atom()</v> @@ -1504,7 +1504,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>stop(Xref)</name> + <name since="">stop(Xref)</name> <fsummary>Delete an Xref server.</fsummary> <type> <v>Xref = xref()</v> @@ -1514,7 +1514,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>update(Xref [, Options]) -> {ok, Modules} | Error</name> + <name since="">update(Xref [, Options]) -> {ok, Modules} | Error</name> <fsummary>Replace newly compiled analyzed modules.</fsummary> <type> <v>Error = {error, module(), Reason}</v> @@ -1534,7 +1534,7 @@ Evaluates a predefined analysis. </desc> </func> <func> - <name>variables(Xref [, Options]) -> {ok, [VariableInfo]}</name> + <name since="">variables(Xref [, Options]) -> {ok, [VariableInfo]}</name> <fsummary>Return the names of variables.</fsummary> <type> <v>Options = [Option] | Option</v> diff --git a/lib/tools/priv/styles.css b/lib/tools/priv/styles.css index e10e94e3ad..84f00be9fd 100644 --- a/lib/tools/priv/styles.css +++ b/lib/tools/priv/styles.css @@ -53,21 +53,25 @@ table thead { display: none; } table td.line, +table td.line a, table td.hits { width: 20px; background: #eaeaea; text-align: center; + text-decoration: none; font-size: 11px; padding: 0 10px; color: #949494; } table td.hits { width: 10px; + text-align: right; padding: 2px 5px; color: rgba(0, 0, 0, 0.6); background-color: #f0f0f0; } tr.miss td.line, +tr.miss td.line a, tr.miss td.hits { background-color: #ffdce0; border-color: #fdaeb7; @@ -76,6 +80,7 @@ tr.miss td { background-color: #ffeef0; } tr.hit td.line, +tr.hit td.line a, tr.hit td.hits { background-color: #cdffd8; border-color: #bef5cb; diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index d7269e3f27..8d4561ca9e 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -2563,11 +2563,13 @@ table_row(Line, L) -> table_data(Line, L, N) -> LineNoNL = Line -- "\n", ["<td class=\"line\" id=\"L",integer_to_list(L),"\">", + "<a href=\"#L",integer_to_list(L),"\">", integer_to_list(L), - "</td>\n", + "</a></td>\n", "<td class=\"hits\">",maybe_integer_to_list(N),"</td>\n", "<td class=\"source\"><code>",LineNoNL,"</code></td>\n</tr>\n"]. +maybe_integer_to_list(0) -> "<pre style=\"display: inline;\">:-(</pre>"; maybe_integer_to_list(N) when is_integer(N) -> integer_to_list(N); maybe_integer_to_list(_) -> "". diff --git a/lib/wx/c_src/Makefile.in b/lib/wx/c_src/Makefile.in index daa8afce83..8ec64bea7e 100644 --- a/lib/wx/c_src/Makefile.in +++ b/lib/wx/c_src/Makefile.in @@ -181,6 +181,7 @@ release_spec: opt $(INSTALL_DIR) "$(RELSYSDIR)/priv" $(INSTALL_DATA) ../priv/erlang-logo32.png "$(RELSYSDIR)/priv/" $(INSTALL_DATA) ../priv/erlang-logo64.png "$(RELSYSDIR)/priv/" + $(INSTALL_DATA) ../priv/erlang-logo128.png "$(RELSYSDIR)/priv/" $(INSTALL_PROGRAM) $(TARGET_DIR)/wxe_driver$(SO_EXT) "$(RELSYSDIR)/priv/" $(INSTALL_PROGRAM) $(TARGET_DIR)/erl_gl$(SO_EXT) "$(RELSYSDIR)/priv/" diff --git a/lib/wx/c_src/wxe_ps_init.c b/lib/wx/c_src/wxe_ps_init.c index 4b3b47a80b..62c7c51c13 100644 --- a/lib/wx/c_src/wxe_ps_init.c +++ b/lib/wx/c_src/wxe_ps_init.c @@ -64,6 +64,10 @@ void * wxe_ps_init2() { size_t app_len = 127; char app_title_buf[128]; char * app_title; + size_t app_icon_len = 1023; + char app_icon_buf[1024]; + char * app_icon; + // Setup and enable gui pool = [[NSAutoreleasePool alloc] init]; @@ -78,9 +82,15 @@ void * wxe_ps_init2() { if(!GetCurrentProcess(&psn)) { CPSSetProcessName(&psn, app_title?app_title:"Erlang"); } - // Load and set icon + // Enable setting custom application icon for Mac OS X + res = erl_drv_getenv("WX_APP_ICON", app_icon_buf, &app_icon_len); NSMutableString *file = [[NSMutableString alloc] init]; - [file appendFormat:@"%s/%s", erl_wx_privdir, "erlang-logo64.png"]; + if (res >= 0) { + [file appendFormat:@"%s", app_icon_buf]; + } else { + [file appendFormat:@"%s/%s", erl_wx_privdir, "erlang-logo128.png"]; + } + // Load and set icon NSImage *icon = [[NSImage alloc] initWithContentsOfFile: file]; [NSApp setApplicationIconImage: icon]; }; diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml index a97036127e..7f6874e36b 100644 --- a/lib/xmerl/doc/src/notes.xml +++ b/lib/xmerl/doc/src/notes.xml @@ -32,6 +32,21 @@ <p>This document describes the changes made to the Xmerl application.</p> +<section><title>Xmerl 1.3.19</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>The charset detection parsing crash in some cases when + the XML directive is not syntactic correct.</p> + <p> + Own Id: OTP-15492 Aux Id: ERIERL-283 </p> + </item> + </list> + </section> + +</section> + <section><title>Xmerl 1.3.18</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -62,6 +77,21 @@ </section> +<section><title>Xmerl 1.3.16.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>The charset detection parsing crash in some cases when + the XML directive is not syntactic correct.</p> + <p> + Own Id: OTP-15492 Aux Id: ERIERL-283 </p> + </item> + </list> + </section> + +</section> + <section><title>Xmerl 1.3.16</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -1412,4 +1442,3 @@ </section> </section> </chapter> - diff --git a/lib/xmerl/doc/src/xmerl_sax_parser.xml b/lib/xmerl/doc/src/xmerl_sax_parser.xml index 8ea197e209..2390779028 100644 --- a/lib/xmerl/doc/src/xmerl_sax_parser.xml +++ b/lib/xmerl/doc/src/xmerl_sax_parser.xml @@ -31,7 +31,7 @@ <rev></rev> </header> - <module>xmerl_sax_parser</module> + <module since="">xmerl_sax_parser</module> <modulesummary>XML SAX parser API</modulesummary> <description> @@ -325,7 +325,7 @@ <funcs> <func> - <name>file(Filename, Options) -> Result</name> + <name since="">file(Filename, Options) -> Result</name> <fsummary>Parse file containing an XML document.</fsummary> <type> <v>Filename = string()</v> @@ -347,7 +347,7 @@ </func> <func> - <name>stream(Xml, Options) -> Result</name> + <name since="">stream(Xml, Options) -> Result</name> <fsummary>Parse a stream containing an XML document.</fsummary> <type> <v>Xml = unicode_binary() | latin1_binary() | [unicode_char()]</v> @@ -381,7 +381,7 @@ <funcs> <func> - <name>ContinuationFun(State) -> {NewBytes, NewState}</name> + <name since="">ContinuationFun(State) -> {NewBytes, NewState}</name> <fsummary>Continuation call back function.</fsummary> <type> <v>State = NewState = term()</v> @@ -402,7 +402,7 @@ </func> <func> - <name>EventFun(Event, Location, State) -> NewState</name> + <name since="">EventFun(Event, Location, State) -> NewState</name> <fsummary>Event call back function.</fsummary> <type> <v>Event = event()</v> diff --git a/lib/xmerl/src/xmerl_sax_parser.erl b/lib/xmerl/src/xmerl_sax_parser.erl index e383c4c349..fe836fd8cd 100644 --- a/lib/xmerl/src/xmerl_sax_parser.erl +++ b/lib/xmerl/src/xmerl_sax_parser.erl @@ -1,8 +1,8 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2017. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2008-2018. 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. %% You may obtain a copy of the License at @@ -14,13 +14,13 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%% +%% %% %CopyrightEnd% %%---------------------------------------------------------------------- %% File : xmerl_sax_parser.erl %% Description : XML SAX parse API module. %% -%% Created : 4 Jun 2008 +%% Created : 4 Jun 2008 %%---------------------------------------------------------------------- -module(xmerl_sax_parser). @@ -72,9 +72,9 @@ file(Name,Options) -> CL = filename:absname(Dir), File = filename:basename(Name), ContinuationFun = fun default_continuation_cb/1, - Res = stream(<<>>, + Res = stream(<<>>, [{continuation_fun, ContinuationFun}, - {continuation_state, FD}, + {continuation_state, FD}, {current_location, CL}, {entity, File} |Options], @@ -101,39 +101,39 @@ stream(Xml, Options, InputType) when is_list(Xml), is_list(Options) -> State = parse_options(Options, initial_state()), case State#xmerl_sax_parser_state.file_type of dtd -> - xmerl_sax_parser_list:parse_dtd(Xml, + xmerl_sax_parser_list:parse_dtd(Xml, State#xmerl_sax_parser_state{encoding = list, input_type = InputType}); normal -> - xmerl_sax_parser_list:parse(Xml, + xmerl_sax_parser_list:parse(Xml, State#xmerl_sax_parser_state{encoding = list, input_type = InputType}) end; stream(Xml, Options, InputType) when is_binary(Xml), is_list(Options) -> - case parse_options(Options, initial_state()) of + case parse_options(Options, initial_state()) of {error, Reason} -> {error, Reason}; State -> - ParseFunction = + ParseFunction = case State#xmerl_sax_parser_state.file_type of dtd -> parse_dtd; normal -> parse end, - try + try {Xml1, State1} = detect_charset(Xml, State), parse_binary(Xml1, State1#xmerl_sax_parser_state{input_type = InputType}, ParseFunction) catch throw:{fatal_error, {State2, Reason}} -> - {fatal_error, + {fatal_error, { State2#xmerl_sax_parser_state.current_location, - State2#xmerl_sax_parser_state.entity, + State2#xmerl_sax_parser_state.entity, 1 }, - Reason, [], + Reason, [], State2#xmerl_sax_parser_state.event_state} end end. @@ -157,7 +157,7 @@ parse_binary(Xml, #xmerl_sax_parser_state{encoding={utf16,big}}=State, F) -> xmerl_sax_parser_utf16be:F(Xml, State); parse_binary(Xml, #xmerl_sax_parser_state{encoding=latin1}=State, F) -> xmerl_sax_parser_latin1:F(Xml, State); -parse_binary(_, #xmerl_sax_parser_state{encoding=Enc}, State) -> +parse_binary(_, #xmerl_sax_parser_state{encoding=Enc}, State) -> ?fatal_error(State, lists:flatten(io_lib:format("Charcter set ~p not supported", [Enc]))). %%---------------------------------------------------------------------- @@ -177,9 +177,9 @@ initial_state() -> %%---------------------------------------------------------------------- %% Function: parse_options(Options, State) %% Input: Options = [Option] -%% Option = {event_state, term()} | {event_fun, fun()} | +%% Option = {event_state, term()} | {event_fun, fun()} | %% {continuation_state, term()} | {continuation_fun, fun()} | -%% {encoding, Encoding} | {file_type, FT} +%% {encoding, Encoding} | {file_type, FT} %% FT = normal | dtd %% Encoding = utf8 | utf16le | utf16be | list | iso8859 %% State = #xmerl_sax_parser_state{} @@ -200,7 +200,7 @@ parse_options([{file_type, FT} |Options], State) when FT==normal; FT==dtd -> parse_options(Options, State#xmerl_sax_parser_state{file_type = FT}); parse_options([{encoding, E} |Options], State) -> case check_encoding_option(E) of - {error, Reason} -> + {error, Reason} -> {error, Reason}; Enc -> parse_options(Options, State#xmerl_sax_parser_state{encoding = Enc}) @@ -231,7 +231,7 @@ check_encoding_option(E) -> %% Description: Detects which character set is used in a binary stream. %%---------------------------------------------------------------------- detect_charset(<<>>, #xmerl_sax_parser_state{continuation_fun = undefined} = State) -> - ?fatal_error(State, "Can't detect character encoding due to lack of indata"); + ?fatal_error(State, "Can't detect character encoding due to lack of indata"); detect_charset(<<>>, State) -> cf(<<>>, State, fun detect_charset/2); detect_charset(Bytes, State) -> @@ -269,22 +269,14 @@ detect_charset_1(<<16#3C, 16#3F, 16#78, 16#6D>> = Xml, State) -> cf(Xml, State, fun detect_charset_1/2); detect_charset_1(<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml2/binary>>, State) -> {Xml3, State1} = read_until_end_of_xml_directive(Xml2, State), - case parse_xml_directive(Xml3) of - {error, Reason} -> - ?fatal_error(State, Reason); - AttrList -> - case lists:keysearch("encoding", 1, AttrList) of - {value, {_, E}} -> - case convert_encoding(E) of - {error, Reason} -> - ?fatal_error(State, Reason); - Enc -> - {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>, - State1#xmerl_sax_parser_state{encoding=Enc}} - end; - _ -> - {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>, State1} - end + AttrList = parse_xml_directive(Xml3, State), + case lists:keysearch("encoding", 1, AttrList) of + {value, {_, E}} -> + Enc = convert_encoding(E, State), + {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>, + State1#xmerl_sax_parser_state{encoding=Enc}}; + _ -> + {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>, State1} end; detect_charset_1(Xml, State) -> {Xml, State}. @@ -295,7 +287,7 @@ detect_charset_1(Xml, State) -> %% Output: utf8 | iso8859 %% Description: Converting 7,8 bit and utf8 encoding strings to internal format. %%---------------------------------------------------------------------- -convert_encoding(Enc) -> %% Just for 7,8 bit + utf8 +convert_encoding(Enc, State) -> %% Just for 7,8 bit + utf8 case string:to_lower(Enc) of "utf-8" -> utf8; "us-ascii" -> utf8; @@ -309,19 +301,19 @@ convert_encoding(Enc) -> %% Just for 7,8 bit + utf8 "iso-8859-7" -> latin1; "iso-8859-8" -> latin1; "iso-8859-9" -> latin1; - _ -> {error, "Unknown encoding: " ++ Enc} + _ -> ?fatal_error(State, "Unknown encoding: " ++ Enc) end. %%---------------------------------------------------------------------- %% Function: parse_xml_directive(Xml) %% Input: Xml = binary() %% Acc = list() -%% Output: +%% Output: %% Description: Parsing the xml declaration from the input stream. %%---------------------------------------------------------------------- -parse_xml_directive(<<C, Rest/binary>>) when ?is_whitespace(C) -> - parse_xml_directive_1(Rest, []). - +parse_xml_directive(<<C, Rest/binary>>, State) when ?is_whitespace(C) -> + parse_xml_directive_1(Rest, [], State). + %%---------------------------------------------------------------------- %% Function: parse_xml_directive_1(Xml, Acc) -> [{Name, Value}] %% Input: Xml = binary() @@ -331,20 +323,20 @@ parse_xml_directive(<<C, Rest/binary>>) when ?is_whitespace(C) -> %% Output: see above %% Description: Parsing the xml declaration from the input stream. %%---------------------------------------------------------------------- -parse_xml_directive_1(<<C, Rest/binary>>, Acc) when ?is_whitespace(C) -> - parse_xml_directive_1(Rest, Acc); -parse_xml_directive_1(<<"?>", _/binary>>, Acc) -> +parse_xml_directive_1(<<C, Rest/binary>>, Acc, State) when ?is_whitespace(C) -> + parse_xml_directive_1(Rest, Acc, State); +parse_xml_directive_1(<<"?>", _/binary>>, Acc, _State) -> Acc; -parse_xml_directive_1(<<C, Rest/binary>>, Acc) when 97 =< C, C =< 122 -> +parse_xml_directive_1(<<C, Rest/binary>>, Acc, State) when 97 =< C, C =< 122 -> {Name, Rest1} = parse_name(Rest, [C]), - Rest2 = parse_eq(Rest1), - {Value, Rest3} = parse_value(Rest2), - parse_xml_directive_1(Rest3, [{Name, Value} |Acc]); -parse_xml_directive_1(_, _) -> - {error, "Unknown attribute in xml directive"}. + Rest2 = parse_eq(Rest1, State), + {Value, Rest3} = parse_value(Rest2, State), + parse_xml_directive_1(Rest3, [{Name, Value} |Acc], State); +parse_xml_directive_1(_, _, State) -> + ?fatal_error(State, "Unknown attribute in xml directive"). %%---------------------------------------------------------------------- -%% Function: parse_xml_directive_1(Xml, Acc) -> Name +%% Function: parse_name(Xml, Acc) -> Name %% Input: Xml = binary() %% Acc = string() %% Output: Name = string() @@ -361,10 +353,12 @@ parse_name(Rest, Acc) -> %% Output: Rest = binary() %% Description: Reads an '=' from the stream. %%---------------------------------------------------------------------- -parse_eq(<<C, Rest/binary>>) when ?is_whitespace(C) -> - parse_eq(Rest); -parse_eq(<<"=", Rest/binary>>) -> - Rest. +parse_eq(<<C, Rest/binary>>, State) when ?is_whitespace(C) -> + parse_eq(Rest, State); +parse_eq(<<"=", Rest/binary>>, _State) -> + Rest; +parse_eq(_, State) -> + ?fatal_error(State, "expecting = or whitespace"). %%---------------------------------------------------------------------- %% Function: parse_value(Xml) -> {Value, Rest} @@ -373,10 +367,12 @@ parse_eq(<<"=", Rest/binary>>) -> %% Rest = binary() %% Description: Parsing an attribute value from the stream. %%---------------------------------------------------------------------- -parse_value(<<C, Rest/binary>>) when ?is_whitespace(C) -> - parse_value(Rest); -parse_value(<<C, Rest/binary>>) when C == $'; C == $" -> - parse_value_1(Rest, C, []). +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(_, State) -> + ?fatal_error(State, "\', \" or whitespace expected"). %%---------------------------------------------------------------------- %% Function: parse_value_1(Xml, Stop, Acc) -> {Value, Rest} @@ -431,7 +427,7 @@ read_until_end_of_xml_directive(Rest, State) -> nomatch -> case cf(Rest, State) of {<<>>, _} -> - ?fatal_error(State, "Can't detect character encoding due to lack of indata"); + ?fatal_error(State, "Can't detect character encoding due to lack of indata"); {NewBytes, NewState} -> read_until_end_of_xml_directive(NewBytes, NewState) end; @@ -450,9 +446,9 @@ read_until_end_of_xml_directive(Rest, State) -> %% input stream and calls the fun in NextCall. %%---------------------------------------------------------------------- cf(_Rest, #xmerl_sax_parser_state{continuation_fun = undefined} = State) -> - ?fatal_error(State, "Continuation function undefined"); + ?fatal_error(State, "Continuation function undefined"); cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = CState} = State) -> - Result = + Result = try CFun(CState) catch @@ -463,9 +459,9 @@ cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = C end, case Result of {<<>>, _} -> - ?fatal_error(State, "Can't detect character encoding due to lack of indata"); + ?fatal_error(State, "Can't detect character encoding due to lack of indata"); {NewBytes, NewContState} -> - {<<Rest/binary, NewBytes/binary>>, + {<<Rest/binary, NewBytes/binary>>, State#xmerl_sax_parser_state{continuation_state = NewContState}} end. @@ -479,10 +475,10 @@ cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = C %% input stream and calls the fun in NextCall. %%---------------------------------------------------------------------- cf(_Rest, #xmerl_sax_parser_state{continuation_fun = undefined} = State, _) -> - ?fatal_error(State, "Continuation function undefined"); -cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = CState} = State, + ?fatal_error(State, "Continuation function undefined"); +cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = CState} = State, NextCall) -> - Result = + Result = try CFun(CState) catch @@ -493,8 +489,8 @@ cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = C end, case Result of {<<>>, _} -> - ?fatal_error(State, "Can't detect character encoding due to lack of indata"); + ?fatal_error(State, "Can't detect character encoding due to lack of indata"); {NewBytes, NewContState} -> - NextCall(<<Rest/binary, NewBytes/binary>>, + NextCall(<<Rest/binary, NewBytes/binary>>, State#xmerl_sax_parser_state{continuation_state = NewContState}) end. diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk index 3a266a56bd..b6486681c2 100644 --- a/lib/xmerl/vsn.mk +++ b/lib/xmerl/vsn.mk @@ -1 +1 @@ -XMERL_VSN = 1.3.18 +XMERL_VSN = 1.3.19 |