diff options
Diffstat (limited to 'lib/kernel')
| -rw-r--r-- | lib/kernel/doc/src/Makefile | 2 | ||||
| -rw-r--r-- | lib/kernel/doc/src/gen_tcp.xml | 7 | ||||
| -rw-r--r-- | lib/kernel/src/dist_util.erl | 3 | ||||
| -rw-r--r-- | lib/kernel/src/erts_debug.erl | 26 | ||||
| -rw-r--r-- | lib/kernel/src/net_kernel.erl | 344 | ||||
| -rw-r--r-- | lib/kernel/test/erl_distribution_wb_SUITE.erl | 14 | ||||
| -rw-r--r-- | lib/kernel/test/zlib_SUITE.erl | 53 | 
7 files changed, 309 insertions, 140 deletions
| diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile index c9d23ac4c4..0759f362d4 100644 --- a/lib/kernel/doc/src/Makefile +++ b/lib/kernel/doc/src/Makefile @@ -71,7 +71,7 @@ XML_REF4_FILES = app.xml config.xml  XML_REF6_FILES = kernel_app.xml  XML_PART_FILES = -XML_CHAPTER_FILES = notes.xml notes_history.xml +XML_CHAPTER_FILES = notes.xml  BOOK_FILES = book.xml diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index 070782e1f3..e6104b0c76 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -51,6 +51,7 @@ server() ->      {ok, Sock} = gen_tcp:accept(LSock),      {ok, Bin} = do_recv(Sock, []),      ok = gen_tcp:close(Sock), +    ok = gen_tcp:close(LSock),      Bin.  do_recv(Sock, Bs) -> @@ -309,9 +310,9 @@ do_recv(Sock, Bs) ->              <seealso marker="inet#setopts/2"><c>inet:setopts/2</c></seealso>.              </p></item>          </taglist> -        <p>The returned socket <c><anno>ListenSocket</anno></c> can only be -          used in calls to -          <seealso marker="#accept/1"><c>accept/1,2</c></seealso>.</p> +        <p>The returned socket <c><anno>ListenSocket</anno></c> should be used +          in calls to <seealso marker="#accept/1"><c>accept/1,2</c></seealso> to +          accept incoming connection requests.</p>          <note>            <p>The default values for options specified to <c>listen</c> can              be affected by the Kernel configuration parameter diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl index 08bd5946cd..fb9f7fd7eb 100644 --- a/lib/kernel/src/dist_util.erl +++ b/lib/kernel/src/dist_util.erl @@ -250,7 +250,8 @@ check_dflags(#hs_data{other_node = Node,                        require_flags = RequiredFlags} = HSData) ->      Mandatory = ((?DFLAG_EXTENDED_REFERENCES                        bor ?DFLAG_EXTENDED_PIDS_PORTS -                      bor ?DFLAG_UTF8_ATOMS) +                      bor ?DFLAG_UTF8_ATOMS +                      bor ?DFLAG_NEW_FUN_TAGS)                       bor RequiredFlags),      Missing = check_mandatory(0, ?DFLAGS_ALL, Mandatory,                                OtherFlags, []), diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl index 2887014c1c..ea8d64b2c7 100644 --- a/lib/kernel/src/erts_debug.erl +++ b/lib/kernel/src/erts_debug.erl @@ -21,7 +21,7 @@  %% Low-level debugging support. EXPERIMENTAL! --export([size/1,df/1,df/2,df/3,ic/1]). +-export([size/1,df/1,df/2,df/3,df/4,ic/1]).  %% This module contains the following *experimental* BIFs:  %%   disassemble/1 @@ -347,31 +347,39 @@ is_term_seen(_, []) -> false.  -spec df(module()) -> df_ret().  df(Mod) when is_atom(Mod) -> +    df(lists:concat([Mod, ".dis"]), Mod). + +-spec df(module(), atom()) -> df_ret(); +        (file:io_device() | file:filename(), module()) -> df_ret(). + +df(Mod, Func) when is_atom(Mod), is_atom(Func) -> +    df(lists:concat([Mod, "_", Func, ".dis"]), Mod, Func); +df(Name, Mod) when is_atom(Mod) ->      try Mod:module_info(functions) of  	Fs0 when is_list(Fs0) -> -	    Name = lists:concat([Mod, ".dis"]),  	    Fs = [{Mod,Func,Arity} || {Func,Arity} <- Fs0],  	    dff(Name, Fs)      catch _:_ -> {undef,Mod}      end. --spec df(module(), atom()) -> df_ret(). -df(Mod, Func) when is_atom(Mod), is_atom(Func) -> +-spec df(module(), atom(), arity()) -> df_ret(); +        (file:io_device() | file:filename(), module(), atom()) -> df_ret(). + +df(Mod, Func, Arity) when is_atom(Mod), is_atom(Func), is_integer(Arity) -> +    df(lists:concat([Mod, "_", Func, "_", Arity, ".dis"]), Mod, Func, Arity); +df(Name, Mod, Func) when is_atom(Mod), is_atom(Func) ->      try Mod:module_info(functions) of  	Fs0 when is_list(Fs0) -> -	    Name = lists:concat([Mod, "_", Func, ".dis"]),  	    Fs = [{Mod,Func1,Arity} || {Func1,Arity} <- Fs0, Func1 =:= Func],  	    dff(Name, Fs)      catch _:_ -> {undef,Mod}      end. --spec df(module(), atom(), arity()) -> df_ret(). - -df(Mod, Func, Arity) when is_atom(Mod), is_atom(Func) -> +-spec df(file:io_device() | file:filename(), module(), atom(), arity()) -> df_ret(). +df(Name, Mod, Func, Arity) when is_atom(Mod), is_atom(Func), is_integer(Arity) ->      try Mod:module_info(functions) of  	Fs0 when is_list(Fs0) -> -	    Name = lists:concat([Mod, "_", Func, "_", Arity, ".dis"]),  	    Fs = [{Mod,Func1,Arity1} || {Func1,Arity1} <- Fs0,  					Func1 =:= Func, Arity1 =:= Arity],  	    dff(Name, Fs) diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index f36b4f1e6a..cdb10a7b12 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -70,8 +70,8 @@  	 protocol_childspecs/0,  	 epmd_module/0]). --export([connect/1, disconnect/1, hidden_connect/1, passive_cnct/1]). --export([hidden_connect_node/1]). %% explicit connect +-export([disconnect/1, passive_cnct/1]). +-export([hidden_connect_node/1]).  -export([set_net_ticktime/1, set_net_ticktime/2, get_net_ticktime/0]).  -export([node_info/1, node_info/2, nodes_info/0, @@ -122,6 +122,7 @@  -record(connection, {  		     node,          %% remote node name +                     conn_id,       %% Connection identity  		     state,         %% pending | up | up_pending  		     owner,         %% owner pid  	             pending_owner, %% possible new owner @@ -247,14 +248,15 @@ ticktime_res(A)      when is_atom(A)             -> A.  %% Called though BIF's -connect(Node) ->               do_connect(Node, normal, false).  %%% Long timeout if blocked (== barred), only affects nodes with  %%% {dist_auto_connect, once} set. -passive_cnct(Node) ->              do_connect(Node, normal, true). -disconnect(Node) ->            request({disconnect, Node}). +passive_cnct(Node) -> +    case request({passive_cnct, Node}) of +        ignored -> false; +        Other -> Other +    end. -%% connect but not seen -hidden_connect(Node) ->        do_connect(Node, hidden, false). +disconnect(Node) ->            request({disconnect, Node}).  %% Should this node publish itself on Node?  publish_on_node(Node) when is_atom(Node) -> @@ -272,67 +274,30 @@ connect_node(Node) when is_atom(Node) ->  hidden_connect_node(Node) when is_atom(Node) ->      request({connect, hidden, Node}). -do_connect(Node, Type, WaitForBarred) -> %% Type = normal | hidden -    case catch ets:lookup(sys_dist, Node) of -	{'EXIT', _} -> -	    ?connect_failure(Node,{table_missing, sys_dist}), -	    false; -	[#barred_connection{}] -> -	    case WaitForBarred of -		false -> -		    false; -		true -> -		    Pid = spawn(?MODULE,passive_connect_monitor,[self(),Node]), -		    receive -			{Pid, true} -> -			    %%io:format("Net Kernel: barred connection (~p) " -			    %%          "connected from other end.~n",[Node]), -			    true; -			{Pid, false} -> -			    ?connect_failure(Node,{barred_connection, -						   ets:lookup(sys_dist, Node)}), -			    %%io:format("Net Kernel: barred connection (~p) " -			    %%      "- failure.~n",[Node]), -			    false -		    end -	    end; -	Else -> -	    case application:get_env(kernel, dist_auto_connect) of -		{ok, never} -> -		    ?connect_failure(Node,{dist_auto_connect,never}), -		    false; -		% This might happen due to connection close -		% not beeing propagated to user space yet. -		% Save the day by just not connecting... -		{ok, once} when Else =/= [], -				(hd(Else))#connection.state =:= up -> -		    ?connect_failure(Node,{barred_connection, -				ets:lookup(sys_dist, Node)}), -		    false; -		_ -> -		    request({connect, Type, Node}) -	    end -    end. -passive_connect_monitor(Parent, Node) -> +passive_connect_monitor(From, Node) ->      ok = monitor_nodes(true,[{node_type,all}]), -    case lists:member(Node,nodes([connected])) of -	true -> -	    ok = monitor_nodes(false,[{node_type,all}]), -	    Parent ! {self(),true}; -	_ -> -	    Ref = make_ref(), -	    Tref = erlang:send_after(connecttime(),self(),Ref), -	    receive -		Ref -> -		    ok = monitor_nodes(false,[{node_type,all}]), -		    Parent ! {self(), false}; -		{nodeup,Node,_} -> -		    ok = monitor_nodes(false,[{node_type,all}]), -		    _ = erlang:cancel_timer(Tref), -		    Parent ! {self(),true} -	    end -    end. +    Reply = case lists:member(Node,nodes([connected])) of +                true -> +                    io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]), +                    true; +                _ -> +                    receive +                        {nodeup,Node,_} -> +                            io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]), +                            true +                    after connecttime() -> +                            io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]), +                            false +                    end +            end, +    ok = monitor_nodes(false,[{node_type,all}]), +    io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]), +    {Pid, Tag} = From, +    io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]), +    erlang:send(Pid, {Tag, Reply}), +    io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]). +  %% If the net_kernel isn't running we ignore all requests to the  %% kernel, thus basically accepting them :-) @@ -394,40 +359,135 @@ init({Name, LongOrShortNames, TickT, CleanHalt}) ->      end. +do_auto_connect(Type, Node, ConnId, WaitForBarred, From, State) -> +    ConnLookup = ets:lookup(sys_dist, Node), + +    case ConnLookup of +        [#barred_connection{}] -> +            case WaitForBarred of +                false -> +                    {reply, false, State}; +                true -> +                    spawn(?MODULE,passive_connect_monitor,[From,Node]), +                    {noreply, State} +            end; + +        [#connection{conn_id=ConnId, state = up}] -> +            {reply, true, State}; +        [#connection{conn_id=ConnId, waiting=Waiting}=Conn] -> +            case From of +                noreply -> ok; +                _ -> ets:insert(sys_dist, Conn#connection{waiting = [From|Waiting]}) +            end, +            {noreply, State}; + +        _ -> +            case application:get_env(kernel, dist_auto_connect) of +                {ok, never} -> +                    ?connect_failure(Node,{dist_auto_connect,never}), +                    {reply, false, State}; + +                %% This might happen due to connection close +                %% not beeing propagated to user space yet. +                %% Save the day by just not connecting... +                {ok, once} when ConnLookup =/= [], +                                (hd(ConnLookup))#connection.state =:= up -> +                    ?connect_failure(Node,{barred_connection, +                                           ets:lookup(sys_dist, Node)}), +                    {reply, false, State}; +                _ -> +                    case setup(ConnLookup, Node,ConnId,Type,From,State) of +                        {ok, SetupPid} -> +                            Owners = [{SetupPid, Node} | State#state.conn_owners], +                            {noreply,State#state{conn_owners=Owners}}; +                        _Error  -> +                            ?connect_failure(Node, {setup_call, failed, _Error}), +                            {reply, false, State} +                    end +            end +    end. + + +do_explicit_connect([#connection{conn_id = ConnId, state = up}], _, _, ConnId, _From, State) -> +    {reply, true, State}; +do_explicit_connect([#connection{conn_id = ConnId}=Conn], _, _, ConnId, From, State) +  when Conn#connection.state =:= pending; +       Conn#connection.state =:= up_pending -> +    Waiting = Conn#connection.waiting, +    ets:insert(sys_dist, Conn#connection{waiting = [From|Waiting]}),     +    {noreply, State}; +do_explicit_connect([#barred_connection{}], Type, Node, ConnId, From , State) -> +    %% Barred connection only affects auto_connect, ignore it. +    do_explicit_connect([], Type, Node, ConnId, From , State); +do_explicit_connect(ConnLookup, Type, Node, ConnId, From , State) -> +    case setup(ConnLookup, Node,ConnId,Type,From,State) of +        {ok, SetupPid} -> +            Owners = [{SetupPid, Node} | State#state.conn_owners], +            {noreply,State#state{conn_owners=Owners}}; +        _Error -> +            ?connect_failure(Node, {setup_call, failed, _Error}), +            {reply, false, State} +    end. + +-define(ERTS_DIST_CON_ID_MASK, 16#ffffff).  % also in external.h + +verify_new_conn_id([], {Nr,_DHandle}) +  when (Nr band (bnot ?ERTS_DIST_CON_ID_MASK)) =:= 0 -> +    true; +verify_new_conn_id([#connection{conn_id = {Old,_}}], {New,_}) +  when New =:= ((Old+1) band ?ERTS_DIST_CON_ID_MASK) -> +    true; +verify_new_conn_id(_, _) -> +    false. +                                                               + +  %% ------------------------------------------------------------  %% handle_call.  %% ------------------------------------------------------------  %% -%% Set up a connection to Node. -%% The response is delayed until the connection is up and -%% running. +%% Passive auto-connect to Node. +%% The response is delayed until the connection is up and running.  %% -handle_call({connect, _, Node}, From, State) when Node =:= node() -> +handle_call({passive_cnct, Node}, From, State) when Node =:= node() -> +    async_reply({reply, true, State}, From); +handle_call({passive_cnct, Node}, From, State) -> +    verbose({passive_cnct, Node}, 1, State), +    Type = normal, +    WaitForBarred = true, +    R = case (catch erts_internal:new_connection(Node)) of +            {Nr,_DHandle}=ConnId when is_integer(Nr) -> +                do_auto_connect(Type, Node, ConnId, WaitForBarred, From, State); + +            _Error -> +                error_logger:error_msg("~n** Cannot get connection id for node ~w~n", +                                       [Node]), +                {reply, false, State} +        end, + +    return_call(R, From); + +%% +%% Explicit connect +%% The response is delayed until the connection is up and running. +%% +handle_call({connect, _, Node, _, _}, From, State) when Node =:= node() ->      async_reply({reply, true, State}, From);  handle_call({connect, Type, Node}, From, State) ->      verbose({connect, Type, Node}, 1, State), -    case ets:lookup(sys_dist, Node) of -	[Conn] when Conn#connection.state =:= up -> -	    async_reply({reply, true, State}, From); -	[Conn] when Conn#connection.state =:= pending -> -	    Waiting = Conn#connection.waiting, -	    ets:insert(sys_dist, Conn#connection{waiting = [From|Waiting]}), -	    {noreply, State}; -	[Conn] when Conn#connection.state =:= up_pending -> -	    Waiting = Conn#connection.waiting, -	    ets:insert(sys_dist, Conn#connection{waiting = [From|Waiting]}), -	    {noreply, State}; -	_ -> -	    case setup(Node,Type,From,State) of -		{ok, SetupPid} -> -		    Owners = [{SetupPid, Node} | State#state.conn_owners], -		    {noreply,State#state{conn_owners=Owners}}; -		_Error  -> -		    ?connect_failure(Node, {setup_call, failed, _Error}), -		    async_reply({reply, false, State}, From) -	    end -    end; +    ConnLookup = ets:lookup(sys_dist, Node), +    R = case (catch erts_internal:new_connection(Node)) of +            {Nr,_DHandle}=ConnId when is_integer(Nr) -> +                do_explicit_connect(ConnLookup, Type, Node, ConnId, From, State); +                     +            _Error -> +                error_logger:error_msg("~n** Cannot get connection id for node ~w~n", +                                       [Node]), +                {reply, false, State}                     +        end, +    return_call(R, From); +              %%  %% Close the connection to Node. @@ -634,6 +694,26 @@ terminate(_Reason, State) ->  %% ------------------------------------------------------------  %% +%% Asynchronous auto connect request +%% +handle_info({auto_connect,Node, Nr, DHandle}, State) -> +    verbose({auto_connect, Node, Nr, DHandle}, 1, State), +    ConnId = {Nr, DHandle}, +    NewState = +        case do_auto_connect(normal, Node, ConnId, false, noreply, State) of +            {noreply, S} ->           %% Pending connection +                S; + +            {reply, true, S} ->  %% Already connected +                S; + +            {reply, false, S} -> %% Connection refused +                erts_internal:abort_connection(Node, ConnId), +                S +        end, +    {noreply, NewState}; + +%%  %% accept a new connection.  %%  handle_info({accept,AcceptPid,Socket,Family,Proto}, State) -> @@ -713,14 +793,23 @@ handle_info({AcceptPid, {accept_pending,MyNode,Node,Address,Type}}, State) ->  	    AcceptPid ! {self(), {accept_pending, already_pending}},  	    {noreply, State};  	_ -> -	    ets:insert(sys_dist, #connection{node = Node, -					     state = pending, -					     owner = AcceptPid, -					     address = Address, -					     type = Type}), -	    AcceptPid ! {self(),{accept_pending,ok}}, -	    Owners = [{AcceptPid,Node} | State#state.conn_owners], -	    {noreply, State#state{conn_owners = Owners}} +            case (catch erts_internal:new_connection(Node)) of +                {Nr,_DHandle}=ConnId when is_integer(Nr) -> +                    ets:insert(sys_dist, #connection{node = Node, +                                                     conn_id = ConnId, +                                                     state = pending, +                                                     owner = AcceptPid, +                                                     address = Address, +                                                     type = Type}), +                    AcceptPid ! {self(),{accept_pending,ok}}, +                    Owners = [{AcceptPid,Node} | State#state.conn_owners], +                    {noreply, State#state{conn_owners = Owners}}; + +                _ -> +                    error_logger:error_msg("~n** Cannot get connection id for node ~w~n", +                                           [Node]), +                    AcceptPid ! {self(),{accept_pending,nok_pending}} +            end      end;  handle_info({SetupPid, {is_pending, Node}}, State) -> @@ -906,6 +995,7 @@ pending_nodedown(Conn, Node, Type, State) ->      % Don't bar connections that have never been alive      %mark_sys_dist_nodedown(Node),      % - instead just delete the node: +    erts_internal:abort_connection(Node, Conn#connection.conn_id),      ets:delete(sys_dist, Node),      reply_waiting(Node,Conn#connection.waiting, false),      case Type of @@ -920,7 +1010,9 @@ up_pending_nodedown(Conn, Node, _Reason, _Type, State) ->      AcceptPid = Conn#connection.pending_owner,      Owners = State#state.conn_owners,      Pend = lists:keydelete(AcceptPid, 1, State#state.pend_owners), +    erts_internal:abort_connection(Node, Conn#connection.conn_id),      Conn1 = Conn#connection { owner = AcceptPid, +                              conn_id = erts_internal:new_connection(Node),  			      pending_owner = undefined,  			      state = pending },      ets:insert(sys_dist, Conn1), @@ -928,15 +1020,16 @@ up_pending_nodedown(Conn, Node, _Reason, _Type, State) ->      State#state{conn_owners = [{AcceptPid,Node}|Owners], pend_owners = Pend}. -up_nodedown(_Conn, Node, _Reason, Type, State) -> -    mark_sys_dist_nodedown(Node), +up_nodedown(Conn, Node, _Reason, Type, State) -> +    mark_sys_dist_nodedown(Conn, Node),      case Type of  	normal -> ?nodedown(Node, State);  	_ -> ok      end,      State. -mark_sys_dist_nodedown(Node) -> +mark_sys_dist_nodedown(Conn, Node) -> +    erts_internal:abort_connection(Node, Conn#connection.conn_id),      case application:get_env(kernel, dist_auto_connect) of  	{ok, once} ->  	    ets:insert(sys_dist, #barred_connection{node = Node}); @@ -1179,15 +1272,8 @@ spawn_func(_,{From,Tag},M,F,A,Gleader) ->  %% Set up connection to a new node.  %% ----------------------------------------------------------- -setup(Node,Type,From,State) -> -    Allowed = State#state.allowed, -    case lists:member(Node, Allowed) of -	false when Allowed =/= [] -> -	    error_msg("** Connection attempt with " -		      "disallowed node ~w ** ~n", [Node]), -	    {error, bad_node}; -	_ -> -	    case select_mod(Node, State#state.listen) of +setup(ConnLookup, Node,ConnId,Type,From,State) -> +    case setup_check(ConnLookup, Node, ConnId, State) of  		{ok, L} ->  		    Mod = L#listen.module,  		    LAddr = L#listen.address, @@ -1200,18 +1286,45 @@ setup(Node,Type,From,State) ->  		    Addr = LAddr#net_address {  					      address = undefined,  					      host = undefined }, +                    Waiting = case From of +                                  noreply -> []; +                                  _ -> [From] +                              end,  		    ets:insert(sys_dist, #connection{node = Node, +                                                     conn_id = ConnId,  						     state = pending,  						     owner = Pid, -						     waiting = [From], +						     waiting = Waiting,  						     address = Addr,  						     type = normal}),  		    {ok, Pid};  		Error ->  		    Error -	    end      end. +setup_check(ConnLookup, Node, ConnId, State) -> +    Allowed = State#state.allowed,     +    case lists:member(Node, Allowed) of +	false when Allowed =/= [] -> +	    error_msg("** Connection attempt with " +		      "disallowed node ~w ** ~n", [Node]), +	    {error, bad_node}; +       _ -> +            case verify_new_conn_id(ConnLookup, ConnId) of +                false -> +                    error_msg("** Connection attempt to ~w with " +                              "bad connection id ~w ** ~n", [Node, ConnId]), +                    {error, bad_conn_id}; +                true -> +                    case select_mod(Node, State#state.listen) of +                        {ok, _L}=OK -> OK; +                        Error -> Error +                    end +            end +    end.                     + +     +  %%  %% Find a module that is willing to handle connection setup to Node  %% @@ -1652,6 +1765,11 @@ verbose(_, _, _) ->  getnode(P) when is_pid(P) -> node(P);  getnode(P) -> P. +return_call({noreply, _State}=R, _From) -> +    R; +return_call(R, From) -> +    async_reply(R, From). +  async_reply({reply, Msg, State}, From) ->      async_gen_server_reply(From, Msg),      {noreply, State}. diff --git a/lib/kernel/test/erl_distribution_wb_SUITE.erl b/lib/kernel/test/erl_distribution_wb_SUITE.erl index 03aaee56b7..1145d30e5e 100644 --- a/lib/kernel/test/erl_distribution_wb_SUITE.erl +++ b/lib/kernel/test/erl_distribution_wb_SUITE.erl @@ -61,10 +61,13 @@  %% From R9 and forward extended references is compulsory  %% From R10 and forward extended pids and ports are compulsory  %% From R20 and forward UTF8 atoms are compulsory +%% From R21 and forward NEW_FUN_TAGS is compulsory (no more tuple fallback {fun, ...})  -define(COMPULSORY_DFLAGS, (?DFLAG_EXTENDED_REFERENCES bor                              ?DFLAG_EXTENDED_PIDS_PORTS bor -                            ?DFLAG_UTF8_ATOMS)). +                            ?DFLAG_UTF8_ATOMS bor +                            ?DFLAG_NEW_FUN_TAGS)). +-define(PASS_THROUGH, $p).  -define(shutdown(X), exit(X)).  -define(int16(X), [((X) bsr 8) band 16#ff, (X) band 16#ff]). @@ -676,13 +679,12 @@ recv_message(Socket) ->      case gen_tcp:recv(Socket, 0) of  	{ok,Data} ->  	    B0 = list_to_binary(Data), -	    {_,B1} = erlang:split_binary(B0,1), -	    Header = binary_to_term(B1), -	    Siz = byte_size(term_to_binary(Header)), -	    {_,B2} = erlang:split_binary(B1,Siz), +	    <<?PASS_THROUGH, B1/binary>> = B0, +	    {Header,Siz} = binary_to_term(B1,[used]), +	    <<_:Siz/binary,B2/binary>> = B1,  	    Message = case (catch binary_to_term(B2)) of  			  {'EXIT', _} -> -			      could_not_digest_message; +			      {could_not_digest_message,B2};  			  Other ->  			      Other  		      end, diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl index 7be7e503df..f203ef878f 100644 --- a/lib/kernel/test/zlib_SUITE.erl +++ b/lib/kernel/test/zlib_SUITE.erl @@ -166,7 +166,7 @@ api_deflateInit(Config) when is_list(Config) ->  			  ?m(ok, zlib:deflateInit(Z12,default,deflated,-Wbits,8,default)),  			  ?m(ok,zlib:close(Z11)),  			  ?m(ok,zlib:close(Z12)) -		  end, lists:seq(8, 15)), +		  end, lists:seq(9, 15)),      lists:foreach(fun(MemLevel) ->  			  Z = zlib:open(), @@ -213,12 +213,46 @@ api_deflateReset(Config) when is_list(Config) ->  %% Test deflateParams.  api_deflateParams(Config) when is_list(Config) -> +    Levels = [none, default, best_speed, best_compression] ++ lists:seq(0, 9), +    Strategies = [filtered, huffman_only, rle, default], +      Z1 = zlib:open(),      ?m(ok, zlib:deflateInit(Z1, default)), -    ?m(L when is_list(L), zlib:deflate(Z1, <<1,1,1,1,1,1,1,1,1>>, none)), -    ?m(ok, zlib:deflateParams(Z1, best_compression, huffman_only)), -    ?m(L when is_list(L), zlib:deflate(Z1, <<1,1,1,1,1,1,1,1,1>>, sync)), -    ?m(ok, zlib:close(Z1)). + +    ApiTest = +        fun(Level, Strategy) -> +            ?m(ok, zlib:deflateParams(Z1, Level, Strategy)), +            ?m(ok, zlib:deflateReset(Z1)) +        end, + +    [ ApiTest(Level, Strategy) || Level <- Levels, Strategy <- Strategies ], + +    ?m(ok, zlib:close(Z1)), + +    FlushTest = +        fun FlushTest(Size, Level, Strategy) -> +            Z = zlib:open(), +            ok = zlib:deflateInit(Z, default), +            Data = gen_determ_rand_bytes(Size), +            case zlib:deflate(Z, Data, none) of +                [<<120, 156>>] -> +                    %% All data is present in the internal zlib state, and will +                    %% be flushed on deflateParams. + +                    ok = zlib:deflateParams(Z, Level, Strategy), +                    Compressed = [<<120, 156>>, zlib:deflate(Z, <<>>, finish)], +                    Data = zlib:uncompress(Compressed), +                    zlib:close(Z), + +                    FlushTest(Size + (1 bsl 10), Level, Strategy); +                _Other -> +                    ok +            end +        end, + +    [ FlushTest(1, Level, Strategy) || Level <- Levels, Strategy <- Strategies ], + +    ok.  %% Test deflate.  api_deflate(Config) when is_list(Config) -> @@ -652,6 +686,11 @@ api_g_un_zip(Config) when is_list(Config) ->      Concatenated = <<Bin/binary, Bin/binary>>,      ?m(Concatenated, zlib:gunzip([Comp, Comp])), +    %% Don't explode if the uncompressed size is a perfect multiple of the +    %% internal inflate chunk size. +    ChunkSizedData = <<0:16384/unit:8>>, +    ?m(ChunkSizedData, zlib:gunzip(zlib:gzip(ChunkSizedData))), +      %% Bad CRC; bad length.      BadCrc = bad_crc_data(),      ?m(?EXIT(data_error),(catch zlib:gunzip(BadCrc))), @@ -762,13 +801,13 @@ zip_usage({run,ZIP,ORIG}) ->      ?m(ok, zlib:deflateInit(Z, default, deflated, -15, 8, default)),      C2 = zlib:deflate(Z, ORIG, finish), -    ?m(true, C1 == list_to_binary(C2)), +    ?m(ORIG, zlib:unzip(C2)),      ?m(ok, zlib:deflateEnd(Z)),      ?m(ok, zlib:deflateInit(Z, none, deflated, -15, 8, filtered)),      ?m(ok, zlib:deflateParams(Z, default, default)),      C3 = zlib:deflate(Z, ORIG, finish), -    ?m(true, C1 == list_to_binary(C3)), +    ?m(ORIG, zlib:unzip(C3)),      ?m(ok, zlib:deflateEnd(Z)),      ok = zlib:close(Z), | 
