aboutsummaryrefslogtreecommitdiffstats
path: root/lang/erlang-runtime17
diff options
context:
space:
mode:
authorolgeni <olgeni@FreeBSD.org>2015-04-11 17:27:16 +0800
committerolgeni <olgeni@FreeBSD.org>2015-04-11 17:27:16 +0800
commit8952d626a70835916cad24b1b4e068466e1933f6 (patch)
treeb12646029b520c476c603c5d78c85f1c61333d32 /lang/erlang-runtime17
parentb233916a27c50383ff5592dd1157ed66a0636e1e (diff)
downloadfreebsd-ports-gnome-8952d626a70835916cad24b1b4e068466e1933f6.tar.gz
freebsd-ports-gnome-8952d626a70835916cad24b1b4e068466e1933f6.tar.zst
freebsd-ports-gnome-8952d626a70835916cad24b1b4e068466e1933f6.zip
Upgrade to version 17.5.1.
No tarballs for this release have been provided by upstream so far.
Diffstat (limited to 'lang/erlang-runtime17')
-rw-r--r--lang/erlang-runtime17/Makefile6
-rw-r--r--lang/erlang-runtime17/files/patch-otp-17.5.1826
2 files changed, 831 insertions, 1 deletions
diff --git a/lang/erlang-runtime17/Makefile b/lang/erlang-runtime17/Makefile
index 742d4c4003ac..96aaa74ac18a 100644
--- a/lang/erlang-runtime17/Makefile
+++ b/lang/erlang-runtime17/Makefile
@@ -2,7 +2,7 @@
# $FreeBSD$
PORTNAME= erlang
-PORTVERSION= 17.5
+PORTVERSION= 17.5.1
CATEGORIES= lang parallel java
MASTER_SITES= http://www.erlang.org/download/:erlangorg \
http://erlang.stacken.kth.se/download/:erlangorg \
@@ -188,6 +188,10 @@ post-install:
${TAR} --unlink -xzpf ${DISTDIR}/${DIST_SUBDIR}/${ERLANG_DOCS} \
-C ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}
+ ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2/* \
+ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2.1
+ ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2
+
${INSTALL_DATA} ${WRKSRC}/lib/dialyzer/doc/*.txt \
${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/dialyzer-*/doc/
.endif
diff --git a/lang/erlang-runtime17/files/patch-otp-17.5.1 b/lang/erlang-runtime17/files/patch-otp-17.5.1
new file mode 100644
index 000000000000..296b344a47cb
--- /dev/null
+++ b/lang/erlang-runtime17/files/patch-otp-17.5.1
@@ -0,0 +1,826 @@
+diff --git OTP_VERSION OTP_VERSION
+index 6060b96..9cbaf23 100644
+--- OTP_VERSION
++++ OTP_VERSION
+@@ -1 +1 @@
+-17.5
++17.5.1
+diff --git lib/ssh/doc/src/notes.xml lib/ssh/doc/src/notes.xml
+index f22bca3..acbf312 100644
+--- lib/ssh/doc/src/notes.xml
++++ lib/ssh/doc/src/notes.xml
+@@ -29,6 +29,28 @@
+ <file>notes.xml</file>
+ </header>
+
++<section><title>Ssh 3.2.1</title>
++
++ <section><title>Fixed Bugs and Malfunctions</title>
++ <list>
++ <item>
++ <p>
++ Ssh crashed if a message was sent on a channel with
++ packet_size = 0.</p>
++ <p>
++ A new option for ssh:daemon is also introduced:
++ <c>minimal_remote_max_packet_size</c>. This option sets
++ the least max packet size declaration that the daemon
++ will accept from a client. The default value is 0 to
++ maintain compatibility with OpenSSH and the rfc:s.</p>
++ <p>
++ Own Id: OTP-12645 Aux Id: seq12816 </p>
++ </item>
++ </list>
++ </section>
++
++</section>
++
+ <section><title>Ssh 3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+diff --git lib/ssh/doc/src/ssh.xml lib/ssh/doc/src/ssh.xml
+index d481a75..0e7e384 100644
+--- lib/ssh/doc/src/ssh.xml
++++ lib/ssh/doc/src/ssh.xml
+@@ -338,6 +338,12 @@
+ </warning>
+ </item>
+
++ <tag><c><![CDATA[{minimal_remote_max_packet_size, non_negative_integer()}]]></c></tag>
++ <item>
++ <p>The least maximum packet size that the daemon will accept in channel open requests from the client. The default value is 0.
++ </p>
++ </item>
++
+ <tag><c><![CDATA[{key_cb, atom()}]]></c></tag>
+ <item>
+ <p>Module implementing the behaviour <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
+diff --git lib/ssh/src/ssh.appup.src lib/ssh/src/ssh.appup.src
+index b2b2994..e76c110 100644
+--- lib/ssh/src/ssh.appup.src
++++ lib/ssh/src/ssh.appup.src
+@@ -1,7 +1,7 @@
+ %% -*- erlang -*-
+ %% %CopyrightBegin%
+ %%
+-%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
++%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+ %%
+ %% The contents of this file are subject to the Erlang Public License,
+ %% Version 1.1, (the "License"); you may not use this file except in
+@@ -19,61 +19,9 @@
+
+ {"%VSN%",
+ [
+- {"3.0.8", [{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_xfer]},
+- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
+- {load_module, ssh, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_xfer, soft_purge, soft_purge, []}
+- ]},
+- {"3.0.7", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
+- {load_module, ssh_info, soft_purge, soft_purge, []},
+- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
+- {"3.0.6", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
+- {load_module, ssh_info, soft_purge, soft_purge, []},
+- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
+ {<<".*">>, [{restart_application, ssh}]}
+ ],
+ [
+- {"3.0.8", [{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_sftp, soft_purge, soft_purge, []},
+- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
+- {load_module, ssh, soft_purge, soft_purge, []},
+- {load_module, ssh_xfer, soft_purge, soft_purge, []}
+- ]},
+- {"3.0.7", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
+- {load_module, ssh_info, soft_purge, soft_purge, []},
+- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
+- {"3.0.6", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_connection_handler, soft_purge, soft_purge, []},
+- {load_module, ssh_info, soft_purge, soft_purge, []},
+- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
+- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
+ {<<".*">>, [{restart_application, ssh}]}
+ ]
+ }.
+diff --git lib/ssh/src/ssh.erl lib/ssh/src/ssh.erl
+index eae33e3..51ad691 100644
+--- lib/ssh/src/ssh.erl
++++ lib/ssh/src/ssh.erl
+@@ -345,9 +345,14 @@ handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+ handle_option([parallel_login|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]);
++handle_option([{minimal_remote_max_packet_size, _} = Opt|Rest], SocketOptions, SshOptions) ->
++ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+ handle_option([Opt | Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions).
+
++
++handle_ssh_option({minimal_remote_max_packet_size, Value} = Opt) when is_integer(Value), Value >=0 ->
++ Opt;
+ handle_ssh_option({system_dir, Value} = Opt) when is_list(Value) ->
+ Opt;
+ handle_ssh_option({user_dir, Value} = Opt) when is_list(Value) ->
+diff --git lib/ssh/src/ssh_acceptor.erl lib/ssh/src/ssh_acceptor.erl
+index 6c443ee..34988f1 100644
+--- lib/ssh/src/ssh_acceptor.erl
++++ lib/ssh/src/ssh_acceptor.erl
+@@ -1,7 +1,7 @@
+ %%
+ %% %CopyrightBegin%
+ %%
+-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
++%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+ %%
+ %% The contents of this file are subject to the Erlang Public License,
+ %% Version 1.1, (the "License"); you may not use this file except in
+@@ -43,7 +43,7 @@ start_link(Port, Address, SockOpts, Opts, AcceptTimeout) ->
+ acceptor_init(Parent, Port, Address, SockOpts, Opts, AcceptTimeout) ->
+ {_, Callback, _} =
+ proplists:get_value(transport, Opts, {tcp, gen_tcp, tcp_closed}),
+- case (catch do_socket_listen(Callback, Port, SockOpts)) of
++ case (catch do_socket_listen(Callback, Port, [{active, false} | SockOpts])) of
+ {ok, ListenSocket} ->
+ proc_lib:init_ack(Parent, {ok, self()}),
+ acceptor_loop(Callback,
+diff --git lib/ssh/src/ssh_connection.erl lib/ssh/src/ssh_connection.erl
+index c66f810..654b9d4 100644
+--- lib/ssh/src/ssh_connection.erl
++++ lib/ssh/src/ssh_connection.erl
+@@ -1,7 +1,7 @@
+ %%
+ %% %CopyrightBegin%
+ %%
+-%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
++%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+ %%
+ %% The contents of this file are subject to the Erlang Public License,
+ %% Version 1.1, (the "License"); you may not use this file except in
+@@ -326,9 +326,7 @@ channel_data(ChannelId, DataType, Data,
+ SendDataType,
+ SendData)}
+ end, SendList),
+- FlowCtrlMsgs = flow_control(Replies,
+- Channel,
+- Cache),
++ FlowCtrlMsgs = flow_control(Replies, Channel, Cache),
+ {{replies, Replies ++ FlowCtrlMsgs}, Connection};
+ _ ->
+ gen_fsm:reply(From, {error, closed}),
+@@ -470,18 +468,31 @@ handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId,
+ handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type,
+ sender_channel = RemoteId,
+ initial_window_size = WindowSz,
+- maximum_packet_size = PacketSz}, Connection0, server) ->
+-
+- try setup_session(Connection0, RemoteId,
+- Type, WindowSz, PacketSz) of
+- Result ->
+- Result
+- catch _:_ ->
++ maximum_packet_size = PacketSz},
++ #connection{options = SSHopts} = Connection0,
++ server) ->
++ MinAcceptedPackSz = proplists:get_value(minimal_remote_max_packet_size, SSHopts, 0),
++
++ if
++ MinAcceptedPackSz =< PacketSz ->
++ try setup_session(Connection0, RemoteId,
++ Type, WindowSz, PacketSz) of
++ Result ->
++ Result
++ catch _:_ ->
++ FailMsg = channel_open_failure_msg(RemoteId,
++ ?SSH_OPEN_CONNECT_FAILED,
++ "Connection refused", "en"),
++ {{replies, [{connection_reply, FailMsg}]},
++ Connection0}
++ end;
++
++ MinAcceptedPackSz > PacketSz ->
+ FailMsg = channel_open_failure_msg(RemoteId,
+- ?SSH_OPEN_CONNECT_FAILED,
+- "Connection refused", "en"),
+- {{replies, [{connection_reply, FailMsg}]},
+- Connection0}
++ ?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
++ lists:concat(["Maximum packet size below ",MinAcceptedPackSz,
++ " not supported"]), "en"),
++ {{replies, [{connection_reply, FailMsg}]}, Connection0}
+ end;
+
+ handle_msg(#ssh_msg_channel_open{channel_type = "session",
+@@ -501,41 +512,57 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip" = Type,
+ initial_window_size = RWindowSz,
+ maximum_packet_size = RPacketSz,
+ data = Data},
+- #connection{channel_cache = Cache} = Connection0, server) ->
++ #connection{channel_cache = Cache,
++ options = SSHopts} = Connection0, server) ->
+ <<?UINT32(ALen), Address:ALen/binary, ?UINT32(Port),
+ ?UINT32(OLen), Orig:OLen/binary, ?UINT32(OrigPort)>> = Data,
+
+- case bound_channel(Address, Port, Connection0) of
+- undefined ->
++ MinAcceptedPackSz = proplists:get_value(minimal_remote_max_packet_size, SSHopts, 0),
++
++ if
++ MinAcceptedPackSz =< RPacketSz ->
++ case bound_channel(Address, Port, Connection0) of
++ undefined ->
++ FailMsg = channel_open_failure_msg(RemoteId,
++ ?SSH_OPEN_CONNECT_FAILED,
++ "Connection refused", "en"),
++ {{replies,
++ [{connection_reply, FailMsg}]}, Connection0};
++ ChannelPid ->
++ {ChannelId, Connection1} = new_channel_id(Connection0),
++ LWindowSz = ?DEFAULT_WINDOW_SIZE,
++ LPacketSz = ?DEFAULT_PACKET_SIZE,
++ Channel = #channel{type = Type,
++ sys = "none",
++ user = ChannelPid,
++ local_id = ChannelId,
++ recv_window_size = LWindowSz,
++ recv_packet_size = LPacketSz,
++ send_window_size = RWindowSz,
++ send_packet_size = RPacketSz,
++ send_buf = queue:new()
++ },
++ ssh_channel:cache_update(Cache, Channel),
++ OpenConfMsg = channel_open_confirmation_msg(RemoteId, ChannelId,
++ LWindowSz, LPacketSz),
++ {OpenMsg, Connection} =
++ reply_msg(Channel, Connection1,
++ {open, Channel, {forwarded_tcpip,
++ decode_ip(Address), Port,
++ decode_ip(Orig), OrigPort}}),
++ {{replies, [{connection_reply, OpenConfMsg},
++ OpenMsg]}, Connection}
++ end;
++
++ MinAcceptedPackSz > RPacketSz ->
+ FailMsg = channel_open_failure_msg(RemoteId,
+- ?SSH_OPEN_CONNECT_FAILED,
+- "Connection refused", "en"),
+- {{replies,
+- [{connection_reply, FailMsg}]}, Connection0};
+- ChannelPid ->
+- {ChannelId, Connection1} = new_channel_id(Connection0),
+- LWindowSz = ?DEFAULT_WINDOW_SIZE,
+- LPacketSz = ?DEFAULT_PACKET_SIZE,
+- Channel = #channel{type = Type,
+- sys = "none",
+- user = ChannelPid,
+- local_id = ChannelId,
+- recv_window_size = LWindowSz,
+- recv_packet_size = LPacketSz,
+- send_window_size = RWindowSz,
+- send_packet_size = RPacketSz},
+- ssh_channel:cache_update(Cache, Channel),
+- OpenConfMsg = channel_open_confirmation_msg(RemoteId, ChannelId,
+- LWindowSz, LPacketSz),
+- {OpenMsg, Connection} =
+- reply_msg(Channel, Connection1,
+- {open, Channel, {forwarded_tcpip,
+- decode_ip(Address), Port,
+- decode_ip(Orig), OrigPort}}),
+- {{replies, [{connection_reply, OpenConfMsg},
+- OpenMsg]}, Connection}
++ ?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
++ lists:concat(["Maximum packet size below ",MinAcceptedPackSz,
++ " not supported"]), "en"),
++ {{replies, [{connection_reply, FailMsg}]}, Connection0}
+ end;
+
++
+ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip",
+ sender_channel = RemoteId},
+ Connection, client) ->
+@@ -917,7 +944,8 @@ start_channel(Cb, Id, Args, SubSysSup, Exec) ->
+ %%--------------------------------------------------------------------
+ %%% Internal functions
+ %%--------------------------------------------------------------------
+-setup_session(#connection{channel_cache = Cache} = Connection0,
++setup_session(#connection{channel_cache = Cache
++ } = Connection0,
+ RemoteId,
+ Type, WindowSize, PacketSize) ->
+ {ChannelId, Connection} = new_channel_id(Connection0),
+@@ -929,6 +957,7 @@ setup_session(#connection{channel_cache = Cache} = Connection0,
+ recv_packet_size = ?DEFAULT_PACKET_SIZE,
+ send_window_size = WindowSize,
+ send_packet_size = PacketSize,
++ send_buf = queue:new(),
+ remote_id = RemoteId
+ },
+ ssh_channel:cache_update(Cache, Channel),
+@@ -1024,63 +1053,74 @@ request_reply_or_data(#channel{local_id = ChannelId, user = ChannelPid},
+
+ update_send_window(Channel, _, undefined,
+ #connection{channel_cache = Cache}) ->
+- do_update_send_window(Channel, Channel#channel.send_buf, Cache);
++ do_update_send_window(Channel, Cache);
+
+-update_send_window(Channel, DataType, Data,
++update_send_window(#channel{send_buf = SendBuffer} = Channel, DataType, Data,
+ #connection{channel_cache = Cache}) ->
+- do_update_send_window(Channel, Channel#channel.send_buf ++ [{DataType, Data}], Cache).
++ do_update_send_window(Channel#channel{send_buf = queue:in({DataType, Data}, SendBuffer)},
++ Cache).
+
+-do_update_send_window(Channel0, Buf0, Cache) ->
+- {Buf1, NewSz, Buf2} = get_window(Buf0,
+- Channel0#channel.send_packet_size,
+- Channel0#channel.send_window_size),
+-
+- Channel = Channel0#channel{send_window_size = NewSz, send_buf = Buf2},
++do_update_send_window(Channel0, Cache) ->
++ {SendMsgs, Channel} = get_window(Channel0, []),
+ ssh_channel:cache_update(Cache, Channel),
+- {Buf1, Channel}.
++ {SendMsgs, Channel}.
+
+-get_window(Bs, PSz, WSz) ->
+- get_window(Bs, PSz, WSz, []).
+-
+-get_window(Bs, _PSz, 0, Acc) ->
+- {lists:reverse(Acc), 0, Bs};
+-get_window([B0 = {DataType, Bin} | Bs], PSz, WSz, Acc) ->
+- BSz = size(Bin),
+- if BSz =< WSz -> %% will fit into window
+- if BSz =< PSz -> %% will fit into a packet
+- get_window(Bs, PSz, WSz-BSz, [B0|Acc]);
+- true -> %% split into packet size
+- <<Bin1:PSz/binary, Bin2/binary>> = Bin,
+- get_window([setelement(2, B0, Bin2) | Bs],
+- PSz, WSz-PSz,
+- [{DataType, Bin1}|Acc])
++get_window(#channel{send_window_size = 0
++ } = Channel, Acc) ->
++ {lists:reverse(Acc), Channel};
++get_window(#channel{send_packet_size = 0
++ } = Channel, Acc) ->
++ {lists:reverse(Acc), Channel};
++get_window(#channel{send_buf = Buffer,
++ send_packet_size = PacketSize,
++ send_window_size = WindowSize0
++ } = Channel, Acc0) ->
++ case queue:out(Buffer) of
++ {{value, {_, Data} = Msg}, NewBuffer} ->
++ case handle_send_window(Msg, size(Data), PacketSize, WindowSize0, Acc0) of
++ {WindowSize, Acc, {_, <<>>}} ->
++ {lists:reverse(Acc), Channel#channel{send_window_size = WindowSize,
++ send_buf = NewBuffer}};
++ {WindowSize, Acc, Rest} ->
++ get_window(Channel#channel{send_window_size = WindowSize,
++ send_buf = queue:in_r(Rest, NewBuffer)}, Acc)
+ end;
+- WSz =< PSz -> %% use rest of window
+- <<Bin1:WSz/binary, Bin2/binary>> = Bin,
+- get_window([setelement(2, B0, Bin2) | Bs],
+- PSz, WSz-WSz,
+- [{DataType, Bin1}|Acc]);
+- true -> %% use packet size
+- <<Bin1:PSz/binary, Bin2/binary>> = Bin,
+- get_window([setelement(2, B0, Bin2) | Bs],
+- PSz, WSz-PSz,
+- [{DataType, Bin1}|Acc])
++ {empty, NewBuffer} ->
++ {[], Channel#channel{send_buf = NewBuffer}}
++ end.
++
++handle_send_window(Msg = {Type, Data}, Size, PacketSize, WindowSize, Acc) when Size =< WindowSize ->
++ case Size =< PacketSize of
++ true ->
++ {WindowSize - Size, [Msg | Acc], {Type, <<>>}};
++ false ->
++ <<Msg1:PacketSize/binary, Msg2/binary>> = Data,
++ {WindowSize - PacketSize, [{Type, Msg1} | Acc], {Type, Msg2}}
+ end;
+-get_window([], _PSz, WSz, Acc) ->
+- {lists:reverse(Acc), WSz, []}.
++handle_send_window({Type, Data}, _, PacketSize, WindowSize, Acc) when WindowSize =< PacketSize ->
++ <<Msg1:WindowSize/binary, Msg2/binary>> = Data,
++ {WindowSize - WindowSize, [{Type, Msg1} | Acc], {Type, Msg2}};
++handle_send_window({Type, Data}, _, PacketSize, WindowSize, Acc) ->
++ <<Msg1:PacketSize/binary, Msg2/binary>> = Data,
++ {WindowSize - PacketSize, [{Type, Msg1} | Acc], {Type, Msg2}}.
+
+ flow_control(Channel, Cache) ->
+ flow_control([window_adjusted], Channel, Cache).
+-
++
+ flow_control([], Channel, Cache) ->
+ ssh_channel:cache_update(Cache, Channel),
+ [];
+-
+ flow_control([_|_], #channel{flow_control = From,
+- send_buf = []} = Channel, Cache) when From =/= undefined ->
+- [{flow_control, Cache, Channel, From, ok}];
++ send_buf = Buffer} = Channel, Cache) when From =/= undefined ->
++ case queue:is_empty(Buffer) of
++ true ->
++ ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}),
++ [{flow_control, Cache, Channel, From, ok}];
++ false ->
++ []
++ end;
+ flow_control(_,_,_) ->
+- [].
++ [].
+
+ pty_req(ConnectionHandler, Channel, Term, Width, Height,
+ PixWidth, PixHeight, PtyOpts, TimeOut) ->
+diff --git lib/ssh/src/ssh_connection_handler.erl lib/ssh/src/ssh_connection_handler.erl
+index 68523aa..e1f2e05 100644
+--- lib/ssh/src/ssh_connection_handler.erl
++++ lib/ssh/src/ssh_connection_handler.erl
+@@ -1,7 +1,7 @@
+ %%
+ %% %CopyrightBegin%
+ %%
+-%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
++%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+ %%
+ %% The contents of this file are subject to the Erlang Public License,
+ %% Version 1.1, (the "License"); you may not use this file except in
+@@ -751,7 +751,9 @@ handle_sync_event({open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Dat
+ user = ChannelPid,
+ local_id = ChannelId,
+ recv_window_size = InitialWindowSize,
+- recv_packet_size = MaxPacketSize},
++ recv_packet_size = MaxPacketSize,
++ send_buf = queue:new()
++ },
+ ssh_channel:cache_update(Cache, Channel),
+ State = add_request(true, ChannelId, From, State2),
+ start_timeout(ChannelId, From, Timeout),
+@@ -1241,10 +1243,9 @@ event(Event, StateName, State) ->
+ handle_disconnect(DisconnectMsg, State);
+ throw:{ErrorToDisplay, #ssh_msg_disconnect{} = DisconnectMsg} ->
+ handle_disconnect(DisconnectMsg, State, ErrorToDisplay);
+- _:Error ->
+- log_error(Error),
++ _:_ ->
+ handle_disconnect(#ssh_msg_disconnect{code = error_code(StateName),
+- description = "Internal error",
++ description = "Invalid state",
+ language = "en"}, State)
+ end.
+ error_code(key_exchange) ->
+diff --git lib/ssh/src/ssh_info.erl lib/ssh/src/ssh_info.erl
+index 9a91875..30df32c 100644
+--- lib/ssh/src/ssh_info.erl
++++ lib/ssh/src/ssh_info.erl
+@@ -27,18 +27,21 @@
+ -compile(export_all).
+
+ print() ->
++ print(user).
++
++print(D) ->
+ try supervisor:which_children(ssh_sup)
+ of
+ _ ->
+- io:nl(),
+- print_general(),
+- io:nl(),
+- underline("Client part", $=),
+- print_clients(),
+- io:nl(),
+- underline("Server part", $=),
+- print_servers(),
+- io:nl(),
++ io:nl(D),
++ print_general(D),
++ io:nl(D),
++ underline(D, "Client part", $=),
++ print_clients(D),
++ io:nl(D),
++ underline(D, "Server part", $=),
++ print_servers(D),
++ io:nl(D),
+ %% case os:type() of
+ %% {unix,_} ->
+ %% io:nl(),
+@@ -50,90 +53,95 @@ print() ->
+ %% catch io:format(os:cmd("netstat -tpn"));
+ %% _ -> ok
+ %% end,
+- underline("Supervisors", $=),
+- walk_sups(ssh_sup),
+- io:nl()
++ underline(D, "Supervisors", $=),
++ walk_sups(D, ssh_sup),
++ io:nl(D)
+ catch
+ _:_ ->
+- io:format("Ssh not found~n",[])
++ io:format(D,"Ssh not found~n",[])
+ end.
+
+ %%%================================================================
+-print_general() ->
++print_general(D) ->
+ {_Name, Slogan, Ver} = lists:keyfind(ssh,1,application:which_applications()),
+- underline(io_lib:format("~s ~s", [Slogan, Ver]), $=),
+- io:format('This printout is generated ~s. ~n',[datetime()]).
++ underline(D, io_lib:format("~s ~s", [Slogan, Ver]), $=),
++ io:format(D, 'This printout is generated ~s. ~n',[datetime()]).
+
+ %%%================================================================
+-print_clients() ->
++print_clients(D) ->
++ PrintClient = fun(X) -> print_client(D,X) end,
+ try
+- lists:foreach(fun print_client/1, supervisor:which_children(sshc_sup))
++ lists:foreach(PrintClient, supervisor:which_children(sshc_sup))
+ catch
+ C:E ->
+- io:format('***FAILED: ~p:~p~n',[C,E])
++ io:format(D, '***FAILED: ~p:~p~n',[C,E])
+ end.
+
+-print_client({undefined,Pid,supervisor,[ssh_connection_handler]}) ->
++print_client(D, {undefined,Pid,supervisor,[ssh_connection_handler]}) ->
+ {{Local,Remote},_Str} = ssh_connection_handler:get_print_info(Pid),
+- io:format(" Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]);
+-print_client(Other) ->
+- io:format(" [[Other 1: ~p]]~n",[Other]).
++ io:format(D, " Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]);
++print_client(D, Other) ->
++ io:format(D, " [[Other 1: ~p]]~n",[Other]).
+
+
+ %%%================================================================
+-print_servers() ->
++print_servers(D) ->
++ PrintServer = fun(X) -> print_server(D,X) end,
+ try
+- lists:foreach(fun print_server/1, supervisor:which_children(sshd_sup))
++ lists:foreach(PrintServer, supervisor:which_children(sshd_sup))
+ catch
+ C:E ->
+- io:format('***FAILED: ~p:~p~n',[C,E])
++ io:format(D, '***FAILED: ~p:~p~n',[C,E])
+ end.
+
+-print_server({{server,ssh_system_sup,LocalHost,LocalPort},Pid,supervisor,[ssh_system_sup]}) when is_pid(Pid) ->
+- io:format('Local=~s (~p children)~n',[fmt_host_port({LocalHost,LocalPort}),
+- ssh_acceptor:number_of_connections(Pid)]),
+- lists:foreach(fun print_system_sup/1, supervisor:which_children(Pid));
+-print_server(Other) ->
+- io:format(" [[Other 2: ~p]]~n",[Other]).
++print_server(D, {{server,ssh_system_sup,LocalHost,LocalPort},Pid,supervisor,[ssh_system_sup]}) when is_pid(Pid) ->
++ io:format(D, 'Local=~s (~p children)~n',[fmt_host_port({LocalHost,LocalPort}),
++ ssh_acceptor:number_of_connections(Pid)]),
++ PrintSystemSup = fun(X) -> print_system_sup(D,X) end,
++ lists:foreach(PrintSystemSup, supervisor:which_children(Pid));
++print_server(D, Other) ->
++ io:format(D, " [[Other 2: ~p]]~n",[Other]).
+
+-print_system_sup({Ref,Pid,supervisor,[ssh_subsystem_sup]}) when is_reference(Ref),
++print_system_sup(D, {Ref,Pid,supervisor,[ssh_subsystem_sup]}) when is_reference(Ref),
+ is_pid(Pid) ->
+- lists:foreach(fun print_channels/1, supervisor:which_children(Pid));
+-print_system_sup({{ssh_acceptor_sup,LocalHost,LocalPort}, Pid,supervisor, [ssh_acceptor_sup]}) when is_pid(Pid) ->
+- io:format(" [Acceptor for ~s]~n",[fmt_host_port({LocalHost,LocalPort})]);
+-print_system_sup(Other) ->
+- io:format(" [[Other 3: ~p]]~n",[Other]).
++ PrintChannels = fun(X) -> print_channels(D,X) end,
++ lists:foreach(PrintChannels, supervisor:which_children(Pid));
++print_system_sup(D, {{ssh_acceptor_sup,LocalHost,LocalPort}, Pid,supervisor, [ssh_acceptor_sup]}) when is_pid(Pid) ->
++ io:format(D, " [Acceptor for ~s]~n",[fmt_host_port({LocalHost,LocalPort})]);
++print_system_sup(D, Other) ->
++ io:format(D, " [[Other 3: ~p]]~n",[Other]).
+
+-print_channels({{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) ->
+- lists:foreach(fun print_channel/1, supervisor:which_children(Pid));
+-print_channels(Other) ->
+- io:format(" [[Other 4: ~p]]~n",[Other]).
++print_channels(D, {{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) ->
++ PrintChannel = fun(X) -> print_channel(D,X) end,
++ lists:foreach(PrintChannel, supervisor:which_children(Pid));
++print_channels(D, Other) ->
++ io:format(D, " [[Other 4: ~p]]~n",[Other]).
+
+
+-print_channel({Ref,Pid,worker,[ssh_channel]}) when is_reference(Ref),
+- is_pid(Pid) ->
++print_channel(D, {Ref,Pid,worker,[ssh_channel]}) when is_reference(Ref),
++ is_pid(Pid) ->
+ {{ConnManager,ChannelID}, Str} = ssh_channel:get_print_info(Pid),
+ {{Local,Remote},StrM} = ssh_connection_handler:get_print_info(ConnManager),
+- io:format(' ch ~p: ~s ~s',[ChannelID, StrM, Str]),
+- io:format(" Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]);
+-print_channel(Other) ->
+- io:format(" [[Other 5: ~p]]~n",[Other]).
++ io:format(D, ' ch ~p: ~s ~s',[ChannelID, StrM, Str]),
++ io:format(D, " Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]);
++print_channel(D, Other) ->
++ io:format(D, " [[Other 5: ~p]]~n",[Other]).
+
+ %%%================================================================
+ -define(inc(N), (N+4)).
+
+-walk_sups(StartPid) ->
+- io:format("Start at ~p, ~s.~n",[StartPid,dead_or_alive(StartPid)]),
+- walk_sups(children(StartPid), _Indent=?inc(0)).
++walk_sups(D, StartPid) ->
++ io:format(D, "Start at ~p, ~s.~n",[StartPid,dead_or_alive(StartPid)]),
++ walk_sups(D, children(StartPid), _Indent=?inc(0)).
+
+-walk_sups([H={_,Pid,SupOrWorker,_}|T], Indent) ->
+- indent(Indent), io:format('~200p ~p is ~s~n',[H,Pid,dead_or_alive(Pid)]),
++walk_sups(D, [H={_,Pid,SupOrWorker,_}|T], Indent) ->
++ indent(D, Indent), io:format(D, '~200p ~p is ~s~n',[H,Pid,dead_or_alive(Pid)]),
+ case SupOrWorker of
+- supervisor -> walk_sups(children(Pid), ?inc(Indent));
++ supervisor -> walk_sups(D, children(Pid), ?inc(Indent));
+ _ -> ok
+ end,
+- walk_sups(T, Indent);
+-walk_sups([], _) ->
++ walk_sups(D, T, Indent);
++walk_sups(_D, [], _) ->
+ ok.
+
+ dead_or_alive(Name) when is_atom(Name) ->
+@@ -149,7 +157,7 @@ dead_or_alive(Pid) when is_pid(Pid) ->
+ _ -> "alive"
+ end.
+
+-indent(I) -> io:format('~*c',[I,$ ]).
++indent(D, I) -> io:format(D,'~*c',[I,$ ]).
+
+ children(Pid) ->
+ Parent = self(),
+@@ -166,16 +174,16 @@ children(Pid) ->
+ end.
+
+ %%%================================================================
+-underline(Str) ->
+- underline(Str, $-).
++underline(D, Str) ->
++ underline(D, Str, $-).
+
+-underline(Str, LineChar) ->
++underline(D, Str, LineChar) ->
+ Len = lists:flatlength(Str),
+- io:format('~s~n',[Str]),
+- line(Len,LineChar).
++ io:format(D, '~s~n',[Str]),
++ line(D,Len,LineChar).
+
+-line(Len, Char) ->
+- io:format('~*c~n', [Len,Char]).
++line(D, Len, Char) ->
++ io:format(D, '~*c~n', [Len,Char]).
+
+
+ datetime() ->
+@@ -188,6 +196,6 @@ fmt_host_port({Host,Port}) -> io_lib:format('~s:~p',[Host,Port]).
+
+
+
+-nyi() ->
+- io:format('Not yet implemented~n',[]),
++nyi(D) ->
++ io:format(D,'Not yet implemented~n',[]),
+ nyi.
+diff --git lib/ssh/test/ssh_basic_SUITE.erl lib/ssh/test/ssh_basic_SUITE.erl
+index 45c0303..81c7b5c 100644
+--- lib/ssh/test/ssh_basic_SUITE.erl
++++ lib/ssh/test/ssh_basic_SUITE.erl
+@@ -50,6 +50,8 @@ all() ->
+ double_close,
+ ssh_connect_timeout,
+ ssh_connect_arg4_timeout,
++ packet_size_zero,
++ ssh_daemon_minimal_remote_max_packet_size_option,
+ {group, hardening_tests}
+ ].
+
+@@ -757,6 +759,64 @@ ms_passed(N1={_,_,M1}, N2={_,_,M2}) ->
+ 1000 * (Min*60 + Sec + (M2-M1)/1000000).
+
+ %%--------------------------------------------------------------------
++packet_size_zero(Config) ->
++ SystemDir = ?config(data_dir, Config),
++ PrivDir = ?config(priv_dir, Config),
++ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
++ file:make_dir(UserDir),
++
++ {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
++ {user_dir, UserDir},
++ {user_passwords, [{"vego", "morot"}]}]),
++ Conn =
++ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
++ {user_dir, UserDir},
++ {user_interaction, false},
++ {user, "vego"},
++ {password, "morot"}]),
++
++ {ok,Chan} = ssh_connection:session_channel(Conn, 1000, _MaxPacketSize=0, 60000),
++ ok = ssh_connection:shell(Conn, Chan),
++
++ ssh:close(Conn),
++ ssh:stop_daemon(Server),
++
++ receive
++ {ssh_cm,Conn,{data,Chan,_Type,_Msg1}} = M ->
++ ct:pal("Got ~p",[M]),
++ ct:fail(doesnt_obey_max_packet_size_0)
++ after 5000 ->
++ ok
++ end.
++
++%%--------------------------------------------------------------------
++ssh_daemon_minimal_remote_max_packet_size_option(Config) ->
++ SystemDir = ?config(data_dir, Config),
++ PrivDir = ?config(priv_dir, Config),
++ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
++ file:make_dir(UserDir),
++
++ {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
++ {user_dir, UserDir},
++ {user_passwords, [{"vego", "morot"}]},
++ {failfun, fun ssh_test_lib:failfun/2},
++ {minimal_remote_max_packet_size, 14}]),
++ Conn =
++ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
++ {user_dir, UserDir},
++ {user_interaction, false},
++ {user, "vego"},
++ {password, "morot"}]),
++
++ %% Try the limits of the minimal_remote_max_packet_size:
++ {ok, _ChannelId} = ssh_connection:session_channel(Conn, 100, 14, infinity),
++ {open_error,_,"Maximum packet size below 14 not supported",_} =
++ ssh_connection:session_channel(Conn, 100, 13, infinity),
++
++ ssh:close(Conn),
++ ssh:stop_daemon(Server).
++
++%%--------------------------------------------------------------------
+ ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true).
+ ssh_connect_negtimeout_sequential(Config) -> ssh_connect_negtimeout(Config,false).
+
+@@ -970,7 +1030,7 @@ max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) ->
+
+ %% Due to timing the error message may or may not be delivered to
+ %% the "tcp-application" before the socket closed message is recived
+-check_error("Internal error") ->
++check_error("Invalid state") ->
+ ok;
+ check_error("Connection closed") ->
+ ok;
+diff --git lib/ssh/vsn.mk lib/ssh/vsn.mk
+index 0d90278..fec8dac 100644
+--- lib/ssh/vsn.mk
++++ lib/ssh/vsn.mk
+@@ -1,5 +1,4 @@
+ #-*-makefile-*- ; force emacs to enter makefile-mode
+
+-SSH_VSN = 3.2
++SSH_VSN = 3.2.1
+ APP_VSN = "ssh-$(SSH_VSN)"
+-
+diff --git otp_versions.table otp_versions.table
+index 64ffd82..a82f535 100644
+--- otp_versions.table
++++ otp_versions.table
+@@ -1,3 +1,4 @@
++OTP-17.5.1 : ssh-3.2.1 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
+ OTP-17.5 : asn1-3.0.4 common_test-1.10 compiler-5.0.4 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 eldap-1.1.1 erts-6.4 hipe-3.11.3 inets-5.10.6 kernel-3.2 mnesia-4.12.5 observer-2.0.4 os_mon-2.3.1 public_key-0.23 runtime_tools-1.8.16 ssh-3.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 wx-1.3.3 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 edoc-0.7.16 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 ic-4.3.6 jinterface-1.5.12 megaco-3.17.3 odbc-2.10.22 orber-3.7.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 reltool-0.6.6 sasl-2.4.1 snmp-5.1.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 :
+ OTP-17.4.1 : erts-6.3.1 inets-5.10.5 # asn1-3.0.3 common_test-1.9 compiler-5.0.3 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.2 ic-4.3.6 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.15 sasl-2.4.1 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 typer-0.9.8 webtool-0.8.10 wx-1.3.2 xmerl-1.3.7 :
+ OTP-17.4 : asn1-3.0.3 common_test-1.9 compiler-5.0.3 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.3 eunit-2.2.9 hipe-3.11.2 inets-5.10.4 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 runtime_tools-1.8.15 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 wx-1.3.2 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 et-1.5 gs-1.5.16 ic-4.3.6 orber-3.7.1 os_mon-2.3 ose-1.0.2 public_key-0.22.1 reltool-0.6.6 sasl-2.4.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 :