Commit b942296b authored by Russ Fish's avatar Russ Fish
Browse files

Move the GetLastInputInfo() that detects RDP keyboard and mouse events to a...

Move the GetLastInputInfo() that detects RDP keyboard and mouse events to a sub-daemon named idlemon, which is started as part of the user login.  A VBS script wraps the C program and is started by a Registry entry, hiding its window after startup and getting cleaned up at logout.
parent 42871b0d
......@@ -32,6 +32,13 @@ CP= cp -pf
ifeq ($(SYSTEM),CYGWIN_NT-5.1)
# Cygwin on Windows XP (a.k.a. NT 5.1).
MLIBS += -liphlpapi
WINCLIENT = idlemon
WINCLIENTSRC = idlemon.c
CVR = /HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Run
IDLEKEY = $(CVR)/EmulabIdle
IDLEMONEXE = $(DESTDIR)$(CLIENT_BINDIR)/idlemon$(EXE)
endif
all: $(SDPROGS) client
......@@ -41,16 +48,20 @@ include ${TESTBED_SRCDIR}/GNUmakerules
slothd-debug: slothd.o slothd.h version.o
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ slothd.o version.o $(LIBS)
# This is started up at user login on Windows to monitor desktop events for slothd.
idlemon-debug: idlemon.o version.o
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ idlemon.o version.o $(LIBS)
sdcollectd: sdcollectd.o sdcollectd.h version.o $(TBLIB)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ sdcollectd.o version.o $(SDLIBS)
$(TBLIB):
gmake -C $(OBJDIR)/lib
version.c: slothd.c slothd.h sdcollectd.c sdcollectd.h
version.c: slothd.c slothd.h sdcollectd.c sdcollectd.h $(WINCLIENTSRC)
echo >$@ "char build_info[] = \"Built `date +%d-%b-%Y` by `id -nu`@`hostname | sed 's/\..*//'`:`pwd`\";"
client: slothd
client: slothd $(WINCLIENT)
install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS) sdcollectd) webfeedback
$(INSTALL_PROGRAM) $(SRCDIR)/digest-slothd $(INSTALL_LIBEXECDIR)
......@@ -60,6 +71,18 @@ install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS) sdcollectd) webfeedbac
client-install: client
$(INSTALL_PROGRAM) slothd$(EXE) $(DESTDIR)$(CLIENT_BINDIR)/slothd$(EXE)
ifeq ($(SYSTEM),CYGWIN_NT-5.1)
# If there are any RDP logins active, idlemon will be busy. Try moving it.
-mv $(IDLEMONEXE) $(IDLEMONEXE).prev
$(INSTALL_PROGRAM) idlemon$(EXE) $(IDLEMONEXE)
# Wrap the idlemon program in a VBS script to hide its window away.
$(INSTALL_PROGRAM) $(SRCDIR)/idlemon.vbs $(DESTDIR)$(CLIENT_BINDIR)/idlemon.vbs
# Run the wrapped idlemon as part of any Windows desktop login.
regtool -s set $(IDLEKEY) 'C:\cygwin\usr\local\etc\emulab\idlemon.vbs'
endif
control-install:
clean:
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2005 University of Utah and the Flux Group.
* All rights reserved.
*/
/* idlemon is started up at user login on Windows to monitor desktop events
* for slothd under RDP logins. It has to be in the user session context for
* GetLastInputInfo() to work. Output is just touching a time tag file.
*/
char *rdp_time_file = "/var/run/rdp_input";
#include "slothd.h"
#include "config.h"
void lerror(const char* msgstr) {
if (msgstr) {
syslog(LOG_ERR, "%s: %m", msgstr);
fprintf(stderr, "idlemon: %s: %s\n", msgstr, strerror(errno));
}
}
char err_buff[BUFSIZ];
int main(int argc, char **argv) {
int ch;
int debug = 0;
int input_occurred_fd;
time_t last_time = 0;
while ((ch = getopt(argc, argv, "d")) != -1) {
switch (ch) {
case 'd':
debug = 1;
break;
}
}
input_occurred_fd = open(
rdp_time_file, O_CREAT | O_TRUNC | O_WRONLY, 0666);
if (input_occurred_fd == -1) {
sprintf(err_buff, "Failed to open rdp_time_file %s.", rdp_time_file);
lerror(err_buff);
exit(1);
}
fchmod(input_occurred_fd, 0666); /* Everyone can write, if umask blocked it. */
/* Poll the time of last keyboard or mouse event, once every few seconds. */
for (; 1; sleep(5)) {
LASTINPUTINFO windows_input;
windows_input.cbSize = sizeof(LASTINPUTINFO);
if (GetLastInputInfo(&windows_input) == 0) {
lerror("Failed GetLastInputInfo().");
exit(2);
}
else {
/* Windows keeps time in millisecond ticks since boot time. */
DWORD windows_ticks = GetTickCount() - windows_input.dwTime;
time_t windows_time = time(0) - windows_ticks/1000;
if (debug)
printf("Windows input event time: %s", ctime(&windows_time));
if (windows_time > last_time) {
last_time = windows_time;
/* It would be nice to use futimes(), but there's not one
* on Cygwin. Instead, use ftruncate() to set the modtime.
*/
if (ftruncate(input_occurred_fd, 0)) {
sprintf(err_buff, "Error touching rdp input time file, %s.",
strerror(errno));
lerror(err_buff);
exit(3);
}
}
}
}
}
Const HIDDEN_WINDOW = 12
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = HIDDEN_WINDOW
Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")
pgm = "C:\cygwin\usr\local\etc\emulab\idlemon.exe"
errReturn = objProcess.Create(pgm, null, objConfig, intProcessID)
......@@ -335,7 +335,23 @@ int init_slothd(void) {
}
}
closedir(devs);
#endif /* not __CYGWIN__ */
#else /* __CYGWIN__ */
/* On Cygwin, `tty` returns /dev/console under RDP, and /dev/tty$n under SSH.
* However, stat on anything under /dev always returns the current time, so
* it's no help detecting user input. Instead, we patch sshd to change the
* modtime on a file when input is received and stat that.
*/
parms->ttys[0] = strdup("/var/run/ssh_input");
/* Likewise, idlemon is started up at user login on Windows to monitor
* desktop events for slothd under RDP logins and touches a time tag file.
*/
parms->ttys[1] = strdup("/var/run/rdp_input");
parms->numttys = 2;
#endif /* __CYGWIN__ */
/* prepare UDP connection to server */
if ((parms->sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
......@@ -467,67 +483,30 @@ int send_pkt(SLOTHD_PACKET *pkt) {
void get_min_tty_idle(SLOTHD_PACKET *pkt) {
int i;
time_t mintime = 0;
struct stat sb;
#ifndef __CYGWIN__
int i;
for (i = 0; i < parms->numttys; ++i) {
if (stat(parms->ttys[i], &sb) < 0) {
fprintf(stderr, "Can't stat %s: %s\n",
parms->ttys[i], strerror(errno)); /* XXX change. */
}
else {
/* The time of last reading keyboard input. */
time_t tty_time = sb.st_atime;
if (tty_time > mintime)
mintime = tty_time;
#ifndef __CYGWIN__
/* The time of last reading keyboard input. */
time_t tty_time = sb.st_atime;
#else
/* We're modding time tag files Cygwin, not reading them. */
time_t tty_time = sb.st_mtime;
#endif
if (tty_time > mintime) {
mintime = tty_time;
if (opts->debug)
printf("Input on %s: %s", parms->ttys[i], ctime(&mintime));
}
}
}
#else /* __CYGWIN__ */
LASTINPUTINFO windows_input;
/* On Cygwin, `tty` returns /dev/console under RDP, and /dev/tty$n under SSH.
* However, stat on anything under /dev always returns the current time, so
* it's no help detecting user input. Instead, we patch sshd to change the
* modtime on a file when input is received and stat that.
*/
char *ssh_input = "/var/run/ssh_input";
if (stat(ssh_input, &sb) < 0) {
fprintf(stderr, "Can't stat %s: %s\n",
ssh_input, strerror(errno)); /* XXX change. */
}
else {
/* We're modding a time tag file from sshd on Cygwin, not reading it. */
time_t tty_time = sb.st_mtime;
if (opts->debug)
printf("sshd time: %s", ctime(&tty_time));
if (tty_time > mintime)
mintime = tty_time;
}
/* In a Remote Desktop Protocol login, look at keyboard and mouse input. */
windows_input.cbSize = sizeof(LASTINPUTINFO);
if (GetLastInputInfo(&windows_input) == 0) {
fprintf(stderr, "Failed GetLastInputInfo().\n");
}
else {
/* Windows keeps time in millisecond ticks since boot time. */
DWORD windows_ticks = GetTickCount() - windows_input.dwTime;
time_t windows_time = time(0) - windows_ticks/1000;
/* For debugging, run this under RDP. It doesn't get anything useful
* under ssh. It's normally started by rc.slothd under the EmulabStartup
* service, and that works too.
*/
if (opts->debug)
printf("Windows input event time: %s", ctime(&windows_time));
if (windows_time > mintime)
mintime = windows_time;
}
#endif /* __CYGWIN__ */
/* Assign TTY activity, ensuring we don't go older than initial startup. */
pkt->minidle = (mintime > parms->startup) ? mintime : parms->startup;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment