Permalink
Browse files

New timing infrastructure. There's a new function schedule_timer()

which pretty much any module can call to request a call-back in the
future. So terminal.c can do its own handling of blinking, visual
bells and deferred screen updates, without having to rely on
term_update() being called 50 times a second (fixes: pterm-timer);
and ssh.c and telnet.c both invoke a new module pinger.c which takes
care of sending keepalives, so they get sent uniformly in all front
ends (fixes: plink-keepalives, unix-keepalives).


git-svn-id: svn://svn.tartarus.org/sgt/putty@4906 cda61777-01e9-0310-a592-d414129be87e
  • Loading branch information...
simon
simon committed Nov 27, 2004
1 parent 7063730 commit 39934deb5202149f98198c111a35c21cb4d0d0f8
Showing with 1,106 additions and 366 deletions.
  1. +7 −8 Recipe
  2. +11 −9 doc/udp.but
  3. +1 −2 mac/macterm.c
  4. +23 −0 misc.c
  5. +3 −0 misc.h
  6. +71 −0 pinger.c
  7. +20 −30 psftp.c
  8. +6 −0 psftp.h
  9. +44 −0 putty.h
  10. +1 −0 raw.c
  11. +1 −0 rlogin.c
  12. +13 −0 ssh.c
  13. +9 −0 telnet.c
  14. +202 −119 terminal.c
  15. +15 −5 terminal.h
  16. +173 −0 timing.c
  17. +42 −8 unix/pterm.c
  18. +2 −0 unix/pty.c
  19. +2 −2 unix/unix.h
  20. +8 −0 unix/uxcons.c
  21. +4 −5 unix/uxmisc.c
  22. +19 −1 unix/uxplink.c
  23. +112 −36 unix/uxsftp.c
  24. +0 −23 unix/uxstore.c
  25. +8 −0 windows/wincons.c
  26. +44 −105 windows/window.c
  27. +10 −0 windows/winnet.c
  28. +24 −6 windows/winplink.c
  29. +229 −7 windows/winsftp.c
  30. +2 −0 windows/winstuff.h
View
15 Recipe
@@ -182,14 +182,15 @@ GUITERM = TERMINAL window windlg winctrls sizetip winucs winprint
# Same thing on Unix.
UXTERM = TERMINAL pterm uxcfg gtkdlg gtkcols gtkpanel uxucs uxprint xkeysym
+ + timing
# Non-SSH back ends (putty, puttytel, plink).
-NONSSH = telnet raw rlogin ldisc
+NONSSH = telnet raw rlogin ldisc pinger
# SSH back end (putty, plink, pscp, psftp).
SSH = ssh sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf
+ sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd
- + sshaes sshsh512 sshbn wildcard
+ + sshaes sshsh512 sshbn wildcard pinger
WINSSH = SSH winnoise winpgntc
UXSSH = SSH uxnoise uxagentc
MACSSH = SSH macnoise
@@ -199,12 +200,10 @@ SFTP = sftp int64 logging
# Miscellaneous objects appearing in all the network utilities (not
# Pageant or PuTTYgen).
-WINMISC = misc version winstore settings tree234 winnet proxy cmdline
- + windefs winmisc pproxy
-UXMISC = misc version uxstore settings tree234 uxsel uxnet proxy cmdline
- + uxmisc uxproxy
-MACMISC = misc version macstore settings tree234 macnet mtcpnet otnet proxy
- + macmisc macabout pproxy
+MISC = timing misc version settings tree234 proxy
+WINMISC = MISC winstore winnet cmdline windefs winmisc pproxy
+UXMISC = MISC uxstore uxsel uxnet cmdline uxmisc uxproxy
+MACMISC = MISC macstore macnet mtcpnet otnet macmisc macabout pproxy
# Character set library, for use in pterm.
CHARSET = sbcsdat slookup sbcs utf8 toucs fromucs xenc mimeenc macenc localenc
View
@@ -75,21 +75,23 @@ Some ports of PuTTY - notably the in-progress Mac port - are
constrained by the operating system to run as a single process
potentially managing multiple sessions.
-Therefore, the platform-independent parts of PuTTY use \e{hardly
-any} global variables. The very few that do exist, such as
-\c{flags}, are tolerated because they are not specific to a
-particular login session: instead, they define properties that are
-expected to apply equally to \e{all} the sessions run by a single
-PuTTY process. Any data that is specific to a particular network
-session is stored in dynamically allocated data structures, and
-pointers to these structures are passed around between functions.
+Therefore, the platform-independent parts of PuTTY never use global
+variables to store per-session data. The global variables that do
+exist are tolerated because they are not specific to a particular
+login session: \c{flags} defines properties that are expected to
+apply equally to \e{all} the sessions run by a single PuTTY process,
+the random number state in \cw{sshrand.c} and the timer list in
+\cw{timing.c} serve all sessions equally, and so on. But most data
+is specific to a particular network session, and is therefore stored
+in dynamically allocated data structures, and pointers to these
+structures are passed around between functions.
Platform-specific code can reverse this decision if it likes. The
Windows code, for historical reasons, stores most of its data as
global variables. That's OK, because \e{on Windows} we know there is
only one session per PuTTY process, so it's safe to do that. But
changes to the platform-independent code should avoid introducing
-any more global variables than already exist.
+global variables, unless they are genuinely cross-session.
\H{udp-pure-c} C, not C++
View
@@ -1,4 +1,4 @@
-/* $Id: macterm.c,v 1.78 2004/10/14 16:42:43 simon Exp $ */
+/* $Id$ */
/*
* Copyright (c) 1999 Simon Tatham
* Copyright (c) 1999, 2002 Ben Harris
@@ -314,7 +314,6 @@ void mac_pollterm(void)
Session *s;
for (s = sesslist; s != NULL; s = s->next) {
- term_out(s->term);
term_update(s->term);
}
}
View
23 misc.c
@@ -141,6 +141,29 @@ char *dupvprintf(const char *fmt, va_list ap)
}
}
+/*
+ * Read an entire line of text from a file. Return a buffer
+ * malloced to be as big as necessary (caller must free).
+ */
+char *fgetline(FILE *fp)
+{
+ char *ret = snewn(512, char);
+ int size = 512, len = 0;
+ while (fgets(ret + len, size - len, fp)) {
+ len += strlen(ret + len);
+ if (ret[len-1] == '\n')
+ break; /* got a newline, we're done */
+ size = len + 512;
+ ret = sresize(ret, size, char);
+ }
+ if (len == 0) { /* first fgets returned NULL */
+ sfree(ret);
+ return NULL;
+ }
+ ret[len] = '\0';
+ return ret;
+}
+
/* ----------------------------------------------------------------------
* Base64 encoding routine. This is required in public-key writing
* but also in HTTP proxy handling, so it's centralised here.
View
3 misc.h
@@ -3,6 +3,7 @@
#include "puttymem.h"
+#include <stdio.h> /* for FILE * */
#include <stdarg.h> /* for va_list */
#ifndef FALSE
@@ -20,6 +21,8 @@ char *dupcat(const char *s1, ...);
char *dupprintf(const char *fmt, ...);
char *dupvprintf(const char *fmt, va_list ap);
+char *fgetline(FILE *fp);
+
void base64_encode_atom(unsigned char *data, int n, char *out);
struct bufchain_granule;
View
@@ -0,0 +1,71 @@
+/*
+ * pinger.c: centralised module that deals with sending TS_PING
+ * keepalives, to avoid replicating this code in multiple backends.
+ */
+
+#include "putty.h"
+
+struct pinger_tag {
+ int interval;
+ int pending;
+ long next;
+ Backend *back;
+ void *backhandle;
+};
+
+static void pinger_schedule(Pinger pinger);
+
+static void pinger_timer(void *ctx, long now)
+{
+ Pinger pinger = (Pinger)ctx;
+
+ if (pinger->pending && now - pinger->next >= 0) {
+ pinger->back->special(pinger->backhandle, TS_PING);
+ pinger->pending = FALSE;
+ pinger_schedule(pinger);
+ }
+}
+
+static void pinger_schedule(Pinger pinger)
+{
+ int next;
+
+ if (!pinger->interval) {
+ pinger->pending = FALSE; /* cancel any pending ping */
+ return;
+ }
+
+ next = schedule_timer(pinger->interval * TICKSPERSEC,
+ pinger_timer, pinger);
+ if (!pinger->pending || next < pinger->next) {
+ pinger->next = next;
+ pinger->pending = TRUE;
+ }
+}
+
+Pinger pinger_new(Config *cfg, Backend *back, void *backhandle)
+{
+ Pinger pinger = snew(struct pinger_tag);
+
+ pinger->interval = cfg->ping_interval;
+ pinger->pending = FALSE;
+ pinger->back = back;
+ pinger->backhandle = backhandle;
+ pinger_schedule(pinger);
+
+ return pinger;
+}
+
+void pinger_reconfig(Pinger pinger, Config *oldcfg, Config *newcfg)
+{
+ if (oldcfg->ping_interval != newcfg->ping_interval) {
+ pinger->interval = newcfg->ping_interval;
+ pinger_schedule(pinger);
+ }
+}
+
+void pinger_free(Pinger pinger)
+{
+ expire_timer_context(pinger);
+ sfree(pinger);
+}
View
50 psftp.c
@@ -1361,45 +1361,34 @@ static int sftp_cmd_help(struct sftp_command *cmd)
struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags)
{
char *line;
- int linelen, linesize;
struct sftp_command *cmd;
char *p, *q, *r;
int quoting;
- if ((mode == 0) || (modeflags & 1)) {
- printf("psftp> ");
- }
- fflush(stdout);
-
cmd = snew(struct sftp_command);
cmd->words = NULL;
cmd->nwords = 0;
cmd->wordssize = 0;
line = NULL;
- linesize = linelen = 0;
- while (1) {
- int len;
- char *ret;
-
- linesize += 512;
- line = sresize(line, linesize, char);
- ret = fgets(line + linelen, linesize - linelen, fp);
-
- if (!ret || (linelen == 0 && line[0] == '\0')) {
- cmd->obey = sftp_cmd_quit;
- if ((mode == 0) || (modeflags & 1))
- printf("quit\n");
- return cmd; /* eof */
- }
- len = linelen + strlen(line + linelen);
- linelen += len;
- if (line[linelen - 1] == '\n') {
- linelen--;
- line[linelen] = '\0';
- break;
- }
+
+ if (fp) {
+ if (modeflags & 1)
+ printf("psftp> ");
+ line = fgetline(fp);
+ } else {
+ line = ssh_sftp_get_cmdline("psftp> ");
+ }
+
+ if (!line || !*line) {
+ cmd->obey = sftp_cmd_quit;
+ if ((mode == 0) || (modeflags & 1))
+ printf("quit\n");
+ return cmd; /* eof */
}
+
+ line[strcspn(line, "\r\n")] = '\0';
+
if (modeflags & 1) {
printf("%s\n", line);
}
@@ -1464,7 +1453,8 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags)
}
}
- sfree(line);
+ sfree(line);
+
/*
* Now parse the first word and assign a function.
*/
@@ -1551,7 +1541,7 @@ void do_sftp(int mode, int modeflags, char *batchfile)
*/
while (1) {
struct sftp_command *cmd;
- cmd = sftp_getcmd(stdin, 0, 0);
+ cmd = sftp_getcmd(NULL, 0, 0);
if (!cmd)
break;
ret = cmd->obey(cmd);
View
@@ -32,6 +32,12 @@ void get_file_times(char *filename, unsigned long *mtime,
*/
int ssh_sftp_loop_iteration(void);
+/*
+ * Read a command line for PSFTP from standard input. Caller must
+ * free.
+ */
+char *ssh_sftp_get_cmdline(char *prompt);
+
/*
* The main program in psftp.c. Called from main() in the platform-
* specific code, after doing any platform-specific initialisation.
View
44 putty.h
@@ -578,6 +578,7 @@ void ldisc_update(void *frontend, int echo, int edit);
* shutdown. */
void update_specials_menu(void *frontend);
int from_backend(void *frontend, int is_stderr, const char *data, int len);
+void notify_remote_exit(void *frontend);
#define OPTIMISE_IS_SCROLL 1
void set_iconic(void *frontend, int iconic);
@@ -744,6 +745,14 @@ int random_byte(void);
void random_get_savedata(void **data, int *len);
extern int random_active;
+/*
+ * Exports from pinger.c.
+ */
+typedef struct pinger_tag *Pinger;
+Pinger pinger_new(Config *cfg, Backend *back, void *backhandle);
+void pinger_reconfig(Pinger, Config *oldcfg, Config *newcfg);
+void pinger_free(Pinger);
+
/*
* Exports from misc.c.
*/
@@ -895,4 +904,39 @@ int filename_is_null(Filename fn);
char *get_username(void); /* return value needs freeing */
char *get_random_data(int bytes); /* used in cmdgen.c */
+/*
+ * Exports and imports from timing.c.
+ *
+ * schedule_timer() asks the front end to schedule a callback to a
+ * timer function in a given number of ticks. The returned value is
+ * the time (in ticks since an arbitrary offset) at which the
+ * callback can be expected. This value will also be passed as the
+ * `now' parameter to the callback function. Hence, you can (for
+ * example) schedule an event at a particular time by calling
+ * schedule_timer() and storing the return value in your context
+ * structure as the time when that event is due. The first time a
+ * callback function gives you that value or more as `now', you do
+ * the thing.
+ *
+ * expire_timer_context() drops all current timers associated with
+ * a given value of ctx (for when you're about to free ctx).
+ *
+ * run_timers() is called from the front end when it has reason to
+ * think some timers have reached their moment, or when it simply
+ * needs to know how long to wait next. We pass it the time we
+ * think it is. It returns TRUE and places the time when the next
+ * timer needs to go off in `next', or alternatively it returns
+ * FALSE if there are no timers at all pending.
+ *
+ * timer_change_notify() must be supplied by the front end; it
+ * notifies the front end that a new timer has been added to the
+ * list which is sooner than any existing ones. It provides the
+ * time when that timer needs to go off.
+ */
+typedef void (*timer_fn_t)(void *ctx, long now);
+long schedule_timer(int ticks, timer_fn_t fn, void *ctx);
+void expire_timer_context(void *ctx);
+int run_timers(long now, long *next);
+void timer_change_notify(long next);
+
#endif
View
1 raw.c
@@ -37,6 +37,7 @@ static int raw_closing(Plug plug, const char *error_msg, int error_code,
if (raw->s) {
sk_close(raw->s);
raw->s = NULL;
+ notify_remote_exit(raw->frontend);
}
if (error_msg) {
/* A socket error has occurred. */
View
@@ -39,6 +39,7 @@ static int rlogin_closing(Plug plug, const char *error_msg, int error_code,
if (rlogin->s) {
sk_close(rlogin->s);
rlogin->s = NULL;
+ notify_remote_exit(rlogin->frontend);
}
if (error_msg) {
/* A socket error has occurred. */
Oops, something went wrong.

0 comments on commit 39934de

Please sign in to comment.