Category: |
Win32 Stuff |
Author/Contact Info |
|
Description: |
When I leave my Putty sessions open overnight or even over lunch, they die from lack of activity. For whatever reason, putty's built in keep-alive isn't good enough. This program hangs around until you've been inactive for awhile and every minute frobs any open putty windows with control-g.
That's just the key I liked, use your own if you like. |
#!perl
use strict;
use warnings;
use Carp 'croak';
# Win32::Process::Info and Win32::GuiTest can be installed from ppm.
use Win32::Process::Info;
use Win32::GuiTest qw( GetForegroundWindow SetForegroundWindow
FindWindowLike SendKeys GetCursorPos GetWindowText );
# Enables debugging output whenever the program is run from a terminal
+.
# For normal use, run this with wperl.exe
use constant DEBUG => -t STDOUT;
# I like emacs, yes I do! I like emacs, how about you?
use constant KEY_SEQUENCE => "^g";
use constant PUTTY => qr/ - PuTTY$/;
use constant REPEATING_SIGNATURE => qr/^((?>\d+)(?>(?:,(?>\d+))+))(?>(
+?: \1){59,59})$/;
# Generated from YAPE::Regex::Explain:
# The regular expression:
#
# ^((?>\d+)(?>(?:,(?>\d+))+))(?>(?: \1){59,59})$
#
# matches as follows:
#
# NODE EXPLANATION
# --------------------------------------------------------------------
# ^ the beginning of the string
# --------------------------------------------------------------------
# ( group and capture to \1:
# --------------------------------------------------------------------
# (?> match (and do not backtrack afterwards):
# --------------------------------------------------------------------
# \d+ digits (0-9) (1 or more times
# (matching the most amount possible))
# --------------------------------------------------------------------
# ) end of look-ahead
# --------------------------------------------------------------------
# (?> match (and do not backtrack afterwards):
# --------------------------------------------------------------------
# (?: group, but do not capture (1 or more
# times (matching the most amount
# possible)):
# --------------------------------------------------------------------
# , ','
# --------------------------------------------------------------------
# (?> match (and do not backtrack
# afterwards):
# --------------------------------------------------------------------
# \d+ digits (0-9) (1 or more times
# (matching the most amount
# possible))
# --------------------------------------------------------------------
# ) end of look-ahead
# --------------------------------------------------------------------
# )+ end of grouping
# --------------------------------------------------------------------
# ) end of look-ahead
# --------------------------------------------------------------------
# ) end of \1
# --------------------------------------------------------------------
# (?> match (and do not backtrack afterwards):
# --------------------------------------------------------------------
# (?: group, but do not capture (between 59
# and 59 times (matching the most amount
# possible)):
# --------------------------------------------------------------------
# ' '
# --------------------------------------------------------------------
# \1 what was matched by capture \1
# --------------------------------------------------------------------
# ){59,59} end of grouping
# --------------------------------------------------------------------
# ) end of look-ahead
# --------------------------------------------------------------------
# $ before an optional \n, and the end of the
# string
# --------------------------------------------------------------------
# If we are started and this program is already running, die.
LockOrDie();
my $lastfrob = time;
my @snapshots;
while ( 1 ) {
# Don't even bother watching for inactivity if there is no PuTTY a
+round to frongle.
WaitWindowLike( undef, PUTTY );
# A queue, one minute long, of snapshots of system state.
push @snapshots, join( ",",
# Something non-numeric snuck in, I think.
grep /^\d+$/,
GetForegroundWindow(), GetCursorPos(), Find
+WindowLike() );
shift @snapshots if @snapshots > 60;
my $elapsed = time - $lastfrob;
my $frotz = "@snapshots" =~ REPEATING_SIGNATURE;
print "$elapsed $frotz\n"
if DEBUG;
if ( $elapsed >= 30 and $frotz ) {
frobnicate_putty();
$lastfrob = time;
}
sleep 1;
}
sub WaitWindowLike {
while ( 1 ) {
return if FindWindowLike( @_ );
sleep 60;
}
}
sub frobnicate_putty {
my $active = GetForegroundWindow();
my @windows = FindWindowLike( undef, PUTTY );
print "Frobbing \@ @{[scalar time]}\n" if DEBUG and @windows;
for my $window ( @windows ) {
print " $window: " . GetWindowText( $window ) . "\n"
if DEBUG;
# This is utterly obnoxious. Yuck.
SetForegroundWindow( $window );
SendKeys( KEY_SEQUENCE );
}
SetForegroundWindow( $active );
}
sub LockOrDie {
my $lock_file = File::Spec->tmpdir() . "/$0.lck";
my ( $lock_pid )
= grep /^\d+$/,
eval { do { local @ARGV = $lock_file;
<> } };
my ( $proc )
= grep { $_->{ProcessId} == $lock_pid
and $_->{Name} =~ /perl/i }
Win32::Process::Info->new->GetProcInfo;
croak "$0 appears to be already running as $proc->{ProcessId}."
if $proc;
open my $fh, ">", $lock_file
or croak "Can't open $lock_file for writing: $^E";
print $fh "$$\n"
or croak "Can't write to $lock_file for writing: $^E";
close $fh
or croak "Can't close and flush $lock_file after writing: $^E";
return 1;
}
|
Re: A "better" Putty keep-alive
by merlyn (Sage) on Aug 11, 2005 at 15:33 UTC
|
I just leave emacs running in the Putty window, and have the time of day in the mode-line. The once-a-minute update is enough to keep Putty happy.
| [reply] |
|
I do the same thing with screen, with this .screenrc:
caption always "%{G}%3n %t%? @%u%?%? %H [%h]%?%=%c"
hardstatus string "[screen %n%?: %t%?] %h"
startup_message off
| [reply] [d/l] |
|
(Someone has to say it...)
Well, yes, but then you're stuck with emacs on your screen. Much worse than having to log back in :)
(Just kidding, folks! As long as emacs works for him, that's as good a solution as any...)
| [reply] |
Re: A "better" Putty keep-alive
by davidrw (Prior) on Aug 11, 2005 at 16:16 UTC
|
server-side method instead of your client-side (so a tradeoff there), but this is what i usually use:
i put this in my .bashrc (if statement is so that it won't run during batch ssh or scp logins):
if test "xterm" = "$TERM" ; then
/home/myname/bin/keepalive &
fi
and /home/myname/bin/keepalive is just (periodically print a space and a backspace):
#!/bin/bash
while test 1 ; do sleep 600; echo -ne " \b"; done
Only side effect is that if a vi is left open, it appears to make the character under the cursor disappear (but really doesn't) .. ctrl-L to refresh the screen "fixes" it if i even notice it.
| [reply] [d/l] [select] |
Re: A "better" Putty keep-alive
by tinita (Parson) on Aug 12, 2005 at 09:54 UTC
|
i like to use screen on the serverside, whenever possible.
log in the next day and type screen -r, and everything is back (unless some sysadmin decided to empty the /tmp or to reboot...)
screen++ | [reply] [d/l] [select] |
Re: A "better" Putty keep-alive
by shiza (Hermit) on Aug 11, 2005 at 17:55 UTC
|
I haven't had to think about that problem since I switched to a Linux OS on my workstation :^P | [reply] |
Re: A "better" Putty keep-alive
by converter (Priest) on Aug 12, 2005 at 02:55 UTC
|
Try setting putty's "Seconds between keepalives" option to something greater than zero, 300 is probably a good number. Since I set this option I've had no problem keeping my connections alive for long periods of time. I've never had any luck with TCP keepalives, so I don't bother with them.
| [reply] |
|
This is exactly the setting that isn't doing me any good. I need something more substantial than the plain keep-alive. I need something the server thinks is a real key press.
| [reply] |
|
| [reply] |
|
On some *nix OS I have found security policies that forcibly disconnect terminal sessions believed to be idle. In which case keep-alives don't offer any help. One way to fool the policy is to leave the terminal with a blank "read" request.
prompt$ jobs
<stuff running in background (or not, just camping)>
prompt$ read
<terminal (and policy) thinks we are waiting for user input and dare not end our session>
When you return just hit enter, and you get your prompt back.
This is also a great way to keep "screen" sessions from being killed based on policy idle timeouts.
Of course your situation may be very different. Hope this helps, If not don't blame a guy for trying to help.
| [reply] |
|
|