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/ssh/src') 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/ssh/src') 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/ssh/src') 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/ssh/src') 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 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/ssh/src') 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