From: simon Date: Tue, 18 Sep 2001 19:41:07 +0000 (+0000) Subject: terminal.c's from_backend() no longer calls term_out(), because X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/commitdiff_plain/a748a096fb9654d8704ceacdb339507722320f6a?hp=4f892125d8842ae40448e7ecdd994fb6d26313a7 terminal.c's from_backend() no longer calls term_out(), because term_out() can in turn call ldisc_send() which calls back to from_backend() when local echo is enabled. This was giving rise to crazy re-entrancy stuff and stack overflows. Instead from_backend() deposits its data in a bufchain which term_out() empties the next time it's called. git-svn-id: svn://svn.tartarus.org/sgt/putty@1276 cda61777-01e9-0310-a592-d414129be87e --- diff --git a/putty.h b/putty.h index 90e10ffc..7a70e371 100644 --- a/putty.h +++ b/putty.h @@ -93,15 +93,6 @@ typedef HDC Context; GLOBAL int rows, cols, savelines; -#define INBUF_SIZE 2048 -GLOBAL unsigned char inbuf[INBUF_SIZE]; -GLOBAL int inbuf_head; - -#define OUTBUF_SIZE 2048 -#define OUTBUF_MASK (OUTBUF_SIZE-1) -GLOBAL unsigned char outbuf[OUTBUF_SIZE]; -GLOBAL int outbuf_head, outbuf_reap; - GLOBAL int has_focus; GLOBAL int in_vbell; diff --git a/scp.c b/scp.c index f4c8d794..2361d803 100644 --- a/scp.c +++ b/scp.c @@ -375,8 +375,6 @@ int from_backend(int is_stderr, char *data, int datalen) return 0; } - inbuf_head = 0; - /* * If this is before the real session begins, just return. */ diff --git a/terminal.c b/terminal.c index 5245cdb7..3b9d4e81 100644 --- a/terminal.c +++ b/terminal.c @@ -86,6 +86,7 @@ typedef struct { #define incpos(p) ( (p).x == cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) ) #define decpos(p) ( (p).x == 0 ? ((p).x = cols, (p).y--, 1) : ((p).x--, 0) ) +static bufchain inbuf; /* terminal input buffer */ static pos curs; /* cursor */ static pos savecurs; /* saved cursor position */ static int marg_t, marg_b; /* scroll margins */ @@ -973,20 +974,38 @@ static void do_osc(void) */ void term_out(void) { - int c, inbuf_reap; + int c, unget; + unsigned char localbuf[256], *chars; + int nchars = 0; + + unget = -1; + + while (nchars > 0 || bufchain_size(&inbuf) > 0) { + if (unget == -1) { + if (nchars == 0) { + void *ret; + bufchain_prefix(&inbuf, &ret, &nchars); + if (nchars > sizeof(localbuf)) + nchars = sizeof(localbuf); + memcpy(localbuf, ret, nchars); + bufchain_consume(&inbuf, nchars); + chars = localbuf; + assert(chars != NULL); + } + c = *chars++; + nchars--; - /* - * Optionally log the session traffic to a file. Useful for - * debugging and possibly also useful for actual logging. - */ - if (cfg.logtype == LGTYP_DEBUG) - for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) { - logtraffic((unsigned char) inbuf[inbuf_reap], LGTYP_DEBUG); + /* + * Optionally log the session traffic to a file. Useful for + * debugging and possibly also useful for actual logging. + */ + if (cfg.logtype == LGTYP_DEBUG) + logtraffic((unsigned char) &c, LGTYP_DEBUG); + } else { + c = unget; + unget = -1; } - for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) { - c = inbuf[inbuf_reap]; - /* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even * be able to display 8-bit characters, but I'll let that go 'cause * of i18n. @@ -1029,7 +1048,7 @@ void term_out(void) case 4: case 5: if ((c & 0xC0) != 0x80) { - inbuf_reap--; + unget = c; c = UCSERR; utf_state = 0; break; @@ -2480,7 +2499,6 @@ void term_out(void) check_selection(curs, cursplus); } } - inbuf_head = 0; } #if 0 @@ -3358,18 +3376,15 @@ int term_ldisc(int option) */ int from_backend(int is_stderr, char *data, int len) { - while (len--) { - if (inbuf_head >= INBUF_SIZE) - term_out(); - inbuf[inbuf_head++] = *data++; - } + bufchain_add(&inbuf, data, len); /* - * We process all stdout/stderr data immediately we receive it, - * and don't return until it's all gone. Therefore, there's no - * reason at all to return anything other than zero from this - * function. - * + * term_out() always completely empties inbuf. Therefore, + * there's no reason at all to return anything other than zero + * from this function, because there _can't_ be a question of + * the remote side needing to wait until term_out() has cleared + * a backlog. + * * This is a slightly suboptimal way to deal with SSH2 - in * principle, the window mechanism would allow us to continue * to accept data on forwarded ports and X connections even @@ -3379,7 +3394,7 @@ int from_backend(int is_stderr, char *data, int len) * portability. So we manage stdout buffering the old SSH1 way: * if the terminal processing goes slowly, the whole SSH * connection stops accepting data until it's ready. - * + * * In practice, I can't imagine this causing serious trouble. */ return 0; diff --git a/window.c b/window.c index cd5f703c..3347260d 100644 --- a/window.c +++ b/window.c @@ -526,12 +526,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) session_closed = FALSE; /* - * Set up the input and output buffers. - */ - inbuf_head = 0; - outbuf_reap = outbuf_head = 0; - - /* * Prepare the mouse handler. */ lastact = MA_NOTHING; @@ -660,8 +654,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) timer_id = 0; } HideCaret(hwnd); - if (inbuf_head) - term_out(); + term_out(); term_update(); ShowCaret(hwnd); @@ -1392,8 +1385,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_TIMER: if (pending_netevent) enact_pending_netevent(); - if (inbuf_head) - term_out(); + term_out(); noise_regular(); HideCaret(hwnd); term_update();