From 600a56059a879a1714cd7f93bcb19f955fe91bca Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Tue, 30 Oct 2012 11:41:06 +0100
Subject: Timeout after 1h of idle on connection, which exits the connection
---
lib/ssh/src/ssh_connection_manager.erl | 31 ++++++++++++++++++++++++++++---
1 file changed, 28 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index 422d9356d5..2d0830857f 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -62,6 +62,7 @@
latest_channel_id = 0,
opts,
channel_args,
+ timer_ref, % timerref
connected
}).
@@ -203,6 +204,7 @@ init([client, Opts]) ->
ChannelPid = proplists:get_value(channel_pid, Opts),
self() !
{start_connection, client, [Parent, Address, Port, SocketOpts, Options]},
+ TimerRef = erlang:send_after(3600000, self(), {'EXIT', [], "Timeout"}),
{ok, #state{role = client,
client = ChannelPid,
connection_state = #connection{channel_cache = Cache,
@@ -211,6 +213,7 @@ init([client, Opts]) ->
connection_supervisor = Parent,
requests = []},
opts = Opts,
+ timer_ref = TimerRef,
connected = false}}.
%%--------------------------------------------------------------------
@@ -358,7 +361,7 @@ handle_call({open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data},
recv_packet_size = MaxPacketSize},
ssh_channel:cache_update(Cache, Channel),
State = add_request(true, ChannelId, From, State1),
- {noreply, State};
+ {noreply, remove_timer_ref(State)};
handle_call({send_window, ChannelId}, _From,
#state{connection_state =
@@ -403,6 +406,7 @@ handle_call({close, ChannelId}, _,
send_msg({connection_reply, Pid,
ssh_connection:channel_close_msg(Id)}),
ssh_channel:cache_update(Cache, Channel#channel{sent_close = true}),
+ erlang:send_after(3600000, self(), {check_cache, [], []}),
{reply, ok, State};
undefined ->
{reply, ok, State}
@@ -523,7 +527,10 @@ handle_info({start_connection, client,
Pid ! {self(), not_connected, Reason},
{stop, {shutdown, normal}, State}
end;
-
+handle_info({check_cache, _ , _},
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State) ->
+ {noreply, check_cache(State, Cache)};
handle_info({ssh_cm, _Sender, Msg}, State0) ->
%% Backwards compatibility!
State = cm_message(Msg, State0),
@@ -580,6 +587,24 @@ code_change(_OldVsn, State, _Extra) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+check_cache(State, Cache) ->
+ %% Check the number of entries in Cache
+ case proplists:get_value(size, ets:info(Cache)) of
+ 0 ->
+ TimerRef = erlang:send_after(3600000, self(), {'EXIT', [], "Timeout"}),
+ State#state{timer_ref=TimerRef};
+ _ ->
+ State
+ end.
+remove_timer_ref(State) ->
+ case State#state.timer_ref of
+ undefined ->
+ State;
+ _ ->
+ TimerRef = State#state.timer_ref,
+ erlang:cancel_timer(TimerRef),
+ State#state{timer_ref = undefined}
+ end.
channel_data(Id, Type, Data, Connection0, ConnectionPid, From, State) ->
case ssh_connection:channel_data(Id, Type, Data, Connection0,
ConnectionPid, From) of
@@ -677,7 +702,7 @@ handle_channel_down(ChannelPid, #state{connection_state =
(_,Acc) ->
Acc
end, [], Cache),
- {{replies, []}, State}.
+ {{replies, []}, check_cache(State, Cache)}.
update_sys(Cache, Channel, Type, ChannelPid) ->
ssh_channel:cache_update(Cache,
--
cgit v1.2.3
From 7e6bfd3101d25d4a8061ab7a59002740ee021376 Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Tue, 30 Oct 2012 17:25:34 +0100
Subject: Option idle_time introduced, it will trigger the timer and if it is
not given the timer_ref entry is infinity
---
lib/ssh/src/ssh.erl | 13 +++++++++++-
lib/ssh/src/ssh_connection_manager.erl | 36 ++++++++++++++++++++++++----------
2 files changed, 38 insertions(+), 11 deletions(-)
(limited to 'lib')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 3395f73884..db753e0e4e 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -79,7 +79,7 @@ connect(Host, Port, Options, Timeout) ->
DisableIpv6 = proplists:get_value(ip_v6_disabled, SshOptions, false),
Inet = inetopt(DisableIpv6),
do_connect(Host, Port, [Inet | SocketOptions],
- [{host, Host} | SshOptions], Timeout, DisableIpv6)
+ [{host, Host} | fix_idle_time(SshOptions)], Timeout, DisableIpv6)
end.
do_connect(Host, Port, SocketOptions, SshOptions, Timeout, DisableIpv6) ->
@@ -237,6 +237,13 @@ shell(Host, Port, Options) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+fix_idle_time(SshOptions) ->
+ case proplists:get_value(idle_time, SshOptions) of
+ undefined ->
+ [{idle_time, infinity}|SshOptions];
+ _ ->
+ SshOptions
+ end.
start_daemon(Host, Port, Options, Inet) ->
case handle_options(Options) of
{error, _Reason} = Error ->
@@ -342,6 +349,8 @@ handle_option([{exec, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{auth_methods, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{idle_time, _} = 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).
@@ -407,6 +416,8 @@ handle_ssh_option({shell, {Module, Function, _}} = Opt) when is_atom(Module),
Opt;
handle_ssh_option({shell, Value} = Opt) when is_function(Value) ->
Opt;
+handle_ssh_option({idle_time, Value} = Opt) when is_integer(Value), Value > 0 ->
+ Opt;
handle_ssh_option(Opt) ->
throw({error, {eoptions, Opt}}).
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index 2d0830857f..2e62312423 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -62,7 +62,7 @@
latest_channel_id = 0,
opts,
channel_args,
- timer_ref, % timerref
+ idle_timer_ref, % timerref
connected
}).
@@ -204,7 +204,8 @@ init([client, Opts]) ->
ChannelPid = proplists:get_value(channel_pid, Opts),
self() !
{start_connection, client, [Parent, Address, Port, SocketOpts, Options]},
- TimerRef = erlang:send_after(3600000, self(), {'EXIT', [], "Timeout"}),
+ TimerRef = get_idle_time(Options),
+
{ok, #state{role = client,
client = ChannelPid,
connection_state = #connection{channel_cache = Cache,
@@ -213,7 +214,7 @@ init([client, Opts]) ->
connection_supervisor = Parent,
requests = []},
opts = Opts,
- timer_ref = TimerRef,
+ idle_timer_ref = TimerRef,
connected = false}}.
%%--------------------------------------------------------------------
@@ -406,7 +407,13 @@ handle_call({close, ChannelId}, _,
send_msg({connection_reply, Pid,
ssh_connection:channel_close_msg(Id)}),
ssh_channel:cache_update(Cache, Channel#channel{sent_close = true}),
- erlang:send_after(3600000, self(), {check_cache, [], []}),
+ SshOpts = proplists:get_value(ssh_opts, State#state.opts),
+ case proplists:get_value(idle_time, SshOpts) of
+ infinity ->
+ ok;
+ _IdleTime ->
+ erlang:send_after(5000, self(), {check_cache, [], []})
+ end,
{reply, ok, State};
undefined ->
{reply, ok, State}
@@ -587,23 +594,32 @@ code_change(_OldVsn, State, _Extra) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+get_idle_time(SshOptions) ->
+ case proplists:get_value(idle_time, SshOptions) of
+ infinity ->
+ infinity;
+ IdleTime ->
+ TimerRef = erlang:send_after(IdleTime, self(), {'EXIT', [], "Timeout"}),
+ TimerRef
+ end.
check_cache(State, Cache) ->
%% Check the number of entries in Cache
case proplists:get_value(size, ets:info(Cache)) of
0 ->
- TimerRef = erlang:send_after(3600000, self(), {'EXIT', [], "Timeout"}),
- State#state{timer_ref=TimerRef};
+ Opts = proplists:get_value(ssh_opts, State#state.opts),
+ TimerRef = erlang:send_after(proplists:get_value(idle_time, Opts), self(), {'EXIT', [], "Timeout"}),
+ State#state{idle_timer_ref=TimerRef};
_ ->
State
end.
remove_timer_ref(State) ->
- case State#state.timer_ref of
- undefined ->
+ case State#state.idle_timer_ref of
+ infinity ->
State;
_ ->
- TimerRef = State#state.timer_ref,
+ TimerRef = State#state.idle_timer_ref,
erlang:cancel_timer(TimerRef),
- State#state{timer_ref = undefined}
+ State#state{idle_timer_ref = undefined}
end.
channel_data(Id, Type, Data, Connection0, ConnectionPid, From, State) ->
case ssh_connection:channel_data(Id, Type, Data, Connection0,
--
cgit v1.2.3
From b788929349f4eec4980dd2181d92f7df3687db85 Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Wed, 31 Oct 2012 09:34:18 +0100
Subject: handle no idle-timer on check cache
---
lib/ssh/src/ssh_connection_manager.erl | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index 2e62312423..6e2fe9da74 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -607,8 +607,15 @@ check_cache(State, Cache) ->
case proplists:get_value(size, ets:info(Cache)) of
0 ->
Opts = proplists:get_value(ssh_opts, State#state.opts),
- TimerRef = erlang:send_after(proplists:get_value(idle_time, Opts), self(), {'EXIT', [], "Timeout"}),
- State#state{idle_timer_ref=TimerRef};
+ case proplists:get_value(idle_time, Opts) of
+ infinity ->
+ State;
+ undefined ->
+ State;
+ Time ->
+ TimerRef = erlang:send_after(Time, self(), {'EXIT', [], "Timeout"}),
+ State#state{idle_timer_ref=TimerRef}
+ end;
_ ->
State
end.
--
cgit v1.2.3
From 8e8b61c63431096cc8fdd4eaea7d7ed33c143847 Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Wed, 31 Oct 2012 10:45:16 +0100
Subject: Check cache on channel exec
---
lib/ssh/src/ssh_connection_manager.erl | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index 6e2fe9da74..9a96542505 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -234,6 +234,13 @@ handle_call({request, ChannelPid, ChannelId, Type, Data}, From, State0) ->
%% channel is sent later when reply arrives from the connection
%% handler.
lists:foreach(fun send_msg/1, Replies),
+ SshOpts = proplists:get_value(ssh_opts, State0#state.opts),
+ case proplists:get_value(idle_time, SshOpts) of
+ infinity ->
+ ok;
+ _IdleTime ->
+ erlang:send_after(5000, self(), {check_cache, [], []})
+ end,
{noreply, State};
handle_call({request, ChannelId, Type, Data}, From, State0) ->
@@ -613,18 +620,24 @@ check_cache(State, Cache) ->
undefined ->
State;
Time ->
- TimerRef = erlang:send_after(Time, self(), {'EXIT', [], "Timeout"}),
- State#state{idle_timer_ref=TimerRef}
+ case State#state.idle_timer_ref of
+ undefined ->
+ TimerRef = erlang:send_after(Time, self(), {'EXIT', [], "Timeout"}),
+ State#state{idle_timer_ref=TimerRef};
+ _ ->
+ State
+ end
end;
_ ->
State
end.
remove_timer_ref(State) ->
case State#state.idle_timer_ref of
- infinity ->
+ infinity -> %% If the timer is not activated
State;
- _ ->
- TimerRef = State#state.idle_timer_ref,
+ undefined -> %% If we already has cancelled the timer
+ State;
+ TimerRef -> %% Timer is active
erlang:cancel_timer(TimerRef),
State#state{idle_timer_ref = undefined}
end.
--
cgit v1.2.3
From 9c9e054f56b9bf05dfca8697e5df318e2ce6a3cd Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Wed, 31 Oct 2012 14:51:42 +0100
Subject: Doc about idle_time option to ssh:connect
---
lib/ssh/doc/src/ssh.xml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 0133250979..07f657da70 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -184,7 +184,10 @@
(simply passed on to the transport protocol).
-
-
Determines if SSH shall use IPv6 or not.
+ Determines if SSH shall use IPv6 or not.
+
+ -
+
Sets a timeout on connection when not used and no channels are active, default is infinity
--
cgit v1.2.3
From 104d902c2e325060ab66abc05a449194792dee7a Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Mon, 5 Nov 2012 11:39:12 +0100
Subject: Not start the idle timer on connect
---
lib/ssh/src/ssh_connection_manager.erl | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index 9a96542505..1384740bfa 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -605,9 +605,8 @@ get_idle_time(SshOptions) ->
case proplists:get_value(idle_time, SshOptions) of
infinity ->
infinity;
- IdleTime ->
- TimerRef = erlang:send_after(IdleTime, self(), {'EXIT', [], "Timeout"}),
- TimerRef
+ _IdleTime -> %% We dont want to set the timeout on first connect
+ undefined
end.
check_cache(State, Cache) ->
%% Check the number of entries in Cache
--
cgit v1.2.3
From 6a17960f0610ebaa332cf7f2037d01df47f5f5d8 Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Mon, 5 Nov 2012 12:40:02 +0100
Subject: Added testcase for idle timer
---
lib/ssh/test/ssh_basic_SUITE.erl | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 7a641c92c1..61b91e3a25 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -42,6 +42,7 @@ all() ->
{group, dsa_pass_key},
{group, rsa_pass_key},
{group, internal_error},
+ idle_time,
daemon_already_started,
server_password_option,
server_userpassword_option,
@@ -234,7 +235,28 @@ exec_compressed(Config) when is_list(Config) ->
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
-
+idle_time(doc) ->
+ ["Idle timeout test"];
+idle_time(Config) ->
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ConnectionRef =
+ ssh:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user_interaction, false},
+ {idle_time, 3000}]),
+ {ok, Id} = ssh_connection:session_channel(ConnectionRef, 1000),
+ ssh_connection:close(ConnectionRef, Id),
+ receive
+ after 10000 ->
+ {error,channel_closed} = ssh_connection:session_channel(ConnectionRef, 1000)
+ end,
+ ssh:stop_daemon(Pid).
+%%--------------------------------------------------------------------
shell(doc) ->
["Test that ssh:shell/2 works"];
shell(Config) when is_list(Config) ->
--
cgit v1.2.3
From f83a7daeb2b7c913688f62dfd78d7f68bcdb542b Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Mon, 5 Nov 2012 13:04:49 +0100
Subject: Fixed doc
---
lib/ssh/doc/src/ssh.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 07f657da70..30d4f45a32 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -187,7 +187,7 @@
Determines if SSH shall use IPv6 or not.
-
-
Sets a timeout on connection when not used and no channels are active, default is infinity
+ Sets a timeout on connection when no channels are active, default is infinity
--
cgit v1.2.3
From 7e1454df69201236ccf2f0955ca1ddce727f07c3 Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Tue, 6 Nov 2012 15:10:22 +0100
Subject: Use same connect as the rest of testcases
---
lib/ssh/test/ssh_basic_SUITE.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 61b91e3a25..0ae7874c4b 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -245,7 +245,7 @@ idle_time(Config) ->
{user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
ConnectionRef =
- ssh:connect(Host, Port, [{silently_accept_hosts, true},
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user_dir, UserDir},
{user_interaction, false},
{idle_time, 3000}]),
--
cgit v1.2.3
From 49fef147845655e44f91cd4fdf4be92162e65710 Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson
Date: Wed, 7 Nov 2012 13:41:26 +0100
Subject: New setup in testing idle_time
---
lib/ssh/test/ssh_basic_SUITE.erl | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
(limited to 'lib')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 0ae7874c4b..5fec7f0cd7 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -42,15 +42,15 @@ all() ->
{group, dsa_pass_key},
{group, rsa_pass_key},
{group, internal_error},
- idle_time,
+ {group, idle_time},
daemon_already_started,
server_password_option,
server_userpassword_option,
close].
groups() ->
- [{dsa_key, [], [send, exec, exec_compressed, shell, known_hosts]},
- {rsa_key, [], [send, exec, exec_compressed, shell, known_hosts]},
+ [{dsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time]},
+ {rsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time]},
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
{internal_error, [], [internal_error]}
@@ -240,15 +240,14 @@ idle_time(doc) ->
idle_time(Config) ->
SystemDir = filename:join(?config(priv_dir, Config), system),
UserDir = ?config(priv_dir, Config),
-
+
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
ConnectionRef =
ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user_dir, UserDir},
- {user_interaction, false},
- {idle_time, 3000}]),
+ {user_interaction, false}]),
{ok, Id} = ssh_connection:session_channel(ConnectionRef, 1000),
ssh_connection:close(ConnectionRef, Id),
receive
--
cgit v1.2.3