diff options
Diffstat (limited to 'lib/kernel')
36 files changed, 1280 insertions, 144 deletions
diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile index f8867ccf25..70623ab9aa 100644 --- a/lib/kernel/doc/src/Makefile +++ b/lib/kernel/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2018. All Rights Reserved. +# Copyright Ericsson AB 1997-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. @@ -36,6 +36,18 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # Target Specs # ---------------------------------------------------- XML_APPLICATION_FILES = ref_man.xml + +# The doc build has problems with if-defing out modules... +ifeq ($(USE_ESOCK),yes) +XML_REF3_ESOCK_FILES = net.xml +ESOCK_USE_NET_XML=<xi:include href="net.xml"\/> +ESOCK_USE_NET_SPECS_XML=<xi:include href="../specs/specs_net.xml"/> +else +XML_REF3_ESOCK_FILES = +ESOCK_USE_NET_SPECS_XML = +ESOCK_USE_NET_XML = +endif + XML_REF3_FILES = application.xml \ auth.xml \ code.xml \ @@ -62,6 +74,7 @@ XML_REF3_FILES = application.xml \ logger_disk_log_h.xml \ logger_filters.xml \ logger_formatter.xml \ + $(XML_REF3_ESOCK_FILES) \ net_adm.xml \ net_kernel.xml \ os.xml \ @@ -112,6 +125,7 @@ SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml) TOP_SPECS_FILE = specs.xml + # ---------------------------------------------------- # FIGURES # ---------------------------------------------------- @@ -138,7 +152,7 @@ SPECS_FLAGS = -I../../include $(HTMLDIR)/%: % $(INSTALL_DATA) $< $@ -docs: man pdf html +docs: ref_man specs man pdf html $(TOP_PDF_FILE): $(XML_FILES) @@ -148,19 +162,32 @@ html: images $(HTML_REF_MAN_FILE) man: $(MAN3_FILES) $(MAN4_FILES) $(MAN6_FILES) +ref_man: ref_man.xml +specs: specs.xml + images: $(IMAGE_FILES:%=$(HTMLDIR)/%) +info: + @echo "XML_APPLICATION_FILES: $(XML_APPLICATION_FILES)" + @echo "XML_REF3_ESOCK_FILES: $(XML_REF3_ESOCK_FILES)" + @echo "XML_REF3_FILES: $(XML_REF3_FILES)" + @echo "XML_REF4_FILES: $(XML_REF4_FILES)" + @echo "XML_REF6_FILES: $(XML_REF6_FILES)" + @echo "XML_PART_FILES: $(XML_PART_FILES)" + @echo "XML_CHAPTER_FILES: $(XML_CHAPTER_FILES)" + @echo "BOOK_FILES: $(BOOK_FILES)" + debug opt: clean clean_docs: rm -rf $(HTMLDIR)/* rm -rf $(XMLDIR) - rm -f $(MAN3DIR)/* - rm -f $(MAN4DIR)/* - rm -f $(MAN6DIR)/* - rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) - rm -f $(SPECDIR)/* - rm -f errs core *~ *.eps + rm -f $(MAN3DIR)/* + rm -f $(MAN4DIR)/* + rm -f $(MAN6DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f $(SPECDIR)/* + rm -f errs core *~ *.eps $(SPECDIR)/specs_erl_prim_loader_stub.xml: $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ @@ -175,6 +202,14 @@ $(SPECDIR)/specs_zlib_stub.xml: $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ -o$(dir $@) -module zlib_stub +ref_man.xml: ref_man.xml.src + ($(PERL) -p -e 's?%ESOCK_USE_NET_XML%?$(ESOCK_USE_NET_XML)?' \ + $<) > $@ +specs.xml: specs.xml.src + ($(PERL) -p -e 's?%ESOCK_USE_NET_SPECS_XML%?$(ESOCK_USE_NET_SPECS_XML)?' \ + $<) > $@ + + # ---------------------------------------------------- # Release Target # ---------------------------------------------------- diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml index d20fc1fdfd..6c0d072fed 100644 --- a/lib/kernel/doc/src/gen_udp.xml +++ b/lib/kernel/doc/src/gen_udp.xml @@ -213,12 +213,93 @@ </func> <func> - <name name="send" arity="4" since=""/> + <name name="send" arity="3" since="OTP @OTP-15747@"/> <fsummary>Send a packet.</fsummary> <desc> <p> - Sends a packet to the specified address and port. Argument - <c><anno>Address</anno></c> can be a hostname or a socket address. + Sends a packet to the specified <c><anno>Destination</anno></c>. + </p> + <p> + This function is equivalent to + <seealso marker="#send-4-AncData"><c>send(<anno>Socket</anno>, <anno>Destination</anno>, [], <anno>Packet</anno>)</c></seealso>. + </p> + </desc> + </func> + + <func> + <name name="send" arity="4" clause_i="1" since=""/> + <fsummary>Send a packet.</fsummary> + <desc> + <p> + Sends a packet to the specified <c><anno>Host</anno></c> + and <c><anno>Port</anno></c>. + </p> + <p> + This clause is equivalent to + <seealso marker="#send/5"><c>send(<anno>Socket</anno>, <anno>Host</anno>, <anno>Port</anno>, [], <anno>Packet</anno>)</c></seealso>. + </p> + </desc> + </func> + + <func> + <name name="send" arity="4" clause_i="2" anchor="send-4-AncData" since="OTP @OTP-15747@"/> + <fsummary>Send a packet.</fsummary> + <desc> + <p> + Sends a packet to the specified <c><anno>Destination</anno></c> + with ancillary data <c><anno>AncData</anno></c>. + </p> + <note> + <p> + The ancillary data <c><anno>AncData</anno></c> + contains options that for this single message + override the default options for the socket, + an operation that may not be supported on all platforms, + and if so return <c>{error, einval}</c>. + Using more than one of an ancillary data item type + may also not be supported. + <c><anno>AncData</anno> =:= []</c> is always supported. + </p> + </note> + </desc> + </func> + + <func> + <name name="send" arity="4" clause_i="3" since="OTP @OTP-15747@"/> + <fsummary>Send a packet.</fsummary> + <desc> + <p> + Sends a packet to the specified <c><anno>Destination</anno></c>. + Since <c><anno>Destination</anno></c> is complete, + <c><anno>PortZero</anno></c> is redundant and has to be <c>0</c>. + </p> + <p> + This is a legacy clause mostly for + <c><anno>Destination</anno> = {local, Binary}</c> + where <c><anno>PortZero</anno></c> is superfluous. + It is equivalent to + <seealso marker="#send-4-AncData"><c>send(<anno>Socket</anno>, <anno>Destination</anno>, [], <anno>Packet</anno>)</c></seealso>, the clause right above here. + </p> + </desc> + </func> + + <func> + <name name="send" arity="5" since="OTP @OTP-15747@"/> + <fsummary>Send a packet.</fsummary> + <desc> + <p> + Sends a packet to the specified <c><anno>Host</anno></c> + and <c><anno>Port</anno></c>, + with ancillary data <c><anno>AncData</anno></c>. + </p> + <p> + Argument <c><anno>Host</anno></c> can be + a hostname or a socket address, + and <c><anno>Port</anno></c> can be a port number + or a service name atom. + These are resolved into a <c>Destination</c> and after that + this function is equivalent to + <seealso marker="#send-4-AncData"><c>send(<anno>Socket</anno>, Destination, <anno>AncData</anno>, <anno>Packet</anno>)</c></seealso>, read there about ancillary data. </p> </desc> </func> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index d4678ca5db..1011befca0 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -118,6 +118,42 @@ fe80::204:acff:fe17:bf38 <name name="port_number"/> </datatype> <datatype> + <name name="family_address" since="OTP @OTP-15747@"/> + <desc> + <p> + A general address format on the form <c>{Family, Destination}</c> + where <c>Family</c> is an atom such as <c>local</c> + and the format of <c>Destination</c> depends on <c>Family</c>, + and is a complete address + (for example an IP address including port number). + </p> + </desc> + </datatype> + <datatype> + <name name="inet_address" since="OTP @OTP-15747@"/> + <desc> + <warning> + <p> + This address format is for now experimental + and for completeness to make all address families have a + <c>{Family, Destination}</c> representation. + </p> + </warning> + </desc> + </datatype> + <datatype> + <name name="inet6_address" since="OTP @OTP-15747@"/> + <desc> + <warning> + <p> + This address format is for now experimental + and for completeness to make all address families have a + <c>{Family, Destination}</c> representation. + </p> + </warning> + </desc> + </datatype> + <datatype> <name name="local_address"/> <desc> <p> @@ -180,12 +216,16 @@ fe80::204:acff:fe17:bf38 <name name="ancillary_data"/> <desc> <p> - Ancillary data received with the data packet - or read with the socket option + Ancillary data received with the data packet, + read with the socket option <seealso marker="gen_tcp#type-pktoptions_value"> <c>pktoptions</c> </seealso> - from a TCP socket. + from a TCP socket, + or to set in a call to + <seealso marker="gen_udp#send-4-AncData"><c>gen_udp:send/4</c></seealso> + or + <seealso marker="gen_udp#send/5"><c>gen_udp:send/5</c></seealso>. </p> <p> The value(s) correspond to the currently active socket @@ -193,7 +233,9 @@ fe80::204:acff:fe17:bf38 <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>, <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso> and - <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>. + <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>, + or for a single send operation the option(s) to override + the currently active socket option(s). </p> </desc> </datatype> diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml index 1aa4b7a3a2..5aa2caadf0 100644 --- a/lib/kernel/doc/src/logger_chapter.xml +++ b/lib/kernel/doc/src/logger_chapter.xml @@ -89,8 +89,8 @@ <p>Filter functions can be used for more sophisticated filtering than the log level check provides. A filter function can stop or pass a log event, based on any of the event's contents. It can - also modify all parts of the log event. See see - section <seealso marker="#filters">Filters</seealso> for more + also modify all parts of the log event. See section + <seealso marker="#filters">Filters</seealso> for more details.</p> <p>If a log event passes through all primary filters and all handler filters for a specific handler, Logger forwards the diff --git a/lib/kernel/doc/src/logger_disk_log_h.xml b/lib/kernel/doc/src/logger_disk_log_h.xml index aa577f3c62..3d8e82ce7c 100644 --- a/lib/kernel/doc/src/logger_disk_log_h.xml +++ b/lib/kernel/doc/src/logger_disk_log_h.xml @@ -133,7 +133,7 @@ logger:add_handler(my_disk_log_h, logger_disk_log_h, #{config => #{file => "./my_disk_log", type => wrap, max_no_files => 4, - max_no_bytes => 10000}, + max_no_bytes => 10000, filesync_repeat_interval => 1000}}). </code> <p>To use the disk_log handler instead of the default standard diff --git a/lib/kernel/doc/src/net.xml b/lib/kernel/doc/src/net.xml new file mode 100644 index 0000000000..6fbc37076c --- /dev/null +++ b/lib/kernel/doc/src/net.xml @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2018</year><year>2018</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>net</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>net.xml</file> + </header> + <module since="OTP 22.0">net</module> + <modulesummary>Network interface.</modulesummary> + <description> + <p>This module provides an API for the network interface.</p> + <note> + <p>There is currently <em>no</em> support for Windows. </p> + </note> + </description> + + <datatypes> + <datatype> + <name name="address_info"/> + </datatype> + <datatype> + <name name="name_info"/> + </datatype> + <datatype> + <name name="name_info_flags"/> + </datatype> + <datatype> + <name name="name_info_flag"/> + </datatype> + <datatype> + <name name="name_info_flag_ext"/> + </datatype> + <datatype> + <name name="network_interface_name"/> + </datatype> + <datatype> + <name name="network_interface_index"/> + </datatype> + </datatypes> + + <funcs> + <func> + <name name="gethostname" arity="0"/> + <fsummary>Get hostname.</fsummary> + <desc> + <p>Returns the name of the current host.</p> + </desc> + </func> + + <func> + <name name="getnameinfo" arity="1" since="OTP 22.0"/> + <name name="getnameinfo" arity="2" since="OTP 22.0"/> + <fsummary>Address-to-name transaltion.</fsummary> + <desc> + <p>Address-to-name translation in a protocol-independant manner.</p> + <p>This function is the inverse of + <seealso marker="#getaddrinfo/1"><c>getaddrinfo</c></seealso>. + It converts a socket address to a corresponding host and service.</p> + </desc> + </func> + + <func> + <name name="getaddrinfo" arity="1" since="OTP 22.0"/> + <name name="getaddrinfo" arity="2" clause_i="1" since="OTP 22.0"/> + <name name="getaddrinfo" arity="2" clause_i="2" since="OTP 22.0"/> + <name name="getaddrinfo" arity="2" clause_i="3" since="OTP 22.0"/> + <fsummary>Network address and service transation.</fsummary> + <desc> + <p>Network address and service translation.</p> + <p>This function is the inverse of + <seealso marker="#getnameinfo/1"><c>getnameinfo</c></seealso>. + It converts host and service to a corresponding socket address.</p> + <p>One of the <c>Host</c> and <c>Service</c> may be <c>undefined</c> + but <em>not</em> both.</p> + </desc> + </func> + + <func> + <name name="if_name2index" arity="1" since="OTP 22.0"/> + <fsummary>Mappings between network interface names and indexes.</fsummary> + <desc> + <p>Mappings between network interface names and indexes.</p> + </desc> + </func> + + <func> + <name name="if_index2name" arity="1" since="OTP 22.0"/> + <fsummary>Mappings between network interface index and names.</fsummary> + <desc> + <p>Mappings between network interface index and names.</p> + </desc> + </func> + + <func> + <name name="if_names" arity="0" since="OTP 22.0"/> + <fsummary>Get network interface names and indexes.</fsummary> + <desc> + <p>Get network interface names and indexes.</p> + </desc> + </func> + + </funcs> + +</erlref> + diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index 6f68a67174..4d31eeea3d 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -31,6 +31,24 @@ </header> <p>This document describes the changes made to the Kernel application.</p> +<section><title>Kernel 6.4.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p><c>user</c>/<c>user_drv</c> could respond to io + requests before they had been processed, which could + cause data to be dropped if the emulator was halted soon + after a call to <c>io:format/2</c>, such as in an + escript.</p> + <p> + Own Id: OTP-15805</p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 6.4</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -129,6 +147,37 @@ </section> +<section><title>Kernel 6.3.1.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The possibility to send ancillary data, in particular the + TOS field, has been added to <c>gen_udp:send/4,5</c>.</p> + <p> + Own Id: OTP-15747 Aux Id: ERIERL-294 </p> + </item> + </list> + </section> + +</section> + +<section><title>Kernel 6.3.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix type spec for <c>seq_trace:set_token/2</c>.</p> + <p> + Own Id: OTP-15858 Aux Id: ERL-700 </p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 6.3.1</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -6027,4 +6076,3 @@ </section> </section> </chapter> - diff --git a/lib/kernel/doc/src/ref_man.xml b/lib/kernel/doc/src/ref_man.xml.src index d3b947527f..72e3409123 100644 --- a/lib/kernel/doc/src/ref_man.xml +++ b/lib/kernel/doc/src/ref_man.xml.src @@ -4,7 +4,7 @@ <application xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>1996</year><year>2018</year> + <year>1996</year><year>2019</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -60,6 +60,7 @@ <xi:include href="logger_formatter.xml"/> <xi:include href="logger_std_h.xml"/> <xi:include href="logger_disk_log_h.xml"/> + %ESOCK_USE_NET_XML% <xi:include href="net_adm.xml"/> <xi:include href="net_kernel.xml"/> <xi:include href="os.xml"/> diff --git a/lib/kernel/doc/src/specs.xml b/lib/kernel/doc/src/specs.xml.src index b8c25ca53b..ccb26b9458 100644 --- a/lib/kernel/doc/src/specs.xml +++ b/lib/kernel/doc/src/specs.xml.src @@ -26,6 +26,7 @@ <xi:include href="../specs/specs_logger_formatter.xml"/> <xi:include href="../specs/specs_logger_std_h.xml"/> <xi:include href="../specs/specs_logger_disk_log_h.xml"/> + %ESOCK_USE_NET_SPECS_XML% <xi:include href="../specs/specs_net_adm.xml"/> <xi:include href="../specs/specs_net_kernel.xml"/> <xi:include href="../specs/specs_os.xml"/> diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile index fcb599859b..88752431eb 100644 --- a/lib/kernel/src/Makefile +++ b/lib/kernel/src/Makefile @@ -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. @@ -123,6 +123,7 @@ MODULES = \ logger_server \ logger_simple_h \ logger_sup \ + net \ net_adm \ net_kernel \ os \ @@ -180,6 +181,7 @@ ERL_COMPILE_FLAGS += -Werror endif ERL_COMPILE_FLAGS += -I../include + # ---------------------------------------------------- # Targets # ---------------------------------------------------- diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index 7faef93609..964ede9bc9 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -19,6 +19,8 @@ %% -module(code). +-include_lib("kernel/include/logger.hrl"). + %% This is the interface module to the code server. It also contains %% some implementation details. See also related modules: code_*.erl %% in this directory. @@ -707,8 +709,20 @@ do_s(Lib) -> start_get_mode() -> case init:get_argument(mode) of - {ok,[["embedded"]]} -> - embedded; + {ok, [FirstMode | Rest]} -> + case Rest of + [] -> + ok; + _ -> + ?LOG_WARNING("Multiple -mode given to erl, using the first, ~p", + [FirstMode]) + end, + case FirstMode of + ["embedded"] -> + embedded; + _ -> + interactive + end; _ -> interactive end. diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index d893d44079..a63df54ff9 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -217,24 +217,29 @@ peeloff(S, AssocId) when is_port(S), is_integer(AssocId) -> Error -> Error end. --spec connect(Socket, Addr, Port, Opts) -> {ok, Assoc} | {error, inet:posix()} when +-spec connect(Socket, Addr, Port, Opts) -> + {ok, #sctp_assoc_change{state :: 'comm_up'}} | + {error, #sctp_assoc_change{state :: 'cant_assoc'}} | + {error, inet:posix()} + when Socket :: sctp_socket(), Addr :: inet:ip_address() | inet:hostname(), Port :: inet:port_number(), - Opts :: [Opt :: option()], - Assoc :: #sctp_assoc_change{}. + Opts :: [Opt :: option()]. connect(S, Addr, Port, Opts) -> connect(S, Addr, Port, Opts, infinity). -spec connect(Socket, Addr, Port, Opts, Timeout) -> - {ok, Assoc} | {error, inet:posix()} when + {ok, #sctp_assoc_change{state :: 'comm_up'}} | + {error, #sctp_assoc_change{state :: 'cant_assoc'}} | + {error, inet:posix()} + when Socket :: sctp_socket(), Addr :: inet:ip_address() | inet:hostname(), Port :: inet:port_number(), Opts :: [Opt :: option()], - Timeout :: timeout(), - Assoc :: #sctp_assoc_change{}. + Timeout :: timeout(). connect(S, Addr, Port, Opts, Timeout) -> case do_connect(S, Addr, Port, Opts, Timeout, true) of diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl index fad7b2f887..3001948209 100644 --- a/lib/kernel/src/gen_udp.erl +++ b/lib/kernel/src/gen_udp.erl @@ -20,7 +20,7 @@ -module(gen_udp). -export([open/1, open/2, close/1]). --export([send/2, send/4, recv/2, recv/3, connect/3]). +-export([send/2, send/3, send/4, send/5, recv/2, recv/3, connect/3]). -export([controlling_process/2]). -export([fdopen/2]). @@ -125,20 +125,80 @@ open(Port, Opts0) -> close(S) -> inet:udp_close(S). --spec send(Socket, Address, Port, Packet) -> ok | {error, Reason} when +-spec send(Socket, Destination, Packet) -> ok | {error, Reason} when Socket :: socket(), - Address :: inet:socket_address() | inet:hostname(), - Port :: inet:port_number(), + Destination :: {inet:ip_address(), inet:port_number()} | + inet:family_address(), + Packet :: iodata(), + Reason :: not_owner | inet:posix(). +%%% +send(Socket, Destination, Packet) -> + send(Socket, Destination, [], Packet). + +-spec send(Socket, Host, Port, Packet) -> ok | {error, Reason} when + Socket :: socket(), + Host :: inet:hostname() | inet:ip_address(), + Port :: inet:port_number() | atom(), + Packet :: iodata(), + Reason :: not_owner | inet:posix(); +%%% + (Socket, Destination, AncData, Packet) -> ok | {error, Reason} when + Socket :: socket(), + Destination :: {inet:ip_address(), inet:port_number()} | + inet:family_address(), + AncData :: inet:ancillary_data(), + Packet :: iodata(), + Reason :: not_owner | inet:posix(); +%%% + (Socket, Destination, PortZero, Packet) -> ok | {error, Reason} when + Socket :: socket(), + Destination :: {inet:ip_address(), inet:port_number()} | + inet:family_address(), + PortZero :: inet:port_number(), Packet :: iodata(), Reason :: not_owner | inet:posix(). +%%% +send(S, {_,_} = Destination, PortZero = AncData, Packet) when is_port(S) -> + %% Destination is {Family,Addr} | {IP,Port}, + %% so it is complete - argument PortZero is redundant + if + PortZero =:= 0 -> + case inet_db:lookup_socket(S) of + {ok, Mod} -> + Mod:send(S, Destination, [], Packet); + Error -> + Error + end; + is_integer(PortZero) -> + %% Redundant PortZero; must be 0 + {error, einval}; + is_list(AncData) -> + case inet_db:lookup_socket(S) of + {ok, Mod} -> + Mod:send(S, Destination, AncData, Packet); + Error -> + Error + end + end; +send(S, Host, Port, Packet) when is_port(S) -> + send(S, Host, Port, [], Packet). -send(S, Address, Port, Packet) when is_port(S) -> +-spec send(Socket, Host, Port, AncData, Packet) -> ok | {error, Reason} when + Socket :: socket(), + Host :: inet:hostname() | inet:ip_address() | inet:local_address(), + Port :: inet:port_number() | atom(), + AncData :: inet:ancillary_data(), + Packet :: iodata(), + Reason :: not_owner | inet:posix(). +%%% +send(S, Host, Port, AncData, Packet) + when is_port(S), is_list(AncData) -> case inet_db:lookup_socket(S) of {ok, Mod} -> - case Mod:getaddr(Address) of + case Mod:getaddr(Host) of {ok,IP} -> case Mod:getserv(Port) of - {ok,UP} -> Mod:send(S, IP, UP, Packet); + {ok,P} -> Mod:send(S, {IP,P}, AncData, Packet); {error,einval} -> exit(badarg); Error -> Error end; @@ -149,6 +209,7 @@ send(S, Address, Port, Packet) when is_port(S) -> Error end. +%% Connected send send(S, Packet) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 9f22eb6aaa..24aff83fbd 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -75,7 +75,8 @@ -export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0, ip6_address/0, ip_address/0, port_number/0, - local_address/0, socket_address/0, returned_non_ip_address/0, + family_address/0, local_address/0, + socket_address/0, returned_non_ip_address/0, socket_setopt/0, socket_getopt/0, ancillary_data/0, posix/0, socket/0, stat_option/0]). %% imports @@ -100,11 +101,16 @@ 0..65535,0..65535,0..65535,0..65535}. -type ip_address() :: ip4_address() | ip6_address(). -type port_number() :: 0..65535. --type local_address() :: {local, File :: binary() | string()}. +-type family_address() :: inet_address() | inet6_address() | local_address(). +-type inet_address() :: + {'inet', {ip4_address() | 'any' | 'loopback', port_number()}}. +-type inet6_address() :: + {'inet6', {ip6_address() | 'any' | 'loopback', port_number()}}. +-type local_address() :: {'local', File :: binary() | string()}. -type returned_non_ip_address() :: - {local, binary()} | - {unspec, <<>>} | - {undefined, any()}. + {'local', binary()} | + {'unspec', <<>>} | + {'undefined', any()}. -type posix() :: 'eaddrinuse' | 'eaddrnotavail' | 'eafnosupport' | 'ealready' | 'econnaborted' | 'econnrefused' | 'econnreset' | @@ -1639,6 +1645,7 @@ fmt_addr({ok,Addr}, Proto) -> {{0,0,0,0,0,0,0,0},Port} -> "*:" ++ fmt_port(Port, Proto); {{127,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto); {{0,0,0,0,0,0,0,1},Port} -> "localhost:" ++ fmt_port(Port, Proto); + {local, Path} -> "local:" ++ binary_to_list(Path); {IP,Port} -> inet_parse:ntoa(IP) ++ ":" ++ fmt_port(Port, Proto) end. diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl index 71db0357cd..cb95a69798 100644 --- a/lib/kernel/src/inet6_udp.erl +++ b/lib/kernel/src/inet6_udp.erl @@ -65,16 +65,25 @@ open(Port, Opts) -> {ok, _} -> exit(badarg) end. -send(S, Addr = {A,B,C,D,E,F,G,H}, P, Data) - when ?ip6(A,B,C,D,E,F,G,H), ?port(P) -> - prim_inet:sendto(S, Addr, P, Data). +send(S, {A,B,C,D,E,F,G,H} = IP, Port, Data) + when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) -> + prim_inet:sendto(S, {IP, Port}, [], Data); +send(S, {{A,B,C,D,E,F,G,H}, Port} = Addr, AncData, Data) + when ?ip6(A,B,C,D,E,F,G,H), ?port(Port), is_list(AncData) -> + prim_inet:sendto(S, Addr, AncData, Data); +send(S, {?FAMILY, {{A,B,C,D,E,F,G,H}, Port}} = Address, AncData, Data) + when ?ip6(A,B,C,D,E,F,G,H), ?port(Port), is_list(AncData) -> + prim_inet:sendto(S, Address, AncData, Data); +send(S, {?FAMILY, {loopback, Port}} = Address, AncData, Data) + when ?port(Port), is_list(AncData) -> + prim_inet:sendto(S, Address, AncData, Data). send(S, Data) -> - prim_inet:sendto(S, {0,0,0,0,0,0,0,0}, 0, Data). + prim_inet:sendto(S, {any, 0}, [], Data). -connect(S, Addr = {A,B,C,D,E,F,G,H}, P) - when ?ip6(A,B,C,D,E,F,G,H), ?port(P) -> - prim_inet:connect(S, Addr, P). +connect(S, Addr = {A,B,C,D,E,F,G,H}, Port) + when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) -> + prim_inet:connect(S, Addr, Port). recv(S, Len) -> prim_inet:recvfrom(S, Len). diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl index 1e624b9e90..083059a2dc 100644 --- a/lib/kernel/src/inet_udp.erl +++ b/lib/kernel/src/inet_udp.erl @@ -66,16 +66,25 @@ open(Port, Opts) -> {ok, _} -> exit(badarg) end. -send(S, {A,B,C,D} = Addr, P, Data) - when ?ip(A,B,C,D), ?port(P) -> - prim_inet:sendto(S, Addr, P, Data). +send(S, {A,B,C,D} = IP, Port, Data) + when ?ip(A,B,C,D), ?port(Port) -> + prim_inet:sendto(S, {IP, Port}, [], Data); +send(S, {{A,B,C,D}, Port} = Addr, AncData, Data) + when ?ip(A,B,C,D), ?port(Port), is_list(AncData) -> + prim_inet:sendto(S, Addr, AncData, Data); +send(S, {?FAMILY, {{A,B,C,D}, Port}} = Address, AncData, Data) + when ?ip(A,B,C,D), ?port(Port), is_list(AncData) -> + prim_inet:sendto(S, Address, AncData, Data); +send(S, {?FAMILY, {loopback, Port}} = Address, AncData, Data) + when ?port(Port), is_list(AncData) -> + prim_inet:sendto(S, Address, AncData, Data). send(S, Data) -> - prim_inet:sendto(S, {0,0,0,0}, 0, Data). + prim_inet:sendto(S, {any, 0}, [], Data). -connect(S, Addr = {A,B,C,D}, P) - when ?ip(A,B,C,D), ?port(P) -> - prim_inet:connect(S, Addr, P). +connect(S, Addr = {A,B,C,D}, Port) + when ?ip(A,B,C,D), ?port(Port) -> + prim_inet:connect(S, Addr, Port). recv(S, Len) -> prim_inet:recvfrom(S, Len). diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src index 8fe6bdd1ca..c2ff6b63e9 100644 --- a/lib/kernel/src/kernel.app.src +++ b/lib/kernel/src/kernel.app.src @@ -74,6 +74,7 @@ logger_simple_h, logger_std_h, logger_sup, + net, net_adm, net_kernel, os, diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index cd0397a98c..95853a7a8f 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -38,7 +38,9 @@ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, {<<"^6\\.3$">>,[restart_new_emulator]}, {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^6\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}], + {<<"^6\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^6\\.4$">>,[restart_new_emulator]}, + {<<"^6\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}], [{<<"^6\\.0$">>,[restart_new_emulator]}, {<<"^6\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, {<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, @@ -50,4 +52,6 @@ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, {<<"^6\\.3$">>,[restart_new_emulator]}, {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^6\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}. + {<<"^6\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^6\\.4$">>,[restart_new_emulator]}, + {<<"^6\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}. diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl index bfa091a036..c8c631ab23 100644 --- a/lib/kernel/src/kernel.erl +++ b/lib/kernel/src/kernel.erl @@ -116,7 +116,7 @@ init([]) -> restart => temporary, shutdown => 2000, type => supervisor, - modules => [user_sup]}, + modules => [standard_error]}, User = #{id => user, start => {user_sup, start, []}, @@ -141,7 +141,7 @@ init([]) -> modules => [logger_sup]}, case init:get_argument(mode) of - {ok, [["minimal"]]} -> + {ok, [["minimal"]|_]} -> {ok, {SupFlags, [Code, File, StdError, User, LoggerSup, Config, RefC, SafeSup]}}; _ -> diff --git a/lib/kernel/src/local_udp.erl b/lib/kernel/src/local_udp.erl index 481a8c4910..933e56228b 100644 --- a/lib/kernel/src/local_udp.erl +++ b/lib/kernel/src/local_udp.erl @@ -70,11 +70,13 @@ open(0, Opts) -> {ok, _} -> exit(badarg) end. -send(S, Addr = {?FAMILY,_}, 0, Data) -> - prim_inet:sendto(S, Addr, 0, Data). +send(S, {?FAMILY,_} = Addr, 0, Data) -> + prim_inet:sendto(S, Addr, [], Data); +send(S, {?FAMILY,_} = Addr, AncData, Data) when is_list(AncData) -> + prim_inet:sendto(S, Addr, AncData, Data). %% send(S, Data) -> - prim_inet:sendto(S, {?FAMILY,<<>>}, 0, Data). + prim_inet:sendto(S, {?FAMILY,<<>>}, [], Data). connect(S, Addr = {?FAMILY,_}, 0) -> prim_inet:connect(S, Addr, 0). diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl index c8f1acfca4..2b078ef091 100644 --- a/lib/kernel/src/logger_std_h.erl +++ b/lib/kernel/src/logger_std_h.erl @@ -170,9 +170,11 @@ check_h_config(_Type,[]) -> ok. normalize_config(#{type:={file,File}}=HConfig) -> - HConfig#{type=>file,file=>File}; + normalize_config(HConfig#{type=>file,file=>File}); normalize_config(#{type:={file,File,Modes}}=HConfig) -> - HConfig#{type=>file,file=>File,modes=>Modes}; + normalize_config(HConfig#{type=>file,file=>File,modes=>Modes}); +normalize_config(#{file:=File}=HConfig) -> + HConfig#{file=>filename:absname(File)}; normalize_config(HConfig) -> HConfig. @@ -188,7 +190,7 @@ merge_default_config(Name,Type,HConfig) -> get_default_config(Name,file) -> #{type => file, - file => atom_to_list(Name), + file => filename:absname(atom_to_list(Name)), modes => [raw,append], file_check => 0, max_no_bytes => infinity, diff --git a/lib/kernel/src/net.erl b/lib/kernel/src/net.erl new file mode 100644 index 0000000000..b8ffa64043 --- /dev/null +++ b/lib/kernel/src/net.erl @@ -0,0 +1,324 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-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% +%% + +-module(net). + +%% We should really ifdef this module depending on if we actually built +%% the system with esock support (socket and prim_net), but our doc-building +%% can't handle the "variables" we need (USE_ESOCK). So instead, we just +%% leave everything hanging... +%% If one of the "hanging" functions is called when esock has been disabled, +%% the function will through a 'notsup' error (erlang:error/1). + +%% Administrative and utility functions +-export([ + info/0, + command/1 + ]). + +-export([ + gethostname/0, + getnameinfo/1, getnameinfo/2, + getaddrinfo/1, getaddrinfo/2, + + if_name2index/1, + if_index2name/1, + if_names/0 + ]). + +%% Deprecated functions from the "old" net module +-export([call/4, + cast/4, + broadcast/3, + ping/1, + relay/1, + sleep/1]). + +%% Should we define these here or refer to the prim_net module +-export_type([ + address_info/0, + name_info/0, + + name_info_flags/0, + name_info_flag/0, + name_info_flag_ext/0, + + network_interface_name/0, + network_interface_index/0 + ]). + + +-deprecated({call, 4, eventually}). +-deprecated({cast, 4, eventually}). +-deprecated({broadcast, 3, eventually}). +-deprecated({ping, 1, eventually}). +-deprecated({relay, 1, eventually}). +-deprecated({sleep, 1, eventually}). + + +-type name_info_flags() :: [name_info_flag()|name_info_flag_ext()]. +-type name_info_flag() :: namereqd | + dgram | + nofqdn | + numerichost | + nomericserv. +-type name_info_flag_ext() :: idn | + idna_allow_unassigned | + idna_use_std3_ascii_rules. +-type name_info() :: #{host := string(), + service := string()}. +-type address_info() :: #{family := socket:domain(), + socktype := socket:type(), + protocol := socket:protocol(), + address := socket:sockaddr()}. +-type network_interface_name() :: string(). +-type network_interface_index() :: non_neg_integer(). + + +%% =========================================================================== +%% +%% D E P R E C A T E D F U N C T I O N S +%% +%% =========================================================================== + +call(N,M,F,A) -> rpc:call(N,M,F,A). +cast(N,M,F,A) -> rpc:cast(N,M,F,A). +broadcast(M,F,A) -> rpc:eval_everywhere(M,F,A). +ping(Node) -> net_adm:ping(Node). +sleep(T) -> receive after T -> ok end. +relay(X) -> slave:relay(X). + + +%% =========================================================================== +%% +%% Administrative and utility API +%% +%% =========================================================================== + +-spec info() -> list(). + +-ifdef(USE_ESOCK). +info() -> + prim_net:info(). +-else. +-dialyzer({nowarn_function, info/0}). +info() -> + erlang:error(notsup). +-endif. + + +-spec command(Cmd :: term()) -> term(). + +-ifdef(USE_ESOCK). +command(Cmd) -> + prim_net:command(Cmd). +-else. +-dialyzer({nowarn_function, command/1}). +command(_Cmd) -> + erlang:error(notsup). +-endif. + + + +%% =========================================================================== +%% +%% The proper net API +%% +%% =========================================================================== + +%% =========================================================================== +%% +%% gethostname - Get the name of the current host. +%% +%% + +-spec gethostname() -> {ok, HostName} | {error, Reason} when + HostName :: string(), + Reason :: term(). + +-ifdef(USE_ESOCK). +gethostname() -> + prim_net:gethostname(). +-else. +-dialyzer({nowarn_function, gethostname/0}). +gethostname() -> + erlang:error(notsup). +-endif. + + +%% =========================================================================== +%% +%% getnameinfo - Address-to-name translation in protocol-independent manner. +%% +%% + +-spec getnameinfo(SockAddr) -> {ok, Info} | {error, Reason} when + SockAddr :: socket:sockaddr(), + Info :: name_info(), + Reason :: term(). + +getnameinfo(SockAddr) -> + getnameinfo(SockAddr, undefined). + +-spec getnameinfo(SockAddr, Flags) -> {ok, Info} | {error, Reason} when + SockAddr :: socket:sockaddr(), + Flags :: name_info_flags() | undefined, + Info :: name_info(), + Reason :: term(). + +-ifdef(USE_ESOCK). +getnameinfo(SockAddr, [] = _Flags) -> + getnameinfo(SockAddr, undefined); +getnameinfo(#{family := Fam, addr := _Addr} = SockAddr, Flags) + when ((Fam =:= inet) orelse (Fam =:= inet6)) andalso + (is_list(Flags) orelse (Flags =:= undefined)) -> + prim_net:getnameinfo(socket:ensure_sockaddr(SockAddr), Flags); +getnameinfo(#{family := Fam, path := _Path} = SockAddr, Flags) + when (Fam =:= local) andalso (is_list(Flags) orelse (Flags =:= undefined)) -> + prim_net:getnameinfo(SockAddr, Flags). +-else. +-dialyzer({nowarn_function, getnameinfo/2}). +getnameinfo(SockAddr, [] = _Flags) -> + getnameinfo(SockAddr, undefined); +getnameinfo(#{family := Fam, addr := _Addr} = _SockAddr, Flags) + when ((Fam =:= inet) orelse (Fam =:= inet6)) andalso + (is_list(Flags) orelse (Flags =:= undefined)) -> + erlang:error(notsup); +getnameinfo(#{family := Fam, path := _Path} = _SockAddr, Flags) + when (Fam =:= local) andalso (is_list(Flags) orelse (Flags =:= undefined)) -> + erlang:error(notsup). +-endif. + + +%% =========================================================================== +%% +%% getaddrinfo - Network address and service translation +%% +%% There is also a "hint" argument that we "at some point" should implement. + +-spec getaddrinfo(Host) -> {ok, Info} | {error, Reason} when + Host :: string(), + Info :: [address_info()], + Reason :: term(). + +getaddrinfo(Host) when is_list(Host) -> + getaddrinfo(Host, undefined). + + +-spec getaddrinfo(Host, undefined) -> {ok, Info} | {error, Reason} when + Host :: string(), + Info :: [address_info()], + Reason :: term() + ; (undefined, Service) -> {ok, Info} | {error, Reason} when + Service :: string(), + Info :: [address_info()], + Reason :: term() + ; (Host, Service) -> {ok, Info} | {error, Reason} when + Host :: string(), + Service :: string(), + Info :: [address_info()], + Reason :: term(). + +-ifdef(USE_ESOCK). +getaddrinfo(Host, Service) + when (is_list(Host) orelse (Host =:= undefined)) andalso + (is_list(Service) orelse (Service =:= undefined)) andalso + (not ((Service =:= undefined) andalso (Host =:= undefined))) -> + prim_net:getaddrinfo(Host, Service). +-else. +-dialyzer({nowarn_function, getaddrinfo/2}). +getaddrinfo(Host, Service) + when (is_list(Host) orelse (Host =:= undefined)) andalso + (is_list(Service) orelse (Service =:= undefined)) andalso + (not ((Service =:= undefined) andalso (Host =:= undefined))) -> + erlang:error(notsup). +-endif. + + + + +%% =========================================================================== +%% +%% if_name2index - Mappings between network interface names and indexes: +%% name -> idx +%% +%% + +-spec if_name2index(Name) -> {ok, Idx} | {error, Reason} when + Name :: network_interface_name(), + Idx :: network_interface_index(), + Reason :: term(). + +-ifdef(USE_ESOCK). +if_name2index(If) when is_list(If) -> + prim_net:if_name2index(If). +-else. +-dialyzer({nowarn_function, if_name2index/1}). +if_name2index(If) when is_list(If) -> + erlang:error(notsup). +-endif. + + + +%% =========================================================================== +%% +%% if_index2name - Mappings between network interface index and names: +%% idx -> name +%% +%% + +-spec if_index2name(Idx) -> {ok, Name} | {error, Reason} when + Idx :: network_interface_index(), + Name :: network_interface_name(), + Reason :: term(). + +-ifdef(USE_ESOCK). +if_index2name(Idx) when is_integer(Idx) -> + prim_net:if_index2name(Idx). +-else. +-dialyzer({nowarn_function, if_index2name/1}). +if_index2name(Idx) when is_integer(Idx) -> + erlang:error(notsup). +-endif. + + + +%% =========================================================================== +%% +%% if_names - Get network interface names and indexes +%% +%% + +-spec if_names() -> Names | {error, Reason} when + Names :: [{Idx, If}], + Idx :: network_interface_index(), + If :: network_interface_name(), + Reason :: term(). + +-ifdef(USE_ESOCK). +if_names() -> + prim_net:if_names(). +-else. +-dialyzer({nowarn_function, if_names/0}). +if_names() -> + erlang:error(notsup). +-endif. + + diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl index 4f9d7b3e5c..f0bd1fabe9 100644 --- a/lib/kernel/src/seq_trace.erl +++ b/lib/kernel/src/seq_trace.erl @@ -59,7 +59,7 @@ set_token({Flags,Label,Serial,_From,Lastcnt}) -> F = decode_flags(Flags), set_token2([{label,Label},{serial,{Lastcnt, Serial}} | F]). --spec set_token(Component, Val) -> {Component, OldVal} when +-spec set_token(Component, Val) -> OldVal when Component :: component(), Val :: value(), OldVal :: value(). diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl index 0c9e1ea303..5a3487a9ba 100644 --- a/lib/kernel/src/user.erl +++ b/lib/kernel/src/user.erl @@ -296,7 +296,8 @@ io_requests([], Stat, _) -> %% port. put_port(List, Port) -> - send_port(Port, {command, List}). + true = port_command(Port, List), + ok. %% send_port(Port, Command) diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl index 69ff8e7971..644aa752b6 100644 --- a/lib/kernel/src/user_drv.erl +++ b/lib/kernel/src/user_drv.erl @@ -543,19 +543,14 @@ set_unicode_state(Iport, Bool) -> %% io_request(Request, InPort, OutPort) %% io_requests(Requests, InPort, OutPort) %% Note: InPort is unused. - -io_request(Request, Iport, Oport) -> - try io_command(Request) of - {command,_} = Command -> - Oport ! {self(),Command}, - ok; - {Command,Reply} -> - Oport ! {self(),Command}, - Reply - catch - {requests,Rs} -> - io_requests(Rs, Iport, Oport); - _ -> +io_request({requests,Rs}, Iport, Oport) -> + io_requests(Rs, Iport, Oport); +io_request(Request, _Iport, Oport) -> + case io_command(Request) of + {Data, Reply} -> + true = port_command(Oport, Data), + Reply; + unhandled -> ok end. @@ -575,19 +570,19 @@ put_int16(N, Tail) -> %% to the console before the vm stops when calling erlang:halt(integer()). -dialyzer({no_improper_lists, io_command/1}). io_command({put_chars_sync, unicode,Cs,Reply}) -> - {{command,[?OP_PUTC_SYNC|unicode:characters_to_binary(Cs,utf8)]},Reply}; + {[?OP_PUTC_SYNC|unicode:characters_to_binary(Cs,utf8)], Reply}; io_command({put_chars, unicode,Cs}) -> - {command,[?OP_PUTC|unicode:characters_to_binary(Cs,utf8)]}; + {[?OP_PUTC|unicode:characters_to_binary(Cs,utf8)], ok}; io_command({move_rel,N}) -> - {command,[?OP_MOVE|put_int16(N, [])]}; + {[?OP_MOVE|put_int16(N, [])], ok}; io_command({insert_chars,unicode,Cs}) -> - {command,[?OP_INSC|unicode:characters_to_binary(Cs,utf8)]}; + {[?OP_INSC|unicode:characters_to_binary(Cs,utf8)], ok}; io_command({delete_chars,N}) -> - {command,[?OP_DELC|put_int16(N, [])]}; + {[?OP_DELC|put_int16(N, [])], ok}; io_command(beep) -> - {command,[?OP_BEEP]}; -io_command(Else) -> - throw(Else). + {[?OP_BEEP], ok}; +io_command(_) -> + unhandled. %% gr_new() %% gr_get_num(Group, Index) diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 4f0847084f..6b133f8d6b 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -41,7 +41,7 @@ big_boot_embedded/1, module_status/1, native_early_modules/1, get_mode/1, - normalized_paths/1]). + normalized_paths/1, mult_embedded_flags/1]). -export([init_per_testcase/2, end_per_testcase/2, init_per_suite/1, end_per_suite/1]). @@ -72,7 +72,8 @@ all() -> on_load_purge, on_load_self_call, on_load_pending, on_load_deleted, module_status, - big_boot_embedded, native_early_modules, get_mode, normalized_paths]. + big_boot_embedded, native_early_modules, get_mode, normalized_paths, + mult_embedded_flags]. %% These need to run in order groups() -> [{sequence, [sequence], [on_load_update, @@ -354,7 +355,7 @@ load_abs(Config) when is_list(Config) -> ensure_loaded(Config) when is_list(Config) -> {module, lists} = code:ensure_loaded(lists), case init:get_argument(mode) of - {ok, [["embedded"]]} -> + {ok, [["embedded"] | _]} -> {error, embedded} = code:ensure_loaded(code_b_test), {error, badarg} = code:ensure_loaded(34), ok; @@ -1836,6 +1837,28 @@ do_normalized_paths([M|Ms]) -> do_normalized_paths([]) -> ok. +%% Make sure that the extra -mode flags are ignored +mult_embedded_flags(_Config) -> + Modes = [{" -mode embedded", embedded}, + {" -mode interactive", interactive}, + {" -mode invalid", interactive}], + + [ begin + {ArgMode, ExpectedMode} = Mode, + {ok, Node} = start_node(mode_test, ArgMode), + ExpectedMode = rpc:call(Node, code, get_mode, []), + true = stop_node(Node) + end || Mode <- Modes], + + [ begin + {ArgIgnoredMode, _} = IgnoredMode, + {ArgRelevantMode, ExpectedMode} = RelevantMode, + {ok, Node} = start_node(mode_test, ArgRelevantMode ++ ArgIgnoredMode), + ExpectedMode = rpc:call(Node, code, get_mode, []), + true = stop_node(Node) + end || IgnoredMode <- Modes, RelevantMode <- Modes], + ok. + %% Test that module_status/1 behaves as expected module_status(_Config) -> case test_server:is_cover() of diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index edf30448c4..de87bd9472 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2018. All Rights Reserved. +%% Copyright Ericsson AB 1998-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. @@ -25,6 +25,7 @@ init_per_group/2,end_per_group/2, controlling_process/1, controlling_process_self/1, no_accept/1, close_with_pending_output/1, active_n/1, + active_n_closed/1, data_before_close/1, iter_max_socks/0, iter_max_socks/1, get_status/1, @@ -36,7 +37,8 @@ show_econnreset_passive/1, econnreset_after_sync_send/1, econnreset_after_async_send_active/1, econnreset_after_async_send_active_once/1, - econnreset_after_async_send_passive/1, linger_zero/1, + econnreset_after_async_send_passive/1, + linger_zero/1, linger_zero_sndbuf/1, default_options/1, http_bad_packet/1, busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1, fill_sendq/1, partial_recv_and_close/1, @@ -73,14 +75,15 @@ suite() -> all() -> [controlling_process, controlling_process_self, no_accept, close_with_pending_output, data_before_close, - iter_max_socks, passive_sockets, active_n, + iter_max_socks, passive_sockets, active_n, active_n_closed, accept_closed_by_other_process, otp_3924, closed_socket, shutdown_active, shutdown_passive, shutdown_pending, show_econnreset_active, show_econnreset_active_once, show_econnreset_passive, econnreset_after_sync_send, econnreset_after_async_send_active, econnreset_after_async_send_active_once, - econnreset_after_async_send_passive, linger_zero, + econnreset_after_async_send_passive, + linger_zero, linger_zero_sndbuf, default_options, http_bad_packet, busy_send, busy_disconnect_passive, busy_disconnect_active, fill_sendq, partial_recv_and_close, @@ -1356,7 +1359,42 @@ linger_zero(Config) when is_list(Config) -> ok = gen_tcp:close(Client), ok = ct:sleep(1), undefined = erlang:port_info(Client, connected), - {error, econnreset} = gen_tcp:recv(S, PayloadSize). + {error, econnreset} = gen_tcp:recv(S, PayloadSize), + ok. + + +linger_zero_sndbuf(Config) when is_list(Config) -> + %% All the econnreset tests will prove that {linger, {true, 0}} aborts + %% a connection when the driver queue is empty. We will test here + %% that it also works when the driver queue is not empty + %% and the linger zero option is set on the listen socket. + {OS, _} = os:type(), + {ok, Listen} = + gen_tcp:listen(0, [{active, false}, + {recbuf, 4096}, + {show_econnreset, true}, + {linger, {true, 0}}]), + {ok, Port} = inet:port(Listen), + {ok, Client} = + gen_tcp:connect(localhost, Port, + [{active, false}, + {sndbuf, 4096}]), + {ok, Server} = gen_tcp:accept(Listen), + ok = gen_tcp:close(Listen), + PayloadSize = 1024 * 1024, + Payload = binary:copy(<<"0123456789ABCDEF">>, 256 * 1024), % 1 MB + ok = gen_tcp:send(Server, Payload), + case erlang:port_info(Server, queue_size) of + {queue_size, N} when N > 0 -> ok; + {queue_size, 0} when OS =:= win32 -> ok; + {queue_size, 0} = T -> ct:fail(T) + end, + {ok, [{linger, {true, 0}}]} = inet:getopts(Server, [linger]), + ok = gen_tcp:close(Server), + ok = ct:sleep(1), + undefined = erlang:port_info(Server, connected), + {error, closed} = gen_tcp:recv(Client, PayloadSize), + ok. %% Thanks to Luke Gorrie. Tests for a very specific problem with @@ -1981,10 +2019,10 @@ recvtclass(_Config) -> %% platforms - change {unix,_} to false? %% pktoptions is not supported for IPv4 -recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); +recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); %% Using the option returns einval, so it is not implemented. -recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0}); +recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% Does not return any value - not implemented for pktoptions recvtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0}); @@ -1993,10 +2031,10 @@ recvtos_ok({unix,_}, _) -> true; recvtos_ok(_, _) -> false. %% pktoptions is not supported for IPv4 -recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); +recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); %% Using the option returns einval, so it is not implemented. -recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0}); +recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% Does not return any value - not implemented for pktoptions recvttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,7,0}); @@ -2005,11 +2043,11 @@ recvttl_ok({unix,_}, _) -> true; recvttl_ok(_, _) -> false. %% pktoptions is not supported for IPv6 -recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); +recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% Using the option returns einval, so it is not implemented. -recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0}); +recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); %% Does not return any value - not implemented for pktoptions recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0}); %% @@ -2186,18 +2224,19 @@ collect_accepts(N,Tmo) -> A = millis(), receive {accepted,P,Msg} -> - [{P,Msg}] ++ collect_accepts(N-1,Tmo-(millis() - A)) + NextN = if N =:= infinity -> N; true -> N - 1 end, + [{P,Msg}] ++ collect_accepts(NextN, Tmo - (millis()-A)) after Tmo -> [] end. -define(EXPECT_ACCEPTS(Pattern,N,Timeout), (fun() -> - case collect_accepts(if N =:= infinity -> -1; true -> N end,Timeout) of + case collect_accepts((N), (Timeout)) of Pattern -> ok; - Other -> - {error,{unexpected,{Other,process_info(self(),messages)}}} + Other__ -> + {error,{unexpected,{Other__,process_info(self(),messages)}}} end end)()). @@ -2582,7 +2621,51 @@ active_once_closed(Config) when is_list(Config) -> ok = inet:setopts(A,[{active,once}]), ok = receive {tcp_closed, A} -> ok after 1000 -> error end end)(). - + +%% Check that active n and tcp_close messages behave as expected. +active_n_closed(Config) when is_list(Config) -> + {ok, L} = gen_tcp:listen(0, [binary, {active, false}]), + + P = self(), + + {ok,Port} = inet:port(L), + + spawn_link(fun() -> + Payload = <<0:50000/unit:8>>, + Cnt = 10000, + P ! {size,Cnt * byte_size(Payload)}, + {ok, S} = gen_tcp:connect("localhost", Port, [binary, {active, false}]), + _ = [gen_tcp:send(S, Payload) || _ <- lists:seq(1, Cnt)], + gen_tcp:close(S) + end), + + receive {size,SendSize} -> SendSize end, + {ok, S} = gen_tcp:accept(L), + inet:setopts(S, [{active, 10}]), + RecvSize = + (fun Server(Size) -> + receive + {tcp, S, Bin} -> + Server(byte_size(Bin) + Size); + {tcp_closed, S} -> + Size; + {tcp_passive, S} -> + inet:setopts(S, [{active, 10}]), + Server(Size); + Msg -> + io:format("~p~n", [Msg]), + Server(Size) + end + end)(0), + + gen_tcp:close(L), + + if SendSize =:= RecvSize -> + ok; + true -> + ct:fail("Send and Recv size not equal: ~p ~p",[SendSize, RecvSize]) + end. + %% Test the send_timeout socket option. send_timeout(Config) when is_list(Config) -> Dir = filename:dirname(code:which(?MODULE)), diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index af9985de45..70d8caf478 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2018. All Rights Reserved. +%% Copyright Ericsson AB 1998-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. @@ -37,6 +37,7 @@ buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1, read_packets/1, open_fd/1, connect/1, implicit_inet6/1, recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1, + sendtos/1, sendtosttl/1, sendttl/1, sendtclass/1, local_basic/1, local_unbound/1, local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]). @@ -49,6 +50,7 @@ all() -> bad_address, read_packets, open_fd, connect, implicit_inet6, active_n, recvtos, recvtosttl, recvttl, recvtclass, + sendtos, sendtosttl, sendttl, sendtclass, {group, local}]. groups() -> @@ -312,7 +314,6 @@ read_packets(Config) when is_list(Config) -> {ok,R} = gen_udp:open(0, [{read_packets,N1}]), {ok,RP} = inet:port(R), {ok,Node} = start_node(gen_udp_SUITE_read_packets), - Die = make_ref(), %% {V1, Trace1} = read_packets_test(R, RP, Msgs, Node), {ok,[{read_packets,N1}]} = inet:getopts(R, [read_packets]), @@ -324,7 +325,7 @@ read_packets(Config) when is_list(Config) -> stop_node(Node), ct:log("N1=~p, V1=~p vs N2=~p, V2=~p",[N1,V1,N2,V2]), - dump_terms(Config, "trace1.terms", Trace2), + dump_terms(Config, "trace1.terms", Trace1), dump_terms(Config, "trace2.terms", Trace2), %% Because of the inherit racy-ness of the feature it is @@ -348,15 +349,6 @@ dump_terms(Config, Name, Terms) -> file:write_file(FName, term_to_binary(Terms)), ct:log("Logged terms to ~s",[FName]). -infinite_loop(Die) -> - receive - Die -> - ok - after - 0 -> - infinite_loop(Die) - end. - read_packets_test(R, RP, Msgs, Node) -> Receiver = self(), Tracer = @@ -577,19 +569,19 @@ active_n(Config) when is_list(Config) -> recvtos(_Config) -> test_recv_opts( - inet, [{recvtos,tos,96}], + inet, [{recvtos,tos,96}], false, fun recvtos_ok/2). recvtosttl(_Config) -> test_recv_opts( - inet, [{recvtos,tos,96},{recvttl,ttl,33}], + inet, [{recvtos,tos,96},{recvttl,ttl,33}], false, fun (OSType, OSVer) -> recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer) end). recvttl(_Config) -> test_recv_opts( - inet, [{recvttl,ttl,33}], + inet, [{recvttl,ttl,33}], false, fun recvttl_ok/2). recvtclass(_Config) -> @@ -601,15 +593,48 @@ recvtclass(_Config) -> of [_] -> test_recv_opts( - inet6, [{recvtclass,tclass,224}], + inet6, [{recvtclass,tclass,224}], false, fun recvtclass_ok/2); [] -> {skip,ipv6_not_supported,IFs} end. + +sendtos(_Config) -> + test_recv_opts( + inet, [{recvtos,tos,96}], true, + fun sendtos_ok/2). + +sendtosttl(_Config) -> + test_recv_opts( + inet, [{recvtos,tos,96},{recvttl,ttl,33}], true, + fun (OSType, OSVer) -> + sendtos_ok(OSType, OSVer) andalso sendttl_ok(OSType, OSVer) + end). + +sendttl(_Config) -> + test_recv_opts( + inet, [{recvttl,ttl,33}], true, + fun sendttl_ok/2). + +sendtclass(_Config) -> + {ok,IFs} = inet:getifaddrs(), + case + [Name || + {Name,Opts} <- IFs, + lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)] + of + [_] -> + test_recv_opts( + inet6, [{recvtclass,tclass,224}], true, + fun sendtclass_ok/2); + [] -> + {skip,ipv6_not_supported,IFs} + end. + %% These version numbers are just above the highest noted in daily tests %% where the test fails for a plausible reason, that is the lowest -%% where we can expect that the test mighe succeed, so +%% where we can expect that the test might succeed, so %% skip on platforms lower than this. %% %% On newer versions it might be fixed, but we'll see about that @@ -621,23 +646,65 @@ recvtclass(_Config) -> %% Using the option returns einval, so it is not implemented. recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0}); %% Using the option returns einval, so it is not implemented. -recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); +recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); %% Using the option returns einval, so it is not implemented. recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% recvtos_ok({unix,_}, _) -> true; recvtos_ok(_, _) -> false. +%% Option has no effect +recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); +%% recvttl_ok({unix,_}, _) -> true; recvttl_ok(_, _) -> false. %% Using the option returns einval, so it is not implemented. recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0}); recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11}); +%% Option has no effect +recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% recvtclass_ok({unix,_}, _) -> true; recvtclass_ok(_, _) -> false. + +%% To send ancillary data seems to require much higher version numbers +%% than receiving it... +%% + +%% Using the option returns einval, so it is not implemented. +sendtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); +sendtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); +sendtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); +sendtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {4,0,0}); +sendtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); +%% +sendtos_ok({unix,_}, _) -> true; +sendtos_ok(_, _) -> false. + +%% Using the option returns einval, so it is not implemented. +sendttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); +sendttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {4,0,0}); +%% Using the option returns enoprotoopt, so it is not implemented. +sendttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {12,1,0}); +%% Option has no effect +sendttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); +sendttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,6,0}); +%% +sendttl_ok({unix,_}, _) -> true; +sendttl_ok(_, _) -> false. + +%% Using the option returns einval, so it is not implemented. +sendtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0}); +sendtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11}); +%% Option has no effect +sendtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); +%% +sendtclass_ok({unix,_}, _) -> true; +sendtclass_ok(_, _) -> false. + + semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) -> if X1 > X2 -> false; @@ -650,18 +717,18 @@ semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) -> end; semver_lt(_, {_,_,_}) -> false. -test_recv_opts(Family, Spec, OSFilter) -> +test_recv_opts(Family, Spec, TestSend, OSFilter) -> OSType = os:type(), OSVer = os:version(), case OSFilter(OSType, OSVer) of true -> io:format("Os: ~p, ~p~n", [OSType,OSVer]), - test_recv_opts(Family, Spec, OSType, OSVer); + test_recv_opts(Family, Spec, TestSend, OSType, OSVer); false -> {skip,{not_supported_for_os_version,{OSType,OSVer}}} end. %% -test_recv_opts(Family, Spec, _OSType, _OSVer) -> +test_recv_opts(Family, Spec, TestSend, _OSType, _OSVer) -> Timeout = 5000, RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec], TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec], @@ -686,16 +753,33 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) -> ok = inet:setopts(S1, TrueRecvOpts_OptsVals), {ok,TrueRecvOpts_OptsVals} = inet:getopts(S1, RecvOpts ++ Opts), %% + %% S1 now has true receive options and set option values + %% {ok,S2} = gen_udp:open(0, [Family,binary,{active,true}|FalseRecvOpts]), {ok,P2} = inet:port(S2), {ok,FalseRecvOpts_OptsVals2} = inet:getopts(S2, RecvOpts ++ Opts), OptsVals2 = FalseRecvOpts_OptsVals2 -- FalseRecvOpts, %% - ok = gen_udp:send(S2, Addr, P1, <<"abcde">>), + %% S2 now has false receive options and default option values, + %% OptsVals2 contains the default option values + %% + ok = gen_udp:send(S2, {Addr,P1}, <<"abcde">>), ok = gen_udp:send(S1, Addr, P2, <<"fghij">>), + TestSend andalso + begin + ok = gen_udp:send(S2, Addr, P1, OptsVals, <<"ABCDE">>), + ok = gen_udp:send(S2, {Addr,P1}, OptsVals, <<"12345">>) + end, {ok,{_,P2,OptsVals3,<<"abcde">>}} = gen_udp:recv(S1, 0, Timeout), verify_sets_eq(OptsVals3, OptsVals2), + TestSend andalso + begin + {ok,{_,P2,OptsVals0,<<"ABCDE">>}} = gen_udp:recv(S1, 0, Timeout), + {ok,{_,P2,OptsVals1,<<"12345">>}} = gen_udp:recv(S1, 0, Timeout), + verify_sets_eq(OptsVals0, OptsVals), + verify_sets_eq(OptsVals1, OptsVals) + end, receive {udp,S2,_,P1,<<"fghij">>} -> ok; @@ -710,8 +794,16 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) -> ok = inet:setopts(S2, TrueRecvOpts), {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts), %% - ok = gen_udp:send(S2, Addr, P1, <<"klmno">>), - ok = gen_udp:send(S1, Addr, P2, <<"pqrst">>), + %% S1 now has false receive options and set option values + %% + %% S2 now has true receive options and default option values + %% + ok = gen_udp:send(S2, {Addr,P1}, [], <<"klmno">>), + ok = gen_udp:send(S1, {Family,{loopback,P2}}, <<"pqrst">>), + TestSend andalso + begin + ok = gen_udp:send(S1, {Family,{loopback,P2}}, OptsVals2, <<"PQRST">>) + end, {ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout), receive {udp,S2,_,P1,OptsVals4,<<"pqrst">>} -> @@ -721,9 +813,18 @@ test_recv_opts(Family, Spec, _OSType, _OSVer) -> after Timeout -> exit(timeout) end, + TestSend andalso + receive + {udp,S2,_,P1,OptsVals5,<<"PQRST">>} -> + verify_sets_eq(OptsVals5, OptsVals2); + Other3 -> + exit({unexpected,Other3}) + after Timeout -> + exit(timeout) + end, ok = gen_udp:close(S1), ok = gen_udp:close(S2), -%% exit({{OSType,OSVer},success}), % In search for the truth +%%% exit({{_OSType,_OSVer},success}), % In search for the truth ok. verify_sets_eq(L1, L2) -> @@ -877,6 +978,10 @@ connect(Config) when is_list(Config) -> implicit_inet6(Config) when is_list(Config) -> Host = ok(inet:gethostname()), case inet:getaddr(Host, inet6) of + {ok,{16#fe80,0,0,0,_,_,_,_} = Addr} -> + {skip, + "Got link local IPv6 address: " + ++inet:ntoa(Addr)}; {ok,Addr} -> implicit_inet6(Host, Addr); {error,Reason} -> @@ -927,11 +1032,12 @@ ok({ok,V}) -> V; ok(NotOk) -> try throw(not_ok) catch - throw:Thrown:Stacktrace -> - erlang:raise( - error, {Thrown, NotOk}, tl(Stacktrace)) + throw:not_ok:Stacktrace -> + raise_error({not_ok, NotOk}, tl(Stacktrace)) end. +raise_error(Reason, Stacktrace) -> + erlang:raise(error, Reason, Stacktrace). local_filename(Tag) -> "/tmp/" ?MODULE_STRING "_" ++ os:getpid() ++ "_" ++ atom_to_list(Tag). diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl index 8eab36e308..5bff9cc292 100644 --- a/lib/kernel/test/global_SUITE.erl +++ b/lib/kernel/test/global_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2018. All Rights Reserved. +%% Copyright Ericsson AB 1997-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. @@ -2512,8 +2512,10 @@ re_register_name(Config) when is_list(Config) -> Me = self(), Pid1 = spawn(fun() -> proc(Me) end), yes = global:register_name(name, Pid1), + wait_for_monitor(Pid1), Pid2 = spawn(fun() -> proc(Me) end), _ = global:re_register_name(name, Pid2), + wait_for_monitor(Pid2), Pid2 ! die, Pid1 ! die, receive {Pid1, MonitoredBy1} -> [] = MonitoredBy1 end, @@ -2522,6 +2524,15 @@ re_register_name(Config) when is_list(Config) -> init_condition(Config), ok. +wait_for_monitor(Pid) -> + case process_info(Pid, monitored_by) of + {monitored_by, []} -> + timer:sleep(1), + wait_for_monitor(Pid); + {monitored_by, [_]} -> + ok + end. + proc(Parent) -> receive die -> ok end, {monitored_by, MonitoredBy} = process_info(self(), monitored_by), diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl index 298a364a91..173e25c520 100644 --- a/lib/kernel/test/interactive_shell_SUITE.erl +++ b/lib/kernel/test/interactive_shell_SUITE.erl @@ -23,7 +23,8 @@ init_per_group/2,end_per_group/2, get_columns_and_rows/1, exit_initial/1, job_control_local/1, job_control_remote/1, - job_control_remote_noshell/1,ctrl_keys/1]). + job_control_remote_noshell/1,ctrl_keys/1, + get_columns_and_rows_escript/1]). -export([init_per_testcase/2, end_per_testcase/2]). %% For spawn @@ -40,7 +41,8 @@ suite() -> {timetrap,{minutes,3}}]. all() -> - [get_columns_and_rows, exit_initial, job_control_local, + [get_columns_and_rows_escript,get_columns_and_rows, + exit_initial, job_control_local, job_control_remote, job_control_remote_noshell, ctrl_keys]. @@ -72,6 +74,60 @@ end_per_group(_GroupName, Config) -> -define(dbg(Data),noop). -endif. +string_to_term(Str) -> + {ok,Tokens,_EndLine} = erl_scan:string(Str ++ "."), + {ok,AbsForm} = erl_parse:parse_exprs(Tokens), + {value,Value,_Bs} = erl_eval:exprs(AbsForm, erl_eval:new_bindings()), + Value. + +run_unbuffer_escript(Rows, Columns, EScript, NoTermStdIn, NoTermStdOut) -> + DataDir = filename:join(filename:dirname(code:which(?MODULE)), "interactive_shell_SUITE_data"), + TmpFile = filename:join(DataDir, "tmp"), + ok = file:write_file(TmpFile, <<>>), + CommandModifier = + case {NoTermStdIn, NoTermStdOut} of + {false, false} -> ""; + {true, false} -> io_lib:format(" < ~s", [TmpFile]); + {false, true} -> io_lib:format(" > ~s ; cat ~s", [TmpFile, TmpFile]); + {true, true} -> io_lib:format(" > ~s < ~s ; cat ~s", [TmpFile, TmpFile, TmpFile]) + end, + Command = io_lib:format("unbuffer -p bash -c \"stty rows ~p; stty columns ~p; escript ~s ~s\"", + [Rows, Columns, EScript, CommandModifier]), + %% io:format("Command: ~s ~n", [Command]), + Out = os:cmd(Command), + %% io:format("Out: ~p ~n", [Out]), + string_to_term(Out). + +get_columns_and_rows_escript(Config) when is_list(Config) -> + ExpectUnbufferInstalled = + try + "79" = string:trim(os:cmd("unbuffer -p bash -c \"stty columns 79 ; tput cols\"")), + true + catch + _:_ -> false + end, + case ExpectUnbufferInstalled of + false -> + {skip, + "The unbuffer tool (https://core.tcl-lang.org/expect/index) does not seem to be installed.~n" + "On Ubuntu/Debian: \"sudo apt-get install expect\""}; + true -> + DataDir = filename:join(filename:dirname(code:which(?MODULE)), "interactive_shell_SUITE_data"), + IoColumnsErl = filename:join(DataDir, "io_columns.erl"), + IoRowsErl = filename:join(DataDir, "io_rows.erl"), + [ + begin + {ok, 42} = run_unbuffer_escript(99, 42, IoColumnsErl, NoTermStdIn, NoTermStdOut), + {ok, 99} = run_unbuffer_escript(99, 42, IoRowsErl, NoTermStdIn, NoTermStdOut) + end + || + {NoTermStdIn, NoTermStdOut} <- [{false, false}, {true, false}, {false, true}] + ], + {error,enotsup} = run_unbuffer_escript(99, 42, IoRowsErl, true, true), + {error,enotsup} = run_unbuffer_escript(99, 42, IoColumnsErl, true, true), + ok + end. + %% Test that the shell can access columns and rows. get_columns_and_rows(Config) when is_list(Config) -> case proplists:get_value(default_shell,Config) of diff --git a/lib/kernel/test/interactive_shell_SUITE_data/.gitignore b/lib/kernel/test/interactive_shell_SUITE_data/.gitignore new file mode 100644 index 0000000000..1c2f433de1 --- /dev/null +++ b/lib/kernel/test/interactive_shell_SUITE_data/.gitignore @@ -0,0 +1 @@ +tmp
\ No newline at end of file diff --git a/lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl b/lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl new file mode 100644 index 0000000000..32d0cf25df --- /dev/null +++ b/lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl @@ -0,0 +1,6 @@ +-module(io_columns). + +-export([main/1]). + +main(_) -> + io:format("~p",[io:columns()]). diff --git a/lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl b/lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl new file mode 100644 index 0000000000..53ceb464b0 --- /dev/null +++ b/lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl @@ -0,0 +1,6 @@ +-module(io_rows). + +-export([main/1]). + +main(_) -> + io:format("~p",[io:rows()]). diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl index 16ab0e97fc..2b2d509860 100644 --- a/lib/kernel/test/logger_std_h_SUITE.erl +++ b/lib/kernel/test/logger_std_h_SUITE.erl @@ -132,6 +132,7 @@ all() -> bad_input, reconfig, file_opts, + relative_file_path, sync, write_failure, sync_failure, @@ -693,6 +694,54 @@ file_opts(Config) -> file_opts(cleanup, _Config) -> logger:remove_handler(?MODULE). +relative_file_path(_Config) -> + {ok,Dir} = file:get_cwd(), + AbsName1 = filename:join(Dir,?MODULE), + ok = logger:add_handler(?MODULE, + logger_std_h, + #{config => #{type=>file}, + filter_default=>log, + filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), + formatter=>{?MODULE,self()}}), + #{cb_state := #{handler_state := #{file:=AbsName1}}} = + logger_olp:info(h_proc_name()), + {ok,#{config := #{file:=AbsName1}}} = + logger:get_handler_config(?MODULE), + ok = logger:remove_handler(?MODULE), + + RelName2 = filename:join(atom_to_list(?FUNCTION_NAME), + lists:concat([?FUNCTION_NAME,".log"])), + AbsName2 = filename:join(Dir,RelName2), + ok = logger:add_handler(?MODULE, + logger_std_h, + #{config => #{file => RelName2}, + filter_default=>log, + filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), + formatter=>{?MODULE,self()}}), + #{cb_state := #{handler_state := #{file:=AbsName2}}} = + logger_olp:info(h_proc_name()), + {ok,#{config := #{file:=AbsName2}}} = + logger:get_handler_config(?MODULE), + logger:notice(M1=?msg,?domain), + ?check(M1), + B1 = ?bin(M1), + try_read_file(AbsName2, {ok,B1}, filesync_rep_int()), + + ok = file:set_cwd(".."), + logger:notice(M2=?msg,?domain), + ?check(M2), + B20 = ?bin(M2), + B2 = <<B1/binary,B20/binary>>, + try_read_file(AbsName2, {ok,B2}, filesync_rep_int()), + + {error,_} = logger:update_handler_config(?MODULE,config,#{file=>RelName2}), + ok = logger:update_handler_config(?MODULE,config,#{file=>AbsName2}), + ok = file:set_cwd(Dir), + ok = logger:update_handler_config(?MODULE,config,#{file=>RelName2}), + ok. +relative_file_path(cleanup,_Config) -> + logger:remove_handler(?MODULE). + sync(Config) -> Dir = ?config(priv_dir,Config), diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl index 663f910751..83a94ab087 100644 --- a/lib/kernel/test/seq_trace_SUITE.erl +++ b/lib/kernel/test/seq_trace_SUITE.erl @@ -26,6 +26,7 @@ init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2]). -export([token_set_get/1, tracer_set_get/1, print/1, + old_heap_token/1, send/1, distributed_send/1, recv/1, distributed_recv/1, trace_exit/1, distributed_exit/1, call/1, port/1, match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1, @@ -50,6 +51,7 @@ suite() -> all() -> [token_set_get, tracer_set_get, print, send, send_literal, distributed_send, recv, distributed_recv, trace_exit, + old_heap_token, distributed_exit, call, port, match_set_seq_token, gc_seq_token, label_capability_mismatch]. @@ -149,17 +151,19 @@ tracer_set_get(Config) when is_list(Config) -> ok. print(Config) when is_list(Config) -> - lists:foreach(fun do_print/1, ?TIMESTAMP_MODES). + [do_print(TsType, Label) || TsType <- ?TIMESTAMP_MODES, + Label <- [17, "label"]]. -do_print(TsType) -> +do_print(TsType, Label) -> start_tracer(), + seq_trace:set_token(label, Label), set_token_flags([print, TsType]), - seq_trace:print(0,print1), + seq_trace:print(Label,print1), seq_trace:print(1,print2), seq_trace:print(print3), seq_trace:reset_trace(), - [{0,{print,_,_,[],print1}, Ts0}, - {0,{print,_,_,[],print3}, Ts1}] = stop_tracer(2), + [{Label,{print,_,_,[],print1}, Ts0}, + {Label,{print,_,_,[],print3}, Ts1}] = stop_tracer(2), check_ts(TsType, Ts0), check_ts(TsType, Ts1). @@ -563,6 +567,24 @@ get_port_message(Port) -> end. +%% OTP-15849 ERL-700 +%% Verify changing label on existing token when it resides on old heap. +%% Bug caused faulty ref from old to new heap. +old_heap_token(Config) when is_list(Config) -> + seq_trace:set_token(label, 1), + erlang:garbage_collect(self(), [{type, minor}]), + erlang:garbage_collect(self(), [{type, minor}]), + %% Now token tuple should be on old-heap. + %% Set a new non-literal label which should reside on new-heap. + NewLabel = {self(), "new label"}, + 1 = seq_trace:set_token(label, NewLabel), + + %% If bug, we now have a ref from old to new heap. Yet another minor gc + %% will make that a ref to deallocated memory. + erlang:garbage_collect(self(), [{type, minor}]), + {label,NewLabel} = seq_trace:get_token(label), + ok. + match_set_seq_token(doc) -> ["Tests that match spec function set_seq_token does not " diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index 765e890157..e5188aa9b5 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 6.4 +KERNEL_VSN = 6.4.1 |