From 2e0525035c4b06660d6f3ad0b886c4e9380da868 Mon Sep 17 00:00:00 2001 From: rootTHC Date: Mon, 22 Feb 2021 12:43:26 +0000 Subject: [PATCH 1/4] small fixes --- configure.ac | 2 +- include/gsocket/gsocket.h | 2 ++ tools/common.h | 42 +++++++++++++++++------ tools/console_display.c | 2 +- tools/filetransfer.c | 71 +++++++++++++++++++++++++++++++++------ tools/filetransfer.h | 5 ++- tools/filetransfer_mgr.c | 10 ++++++ tools/utils.c | 7 +++- 8 files changed, 113 insertions(+), 28 deletions(-) diff --git a/configure.ac b/configure.ac index b6740213..def81024 100755 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this File with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([gsocket], 1.4.24) +AC_INIT([gsocket], 1.4.25) dnl AC_CONFIG_AUX_DIR(config-x86_64-apple-darwin19.6.0) AC_CONFIG_AUX_DIR(config) AC_CANONICAL_SYSTEM diff --git a/include/gsocket/gsocket.h b/include/gsocket/gsocket.h index 80b2833c..ee73d179 100644 --- a/include/gsocket/gsocket.h +++ b/include/gsocket/gsocket.h @@ -41,10 +41,12 @@ #define GS_TOKEN_SIZE (16) /* 128 bit */ #define GS_TV_TO_USEC(tv) ((uint64_t)(tv)->tv_sec * 1000000 + (tv)->tv_usec) +#define GS_TV_TO_MSEC(tv) ((uint64_t)(tv)->tv_sec * 1000 + (tv)->tv_usec/1000) #define GS_TV_DIFF(tv_a, tv_b) (GS_TV_TO_USEC(tv_b) - GS_TV_TO_USEC(tv_a)) #define GS_SEC_TO_USEC(sec) ((uint64_t)sec * 1000000) #define GS_MSEC_TO_USEC(ms) ((uint64_t)ms * 1000) #define GS_USEC_TO_SEC(usec) (usec / 1000000) +#define GS_USEC_TO_MSEC(usec) (usec / 1000) #define GS_USEC_TO_TV(tv, usec) do { (tv)->tv_sec = (usec) / 1000000; (tv)->tv_usec = (usec) % 1000000; } while(0) #define GS_SECRET_MAX_LEN (256 / 8) /* max length in bytes */ diff --git a/tools/common.h b/tools/common.h index c1dea370..7219eda0 100755 --- a/tools/common.h +++ b/tools/common.h @@ -210,7 +210,8 @@ struct _peer #define GSC_FL_IS_SERVER (0x01) -extern struct _gopt gopt; +extern struct _gopt gopt; // declared in utils.c + #define xfprintf(fp, a...) do {if (fp != NULL) { fprintf(fp, a); fflush(fp); } } while (0) #define int_ntoa(x) inet_ntoa(*((struct in_addr *)&x)) @@ -223,6 +224,25 @@ extern struct _gopt gopt; # define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) #endif +#ifdef DEBUG +struct _g_debug_ctx +{ + struct timeval tv_last; + struct timeval tv_now; +}; + +extern struct _g_debug_ctx g_dbg_ctx; // declared in utils.c + +#define DEBUGF_T(xcolor, a...) do { \ + gettimeofday(&g_dbg_ctx.tv_now, NULL); \ + if (g_dbg_ctx.tv_last.tv_sec == 0) { memcpy(&g_dbg_ctx.tv_last, &g_dbg_ctx.tv_now, sizeof g_dbg_ctx.tv_last); } \ + xfprintf(gopt.err_fp, "DEBUG %4llu %s:%d %s", GS_TV_TO_MSEC(&g_dbg_ctx.tv_now) - GS_TV_TO_MSEC(&g_dbg_ctx.tv_last), __func__, __LINE__, xcolor?xcolor:""); \ + memcpy(&g_dbg_ctx.tv_last, &g_dbg_ctx.tv_now, sizeof g_dbg_ctx.tv_last); \ + xfprintf(gopt.err_fp, a); \ + if (xcolor) { xfprintf(gopt.err_fp, "\033[0m"); } \ +} while (0) + + #define D_RED(a) "\033[0;31m"a"\033[0m" #define D_GRE(a) "\033[0;32m"a"\033[0m" #define D_YEL(a) "\033[0;33m"a"\033[0m" @@ -233,16 +253,15 @@ extern struct _gopt gopt; #define D_BYEL(a) "\033[1;33m"a"\033[0m" #define D_BBLU(a) "\033[1;34m"a"\033[0m" #define D_BMAG(a) "\033[1;35m"a"\033[0m" -#ifdef DEBUG -# define DEBUGF(a...) do{xfprintf(gopt.err_fp, "DEBUG %s:%d: ", __func__, __LINE__); xfprintf(gopt.err_fp, a); }while(0) -# define DEBUGF_R(a...) do{xfprintf(gopt.err_fp, "DEBUG %s:%d: ", __func__, __LINE__); xfprintf(gopt.err_fp, "\033[1;31m"); xfprintf(gopt.err_fp, a); xfprintf(gopt.err_fp, "\033[0m"); }while(0) -# define DEBUGF_G(a...) do{xfprintf(gopt.err_fp, "DEBUG %s:%d: ", __func__, __LINE__); xfprintf(gopt.err_fp, "\033[1;32m"); xfprintf(gopt.err_fp, a); xfprintf(gopt.err_fp, "\033[0m"); }while(0) -# define DEBUGF_B(a...) do{xfprintf(gopt.err_fp, "DEBUG %s:%d: ", __func__, __LINE__); xfprintf(gopt.err_fp, "\033[1;34m"); xfprintf(gopt.err_fp, a); xfprintf(gopt.err_fp, "\033[0m"); }while(0) -# define DEBUGF_Y(a...) do{xfprintf(gopt.err_fp, "DEBUG %s:%d: ", __func__, __LINE__); xfprintf(gopt.err_fp, "\033[1;33m"); xfprintf(gopt.err_fp, a); xfprintf(gopt.err_fp, "\033[0m"); }while(0) -# define DEBUGF_M(a...) do{xfprintf(gopt.err_fp, "DEBUG %s:%d: ", __func__, __LINE__); xfprintf(gopt.err_fp, "\033[1;35m"); xfprintf(gopt.err_fp, a); xfprintf(gopt.err_fp, "\033[0m"); }while(0) -# define DEBUGF_C(a...) do{xfprintf(gopt.err_fp, "DEBUG %s:%d: ", __func__, __LINE__); xfprintf(gopt.err_fp, "\033[1;36m"); xfprintf(gopt.err_fp, a); xfprintf(gopt.err_fp, "\033[0m"); }while(0) -# define DEBUGF_W(a...) do{xfprintf(gopt.err_fp, "DEBUG %s:%d: ", __func__, __LINE__); xfprintf(gopt.err_fp, "\033[1;37m"); xfprintf(gopt.err_fp, a); xfprintf(gopt.err_fp, "\033[0m"); }while(0) -#else +# define DEBUGF(a...) do{DEBUGF_T(NULL, a); } while(0) +# define DEBUGF_R(a...) do{DEBUGF_T("\033[1;31m", a); } while(0) +# define DEBUGF_G(a...) do{DEBUGF_T("\033[1;32m", a); } while(0) +# define DEBUGF_B(a...) do{DEBUGF_T("\033[1;34m", a); } while(0) +# define DEBUGF_Y(a...) do{DEBUGF_T("\033[1;33m", a); } while(0) +# define DEBUGF_M(a...) do{DEBUGF_T("\033[1;35m", a); } while(0) +# define DEBUGF_C(a...) do{DEBUGF_T("\033[1;36m", a); } while(0) +# define DEBUGF_W(a...) do{DEBUGF_T("\033[1;37m", a); } while(0) +#else // DEBUG # define DEBUGF(a...) # define DEBUGF_R(a...) # define DEBUGF_G(a...) @@ -251,6 +270,7 @@ extern struct _gopt gopt; # define DEBUGF_M(a...) # define DEBUGF_C(a...) # define DEBUGF_W(a...) +# define DEBUGF_A(a...) #endif // Increase ptr by number of characters added to ptr. diff --git a/tools/console_display.c b/tools/console_display.c index 73b73f72..72c64db3 100644 --- a/tools/console_display.c +++ b/tools/console_display.c @@ -41,7 +41,7 @@ GS_condis_add(GS_CONDIS *cd, int level, const char *str) size_t len; struct condis_line *cdl = &cd->cdl[cd->pos_add]; - DEBUGF("-> '%s'\n", str); + DEBUGF("%s\n", str); len = MIN(sizeof cdl->line - 1, strlen(str)); memcpy(cdl->line, str, len); cdl->line[len] = 0x00; diff --git a/tools/filetransfer.c b/tools/filetransfer.c index d2406ad5..676b748e 100644 --- a/tools/filetransfer.c +++ b/tools/filetransfer.c @@ -209,7 +209,7 @@ GS_FT_add_file(GS_FT *ft, uint32_t id, const char *fname, size_t len, int64_t fs return -1; // protocol error. Not 0 terminated. // FIXME: sanitize file name - DEBUGF_Y("#%u ADD-FILE - size %"PRIu64", fperm 0%o, '%s' mtime=%d flags=0x%02x\n", id, fsize, fperm, fname, mtime, flags); + DEBUGF_Y("#%u ADD-FILE - size %"PRIu64", fperm 0%o, '%s' mtime=%d flags=0x%02x (n_items=%d)\n", id, fsize, fperm, fname, mtime, flags, ft->fadded.n_items); char fn_local[4096]; char *wdir = GS_getpidwd(ft->pid); @@ -359,6 +359,12 @@ GS_FT_list_add(GS_FT *ft, uint32_t globbing_id, const char *fname, size_t len, i { DEBUGF_G("Last file for this globbing id. Free'ing get-list\n"); free_get_li(li); + + // Scenario: All requested files got skipped (already exist). + // - no get request (for file data) outstanding. + // Trigger that GS_FT_packet() is called to return GS_FT_TYPE_DONE (all files transfered) + if ((ft->n_files_waiting == 0) && (ft->plistreq_waiting.n_items == 0)) + ft->is_want_write = 1; } return 0; } @@ -657,13 +663,18 @@ GS_FT_list_add_files(GS_FT *ft, uint32_t globbing_id, const char *pattern, size_ { int ret; char err[128]; + int cwd_fd; if (pattern[len] != '\0') return -1; // protocol error. Not 0-terminated. DEBUGF_Y("G#%u GET-ADD-FILE: %s\n", globbing_id, pattern); + + cwd_fd = open(".", O_RDONLY); + if (cwd_fd < 0) + DEBUGF_R("open(.): %s\n", strerror(errno)); char *ptr = GS_getpidwd(ft->pid); - ret = chdir(ptr); + ret = chdir(ptr); // Temporarily change CWD for globbing to work. if (ret != 0) { @@ -684,6 +695,12 @@ GS_FT_list_add_files(GS_FT *ft, uint32_t globbing_id, const char *pattern, size_ } done: + if (cwd_fd >= 0) + { + // Change back to original CWD. + fchdir(cwd_fd); + close(cwd_fd); + } XFREE(ptr); ft->is_want_write = 1; return ret; @@ -791,6 +808,10 @@ receiving_complete(GS_FT *ft, struct _gs_ft_file *f) ft_done(ft); ft_del(f->li); + + // Trigger that GS_FT_packet() is called to return GS_FT_TYPE_DONE (all files transfered) + if ((ft->n_files_waiting == 0) && (ft->plistreq_waiting.n_items == 0)) + ft->is_want_write = 1; } else { // SERVER (put, upload: all data received) XFCLOSE(f->fp); @@ -962,7 +983,7 @@ mkdirpm(const char *path, mode_t mode, uint32_t mtime) struct stat res; char *f = NULL; - DEBUGF("mkdirpm(%s)\n", path); + // DEBUGF("mkdirpm(%s)\n", path); // Return 0 if directory already exist if (stat(path, &res) == 0) { @@ -993,7 +1014,7 @@ mkdirpm(const char *path, mode_t mode, uint32_t mtime) if (S_ISDIR(res.st_mode)) { // HERE: Parent directory exists. - DEBUGF_W("1-mkdir(%s)\n", path); + // DEBUGF_W("1-mkdir(%s)\n", path); if (mkdir_agressive(path, mode, mtime) != 0) rv = -1; goto done; @@ -1035,7 +1056,7 @@ mkdirpm(const char *path, mode_t mode, uint32_t mtime) *ptr = '\0'; else new_mode = mode; // last part of directory - DEBUGF_W("2-mkdir(%s, 0%o)\n", f, new_mode); + // DEBUGF_W("2-mkdir(%s, 0%o)\n", f, new_mode); if (mkdir_agressive(f, new_mode, mtime) != 0) { rv = -1; @@ -1168,6 +1189,7 @@ gs_ft_switch(GS_FT *ft, uint32_t id, int64_t fz_remote, struct _gs_ft_file **act if (new->fz_remote == 0) { // Zero File Size + DEBUGF("ZERO sized file received\n"); receiving_complete(ft, new); return; } @@ -1238,13 +1260,20 @@ ft_del(GS_LIST_ITEM *li) // Human readable bps string static void -mk_bps(char *str, size_t sz, uint64_t duration, uint64_t amount, int err) +mk_bps(char *str, size_t sz, uint64_t duration, uint64_t amount, int err, int is_zero) { if (err != 0) { snprintf(str, sz, "ERROR"); return; } + + if (is_zero) + { + snprintf(str, sz, "zero size"); + return; + } + if (duration > 0) GS_format_bps(str, sz, (amount * 1000000 / duration), "/s"); else @@ -1270,7 +1299,12 @@ mk_stats_file(GS_FT *ft, uint32_t id, struct _gs_ft_file *f, const char *name, i if (f != NULL) { + // Check if this file had zero size + if ((f->fz_remote == 0) && (f->fz_local == 0)) + s.is_zero = 1; + s.xfer_amount = f->xfer_amount; + if (f->usec_start > f->usec_end) f->usec_end = GS_usec(); @@ -1283,7 +1317,8 @@ mk_stats_file(GS_FT *ft, uint32_t id, struct _gs_ft_file *f, const char *name, i s.xfer_duration = (f->usec_end - f->usec_start) - f->usec_suspend_duration; } - mk_bps(s.speed_str, sizeof s.speed_str, s.xfer_duration, s.xfer_amount, err); + + mk_bps(s.speed_str, sizeof s.speed_str, s.xfer_duration, s.xfer_amount, err, s.is_zero); // Global stats for all files ft->stats.xfer_duration += s.xfer_duration; @@ -1313,7 +1348,7 @@ mk_stats_ft(GS_FT *ft) { GS_FT_stats *st = &ft->stats; - mk_bps(st->speed_str, sizeof st->speed_str, st->xfer_duration, st->xfer_amount, st->n_files_success==0?1:0); + mk_bps(st->speed_str, sizeof st->speed_str, st->xfer_duration, st->xfer_amount, st->n_files_success==0?1:0, 0 /*is_zero*/); } void @@ -1359,7 +1394,7 @@ GS_FT_status(GS_FT *ft, uint32_t id, uint8_t code, const char *err_str, size_t l if (err_str[len] != '\0') return; // protocol error. Not 0 terminated. - DEBUGF_R("#%u STATUS: code=%u (%s)\n", id, code, err_str); + DEBUGF_R("#%u STATUS: code=%u [%s](remote says='%s')\n", id, code, GS_FT_strerror(code), err_str); // There can not be an error in fqueue or plistreq or flist as those are // local lists. Here we only care about lists that send a request @@ -1432,6 +1467,7 @@ GS_FT_status(GS_FT *ft, uint32_t id, uint8_t code, const char *err_str, size_t l // Report stats to caller. Tread ERR_COMPLETED not as an error. mk_stats_file(ft, id, f, name, err); } + } if (f != NULL) @@ -1439,8 +1475,10 @@ GS_FT_status(GS_FT *ft, uint32_t id, uint8_t code, const char *err_str, size_t l if (li->data == ft->active_put_file) ft->active_put_file = NULL; - ft_done(ft); - ft_del(li); + if (ft->is_server == 0) + ft_done(ft); + + ft_del(li); // SERVER & CLIENT } else { // From a PATTERN request (LISTREQ, Client, get, download). // File structure is not available. @@ -1448,6 +1486,17 @@ GS_FT_status(GS_FT *ft, uint32_t id, uint8_t code, const char *err_str, size_t l GS_LIST_del(li); } + DEBUGF("WAITING: %d %d\n", ft->n_files_waiting, ft->plistreq_waiting.n_items); + if (ft->is_server == 0) + { + // CLIENT + // Trigger caller to call GS_FT_packet() so that caller gets the GS_FT_DONE return + // value to then output (and reset) the stats. This can happen when a zero-sized file + // is transfered. + if ((ft->n_files_waiting == 0) && (ft->plistreq_waiting.n_items == 0)) + ft->is_want_write = 1; + } + } /* diff --git a/tools/filetransfer.h b/tools/filetransfer.h index ded622c6..0d70026b 100644 --- a/tools/filetransfer.h +++ b/tools/filetransfer.h @@ -44,6 +44,7 @@ struct _gs_ft_stats_file const char *fname; uint64_t xfer_duration; // Actual transfer time (without suspension) uint64_t xfer_amount; // Actual data transfered + int is_zero; char speed_str[GS_FT_SPEEDSTR_MAXSIZE]; // Speed (bps). Human readable string. }; @@ -114,9 +115,7 @@ typedef struct int is_paused_data; // write() blocked. Queue control data. Pause sending file data int n_files_waiting; // Files waiting for completion or error FIXME: This should be n_requests_waiting - int is_want_write; - // ..and be a counter of all outstanding requests we are awaiting an answer for.... - // int n_listreply_waiting; + int is_want_write; // FT has data to write. Requesting call to GS_FT_packet(). // Statistics total (all files) GS_FT_stats stats; diff --git a/tools/filetransfer_mgr.c b/tools/filetransfer_mgr.c index 10fd0a90..142be185 100644 --- a/tools/filetransfer_mgr.c +++ b/tools/filetransfer_mgr.c @@ -101,6 +101,8 @@ pkt_cb_switch(uint8_t chn, const uint8_t *data, size_t len, void *arg) memcpy(&hdr, data, sizeof hdr); GS_FT_switch(ft, ntohl(hdr.id), ntohll(hdr.offset)); + if (GS_FT_WANT_WRITE(ft)) + GS_SELECT_FD_SET_W(peer->gs); } /* SERVER receiving DATA from client */ @@ -147,6 +149,13 @@ pkt_cb_error(uint8_t chn, const uint8_t *data, size_t len, void *arg) memcpy(&hdr, data, sizeof hdr); GS_FT_status(ft, ntohl(hdr.id), hdr.code, (char *)p->str, len - sizeof hdr - 1); + if (GS_FT_WANT_WRITE(ft)) + { + // GS_FT-stack wants caller to call GS_FT_packet(). The only way we can + // trigger this is to set FD_SET_W() and we know that after select() + // we call GS_FT_packet()... + GS_SELECT_FD_SET_W(peer->gs); + } } // Output total stats @@ -224,6 +233,7 @@ GS_FTM_mk_packet(GS_FT *ft, uint8_t *dst, size_t dlen) // DEBUGF_G("TYPE NONE\n"); return 0; case GS_FT_TYPE_DONE: + DEBUGF_W("GS_FT_TYPE_DONE\n"); // CLIENT only: done with all files. // FIXME: for a 'get' request this is triggered very late and not as soon // as the filetransfer is done (because select() only waits for reading diff --git a/tools/utils.c b/tools/utils.c index 844f3978..3d9e355a 100755 --- a/tools/utils.c +++ b/tools/utils.c @@ -1,12 +1,17 @@ +// #define DEBUG_CTX_DECLARED (1) // All others define this as extern + #include "common.h" #include "utils.h" #include "console.h" struct _gopt gopt; - +#ifdef DEBUG +struct _g_debug_ctx g_dbg_ctx; +#endif extern char **environ; + /* * Add list of argv's from GSOCKET_ARGS to argv[] * result: argv[0] + GSOCKET_ARGS + argv[1..n] From e464f19ee94fcb658deb1d905c04147f37c1df5f Mon Sep 17 00:00:00 2001 From: rootTHC Date: Tue, 23 Feb 2021 07:42:12 +0000 Subject: [PATCH 2/4] small bug fixes. broken ansi. --- man/gs-netcat.1 | 2 +- tools/4_gs-netcat.c | 4 +- tools/common.h | 2 +- tools/console.c | 302 ++++++++++++++++++++++++++++++++++++------ tools/man_gs-netcat.h | 55 +++++++- tools/utils.c | 4 +- 6 files changed, 316 insertions(+), 53 deletions(-) diff --git a/man/gs-netcat.1 b/man/gs-netcat.1 index 8e4521c9..88795a17 100755 --- a/man/gs-netcat.1 +++ b/man/gs-netcat.1 @@ -52,7 +52,7 @@ Generate a secure random password and output it to standard output. .It Fl l Server mode. The default mode is client. .It Fl q -Quite mode. Do not output any warnings or errors. +Quiet mode. Do not output any warnings or errors. .It Fl w Client to wait for the listening server to become available. .It Fl r diff --git a/tools/4_gs-netcat.c b/tools/4_gs-netcat.c index 63d6f138..0806b2bc 100755 --- a/tools/4_gs-netcat.c +++ b/tools/4_gs-netcat.c @@ -1147,10 +1147,10 @@ my_getopt(int argc, char *argv[]) if (gopt.is_daemon) { if (gopt.is_logfile == 0) - gopt.is_quite = 1; + gopt.is_quiet = 1; } - if (gopt.is_quite != 0) + if (gopt.is_quiet != 0) { gopt.log_fp = NULL; gopt.err_fp = NULL; diff --git a/tools/common.h b/tools/common.h index 7219eda0..b45909a9 100755 --- a/tools/common.h +++ b/tools/common.h @@ -130,7 +130,7 @@ struct _gopt int is_multi_peer; /* -p / -S / -d [client & server] */ int is_daemon; int is_logfile; - int is_quite; + int is_quiet; int is_win_resized; // window size changed (signal) int is_console; // console is being displayed int is_pong_pending; // Server: Answer to PING waiting to be send diff --git a/tools/console.c b/tools/console.c index 292104d1..27f073d5 100644 --- a/tools/console.c +++ b/tools/console.c @@ -618,21 +618,6 @@ CONSOLE_reset(void) tty_fd = -1; } -struct _pat -{ - char *data; - size_t len; - int type; -}; - -static struct _pat cls_pattern[] = { - {"\x1B[0J", 4, 1}, // Clear screen from cursor down - {"\x1B[J", 3, 1}, // Clear screen from cursor down - {"\x1B[2J", 4, 1}, // Clear entire screen - {"\x1B[?1049h", 8, 2}, // Switch Alternate Screen Buffer (clears screen) - {"\x1B[?1049l", 8, 3}, // Switch Normal Screen Buffer (clears screen) - {"\x1B""c", 2, 4} // Reset terminal to initial state -}; #ifdef DEBUG /* @@ -745,6 +730,22 @@ ansi_output(void *data, size_t len) static uint8_t cls_buf[8]; static size_t cls_pos; +struct _pat +{ + char *data; + size_t len; + int type; +}; + +static struct _pat cls_pattern[] = { + {"\x1B[0J", 4, 1}, // Clear screen from cursor down + {"\x1B[J", 3, 1}, // Clear screen from cursor down + {"\x1B[2J", 4, 1}, // Clear entire screen + {"\x1B[?1049h", 8, 2}, // Switch Alternate Screen Buffer (clears screen) + {"\x1B[?1049l", 8, 3}, // Switch Normal Screen Buffer (clears screen) + {"\x1B""c", 2, 4} // Reset terminal to initial state +}; + /* * Parse output and check for a any terminal escape sequence that clears * the screen. @@ -763,25 +764,182 @@ static size_t cls_pos; * unfinished ansi sequence). */ -static void -ansi_parse(void *data, size_t len, size_t *amount, int *cls_code) +// Parse through the ansi sequence until it is finished. +// Return length of ansi sequence or 0 if more data is required (ansi sequence hasnt finished yet) +static size_t +ansi_until_end(uint8_t *src, size_t src_sz) +{ + uint8_t *src_end = src + src_sz; + uint8_t *src_orig = src; + + while (src < src_end) + { + DEBUGF_B("%02x\n", *src); + if (*src == '\x1B') + { + // Huh? An ESC inside an ansi sequence? + return src - src_orig; + } + + // Check here + if (*src == '[') + goto skip; + + // Found the end of the ansi sequence (hoho) + + break; +skip: + src++; + } + + return src - src_orig; +} + +static size_t +ansi_until_esc(uint8_t *src, size_t src_sz, int *in_esc) +{ + uint8_t *src_end = src + src_sz; + uint8_t *src_orig = src; + + while (src < src_end) + { + if (*src == '\x1B') + { + *in_esc = 1; + DEBUGF("at pos %zd=%02x\n", src - src_orig - 1, *src); + return src - src_orig; + } + src++; + } + + return src - src_orig; +} + +static int in_esc; +static uint8_t ansi_buf[64]; +static size_t ansi_buf_len; + +// Parse 'src' for an ansi sequence that we might be interested in. +// *tail_len contains a number of bytes if there is an incomplete ansi-sequence (and we +// do not have enough data yet) +// +// Return: Length of data in dst. +static size_t +ansi_parse(uint8_t *src, size_t src_sz, uint8_t *dst, size_t dst_sz, size_t *tail_len, int *cls_code) +{ + uint8_t *src_orig = src; + uint8_t *src_end = src + src_sz; + uint8_t *dst_orig = dst; + uint8_t *dst_end = dst + dst_sz; + size_t len; + + DEBUGF("ansi_buf_len=%zd\n", ansi_buf_len); + while (src < src_end) + { + if (in_esc) + { + DEBUGF_Y("IN esc\n"); + len = ansi_until_end(src, src_end - src); + DEBUGF("esc len = %zd\n", len); + if (len == 0) + { + // Not enough data + *tail_len = src_end - src; + break; + } + + // HERE: Got a full ansi sequence. Either in ansi_buf or src. + // Copy into ansi-buf to make it easier: + if (ansi_buf_len + len > sizeof ansi_buf) + { + // Does not fit. + // Copy into dst + XASSERT(dst_end - dst <= ansi_buf_len, "Buffer to small\n"); + memcpy(dst, ansi_buf, ansi_buf_len); + dst += ansi_buf_len; + + XASSERT(dst_end - dst <= len, "Buffer to small\n"); + memcpy(dst, src, len); + dst += len; + src += len; + in_esc = 0; + continue; + } + STOP HERE: damn. need ot think this better. perhaps easier to have a temp buffer of 64 or so + and if ansi_buf contains data then just check on ansi_buf + src if there is a match and otherwise + check on src. + + // Append to internal ansi buffer + memcpy(ansi_buf + ansi_buf_len, src, len); + ansi_buf_len += len; + + // Check if we are interested in this ansi squence + + // We let this sequence pass through to the terminal: + if (dst_end - dst >= ansi_buf_len) + memcpy(dst, ansi_buf, ansi_buf_len); + dst += ansi_buf_len; + src += len; + + // len is the length of the ansi sequence + ansi_buf_len = 0; + in_esc = 0; + } else { + DEBUGF_Y("not esc\n"); + len = ansi_until_esc(src, src_end - src, &in_esc); + memcpy(dst, src, len); + dst += len; + src += len; // *src points to ESC or is done. + } + + } + + return dst - dst_orig; +} +#if 0 + +static size_t +ansi_parse(uint8_t *src, size_t src_sz, uint8_t *dst, size_t dst_sz, size_t *amount, int *cls_code) { static int in_esc; static int in_esc_pos; - uint8_t *src = (uint8_t *)data; + static int is_semicolon; uint8_t *src_orig = src; - uint8_t *src_end = src + len; + uint8_t *src_end = src + src_sz; + uint8_t *src_last = src; + uint8_t *dst_orig = dst; + uint8_t *dst_end = dst + dst_sz; int rv = 0; while (src < src_end) { if (*src == '\x1B') { + if (in_esc) + { + // Encountered a \x1b while inside an escape? Oops. + DEBUGF_R("SHOULD NOT HAPPEN\n"); + cls_pos = 0; + in_esc = 0; + goto skip; + } in_esc = 1; + src_esc = src; *amount = src - src_orig; in_esc_pos = 0; /* Start of pattern */ cls_pos = 0; + + size_t len = src - src_last; + if (len > 1) + { + // Found an ESC-sequence. Copy all data until now into dst. + XASSERT(dst + len < dst_end, "Buffer to small!\n"); + memcpy(dst, src_last, len); + dst += len; + src_last = src; + } + } else { if (in_esc == 0) goto skip; // ESC not yet encountered @@ -820,7 +978,10 @@ ansi_parse(void *data, size_t len, size_t *amount, int *cls_code) if ((*src >= '0') && (*src <= '9')) break; if (*src == ';') + { + is_semicolon = 1; break; + } if (*src == '?') break; } @@ -830,6 +991,8 @@ ansi_parse(void *data, size_t len, size_t *amount, int *cls_code) break; } + + // None of our sequences is longer than this. if (cls_pos >= sizeof cls_buf) goto skip; @@ -842,6 +1005,36 @@ ansi_parse(void *data, size_t len, size_t *amount, int *cls_code) if (cls_pos < 2) goto skip; + // Check if app tried to move out of screen area (into console) and drop + // such commands (like debian's TOP sends [26;1H] on exit even if scrolling area is + // is 25;80) + DEBUGF("is-semi = %d %c\n", is_semicolon, *src); + if ((in_esc == 0) && (cls_pos > 4) && (is_semicolon)) + { + is_semicolon = 0; + + if ((*src == 'H') || (*src == 'h')) + { + cls_buf[7] = '\0'; + DEBUGF("'%s'\n", (char *)(cls_buf + 1)); + char *ptr = strchr((char *)cls_buf, ';'); + if (ptr != NULL) + { + *ptr = '\0'; + int row = atoi((char *)(cls_buf + 2)); // skipe \x1b[ + DEBUGF("WANTS ROW %d %d\n", row, gopt.winsize.ws_row - GS_CONSOLE_ROWS); + if (row > gopt.winsize.ws_row - GS_CONSOLE_ROWS) + { + DEBUGF_R("DENIED\n"); + cls_pos = 0; + in_esc = 0; + goto skip; + } + } + } + + } + //Check if any ESC sequence matches int i; for (i = 0; i < sizeof cls_pattern / sizeof *cls_pattern; i++) @@ -861,7 +1054,10 @@ ansi_parse(void *data, size_t len, size_t *amount, int *cls_code) *amount = len; *cls_code = rv; + + return dst - dst_orig; } +#endif /* * Buffered write to ansi terminal. All output to terminal needs to be analyzed @@ -879,41 +1075,57 @@ ansi_parse(void *data, size_t len, size_t *amount, int *cls_code) * - If half way inside an ansi sequence then buffer the remaining * - Also return if an ansi sequence was sent that clears the screen */ -static uint8_t ansi_buf[64]; -static size_t ansi_buf_len; +// Parse ANSI: +// 1. Find any ansi sequence that clears the screen (so we know when to draw our console again) +// 2. Substitute ESC-sequences with our own to stop console from getting fucked. +// 3. If the ESC-sequence stops half way then write *dst and record +// the remaining sequence (if we have that much space) static ssize_t -ansi_write(int fd, void *data, size_t len, int *cls_code) +ansi_write(int fd, void *src, size_t src_len, int *cls_code) { size_t amount = 0; + size_t dst_sz = src_len; + uint8_t dst[dst_sz + sizeof ansi_buf]; // alloc() + size_t dst_len; + size_t tail_len = 0; - ansi_parse(data, len, &amount, cls_code); - // DEBUGF_W("len = %zd amount = %zd\n", len, amount); - if (amount == 0) - goto done; - if (ansi_buf_len > 0) + HEXDUMP(src, src_len); + dst_len = ansi_parse(src, src_len, dst, dst_sz, &tail_len, cls_code); + + if (dst_len > 0) { - if (write(fd, ansi_buf, ansi_buf_len) != ansi_buf_len) + if (write(fd, dst, dst_len) != dst_len) return -1; - ansi_buf_len = 0; - } - - if (write(fd, data, amount) != amount) - return -1; #ifdef DEBUG - // ansi_output(data, amount); + ansi_output(dst, dst_len); #endif + } - if (amount < len) + if (tail_len > 0) { - uint8_t *end = ansi_buf + sizeof (ansi_buf); - uint8_t *ptr = ansi_buf + ansi_buf_len; + // Check if there is enough space in our ansi-buf + if (ansi_buf_len + tail_len < sizeof ansi_buf) + { + memcpy(ansi_buf + ansi_buf_len, src - tail_len, tail_len); + ansi_buf_len += tail_len; + goto done; + } - XASSERT(end - ptr >= len - amount, "ANSI buffer to small\n"); + // NOT enough space. + in_esc = 0; - memcpy(ptr, (uint8_t *)data + amount, len - amount); - ansi_buf_len += (len - amount); - // HEXDUMPF(ansi_buf, ansi_buf_len, "ansi buffer (%zd)", ansi_buf_len); + // ANSI esc sequence that does not fit into our ansi buffer. + // Output it (ignore such sequences - we are not interested) + if (ansi_buf_len > 0) + { + if (write(fd, ansi_buf, ansi_buf_len) != ansi_buf_len) + return -1; + ansi_buf_len = 0; + } + // And output the 'tail' that does not fit in. + if (write(fd, src - tail_len, tail_len) != tail_len) + return -1; } done: @@ -921,7 +1133,7 @@ ansi_write(int fd, void *data, size_t len, int *cls_code) // and this function will buffer (if needed) any data not yet passed // to 'write()'. Thus return 'len' here to satisfy caller that all supplied // data is or will be processed. - return len; + return src_len; } static int is_console_before_sb; // before Alternate Screen Buffer @@ -957,6 +1169,8 @@ CONSOLE_write(int fd, void *data, size_t len) ssize_t sz; sz = ansi_write(fd, data, len, &is_detected_clearscreen); + if (gopt.is_console == 0) + return sz; // The write() to upper tier may have set some funky paste modes // and we need to reset this for console input. @@ -998,8 +1212,8 @@ CONSOLE_write(int fd, void *data, size_t len) console_start(); } - if (gopt.is_console == 0) - return sz; + // if (gopt.is_console == 0) + // return sz; if (is_detected_clearscreen) console_draw(fd, 1 /*force*/); diff --git a/tools/man_gs-netcat.h b/tools/man_gs-netcat.h index 04a7eb10..d07e0db9 100644 --- a/tools/man_gs-netcat.h +++ b/tools/man_gs-netcat.h @@ -45,7 +45,7 @@ OPTIONS\n\ \n\ -l Server mode. The default mode is client.\n\ \n\ - -q Quite mode. Do not output any warnings or errors.\n\ + -q Quiet mode. Do not output any warnings or errors.\n\ \n\ -w Client to wait for the listening server to become available.\n\ \n\ @@ -74,13 +74,62 @@ OPTIONS\n\ \n\ -i Interactive login shell. The server spawns a true PTY login\n\ shell. The client acts as a true PTY client (with Ctrl-C etc\n\ - working). The client can terminate the session by typing '~.' at\n\ - any time or by typing 'exit'. The server supports multiple\n\ + working). The client can terminate the session by typing 'Ctrl-e\n\ + q' at any time or by typing 'exit'. The server supports multiple\n\ clients at the same time.\n\ \n\ \n\ port can be a numerical value between 1-65535.\n\ \n\ +CONSOLE\n\ + Pressing 'Ctrl-e c' (e for EEEElite) opens the command console. The com-\n\ + mand console displays the following information:\n\ +\n\ + o Latency (in milliseconds) to the remote host\n\ + o Warning when a user logs into the system or becomes active\n\ + o Data troughput\n\ + o File transfer logs\n\ + Type 'help' for a list of available commands.\n\ +\n\ +\n\ +FILETRANSFER\n\ + File transfer is available from the command console. Files are transfered\n\ + with the permission and modification timestamp unchanged. Partially\n\ + transfered files are re-started where the transfer was left off.\n\ +\n\ + The 'put' command is used for uploading:\n\ +\n\ + put foobar.txt\n\ + put $HOME/foobar.txt\n\ + put /tmp/*.log\n\ + put $(find. -type f -name '*.c')\n\ +\n\ + (The above example shows Shell Variable substitution and word expansion)\n\ +\n\ + It is possible to limit the amount of path information that is sent as\n\ + implied directories for each path you specify. You can insert a dot and a\n\ + slash into the source path, like this:\n\ +\n\ + put /foo/./bar/baz.c\n\ +\n\ + That would create /tmp/bar/baz.c on the remote machine.\n\ +\n\ + The 'get' command is used for downloading:\n\ +\n\ + get foobar.txt\n\ + get $(find /var/./ -name '*.log')\n\ +\n\ + Transfering a directory automatically transfers all files and directories\n\ + within that directory (recursively):\n\ +\n\ + get /var/log\n\ + get /\n\ + The first command transfers all directories and files in /var/log/*. The\n\ + latter command transfers the entire filesystem.\n\ +\n\ + Multiple get/put commands can be scheduled at the same time.\n\ +\n\ +\n\ EXAMPLES\n\ Example 1 - Listen for a new connection using the password 'MySecret':\n\ $ gs-netcat -s MySecret -l\n\ diff --git a/tools/utils.c b/tools/utils.c index 3d9e355a..951b0580 100755 --- a/tools/utils.c +++ b/tools/utils.c @@ -196,7 +196,7 @@ usage(const char *params) fprintf(stderr, " -L Logfile\n"); break; case 'q': - fprintf(stderr, " -q Quite. No log output\n"); + fprintf(stderr, " -q Quiet. No log output\n"); break; case 'r': fprintf(stderr, " -r Receive-only. Terminate when no more data.\n"); @@ -275,7 +275,7 @@ do_getopt(int argc, char *argv[]) gopt.is_use_tor = 1; break; case 'q': - gopt.is_quite = 1; + gopt.is_quiet = 1; break; case 'r': gopt.is_receive_only = 1; From 1d87ee6654512335073fc55bc070ccd42e3f1c22 Mon Sep 17 00:00:00 2001 From: rootTHC Date: Tue, 23 Feb 2021 12:20:42 +0000 Subject: [PATCH 3/4] ansi sub system --- include/gsocket/buf.h | 3 + tools/common.h | 22 +-- tools/console.c | 326 ++++++++++++++++-------------------------- 3 files changed, 139 insertions(+), 212 deletions(-) diff --git a/include/gsocket/buf.h b/include/gsocket/buf.h index 382bdcb3..ba9f0cfe 100644 --- a/include/gsocket/buf.h +++ b/include/gsocket/buf.h @@ -18,6 +18,9 @@ int GS_BUF_add(GS_BUF *gsb, size_t len); int GS_BUF_add_data(GS_BUF *gsb, void *data, size_t len); int GS_BUF_del(GS_BUF *gsb, size_t len); +#define GS_BUF_empty(gsb) (gsb)->sz_used = 0; +#define GS_BUF_DATA(gsb) (gsb)->data +#define GS_BUF_IS_INIT(gsb) ((gsb)->sz_max_add!=0) #define GS_BUF_UNUSED(gsb) ((gsb)->sz_total - (gsb)->sz_used) #define GS_BUF_RSRC(gsb) (gsb)->data #define GS_BUF_WDST(gsb) ((uint8_t *)(gsb)->data + (gsb)->sz_used) diff --git a/tools/common.h b/tools/common.h index b45909a9..fa2bab7b 100755 --- a/tools/common.h +++ b/tools/common.h @@ -224,6 +224,17 @@ extern struct _gopt gopt; // declared in utils.c # define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) #endif +#define D_RED(a) "\033[0;31m"a"\033[0m" +#define D_GRE(a) "\033[0;32m"a"\033[0m" +#define D_YEL(a) "\033[0;33m"a"\033[0m" +#define D_BLU(a) "\033[0;34m"a"\033[0m" +#define D_MAG(a) "\033[0;35m"a"\033[0m" +#define D_BRED(a) "\033[1;31m"a"\033[0m" +#define D_BGRE(a) "\033[1;32m"a"\033[0m" +#define D_BYEL(a) "\033[1;33m"a"\033[0m" +#define D_BBLU(a) "\033[1;34m"a"\033[0m" +#define D_BMAG(a) "\033[1;35m"a"\033[0m" + #ifdef DEBUG struct _g_debug_ctx { @@ -242,17 +253,6 @@ extern struct _g_debug_ctx g_dbg_ctx; // declared in utils.c if (xcolor) { xfprintf(gopt.err_fp, "\033[0m"); } \ } while (0) - -#define D_RED(a) "\033[0;31m"a"\033[0m" -#define D_GRE(a) "\033[0;32m"a"\033[0m" -#define D_YEL(a) "\033[0;33m"a"\033[0m" -#define D_BLU(a) "\033[0;34m"a"\033[0m" -#define D_MAG(a) "\033[0;35m"a"\033[0m" -#define D_BRED(a) "\033[1;31m"a"\033[0m" -#define D_BGRE(a) "\033[1;32m"a"\033[0m" -#define D_BYEL(a) "\033[1;33m"a"\033[0m" -#define D_BBLU(a) "\033[1;34m"a"\033[0m" -#define D_BMAG(a) "\033[1;35m"a"\033[0m" # define DEBUGF(a...) do{DEBUGF_T(NULL, a); } while(0) # define DEBUGF_R(a...) do{DEBUGF_T("\033[1;31m", a); } while(0) # define DEBUGF_G(a...) do{DEBUGF_T("\033[1;32m", a); } while(0) diff --git a/tools/console.c b/tools/console.c index 27f073d5..e55afd43 100644 --- a/tools/console.c +++ b/tools/console.c @@ -618,118 +618,6 @@ CONSOLE_reset(void) tty_fd = -1; } - -#ifdef DEBUG -/* - * For debugging only. - * Find the next ansi sequence. - * Return the length of the sequence. Set 'is_ansi' if it's an ansi sequence. - * The sequence can be a non-ansi sequence (e.g. normal data) or an ansi sequnce. - */ -static size_t -ansi_next(void *data, size_t len, int *is_ansi) -{ - static int in_esc; - static int in_esc_pos; - uint8_t *src = (uint8_t *)data; - uint8_t *src_orig = src; - uint8_t *src_end = src + len; - - in_esc_pos = 0; - in_esc = 0; - *is_ansi = 0; - if (*src == '\x1B') - { - src++; - *is_ansi = 1; - in_esc = 1; - } - - for (; src < src_end; src++) - { - if (in_esc == 0) - { - if (*src != '\x1B') - continue; - - *is_ansi = 0; - return src - src_orig; - } - - // HERE: in escape sequence - // Check when escape finishes - if (*src == '\x1B') - break; - in_esc_pos++; - - if (in_esc_pos == 1) - { - // Check if multi character esc sequence - if (*src == '[') - continue; - if (*src == '(') - continue; - if (*src == ')') - continue; - if (*src == '#') - continue; // Esc-#2 - if (*src == '6') - continue; // Esc-6n - if (*src == '5') - continue; - if (*src == '0') - continue; - if (*src == '3') - continue; - - break; - } - - if (in_esc_pos >= 2) - { - if ((*src >= '0') && (*src <= '9')) - continue; - if (*src == ';') - continue; - if (*src == '?') - continue; - - break; - } - - break; - } - return src - src_orig + 1; -} - -// For debugging -static void -ansi_output(void *data, size_t len) -{ - uint8_t *src = (uint8_t *)data; - uint8_t *src_end = src + len; - int is_ansi; - size_t n; - char buf[64]; - - while (src < src_end) - { - n = ansi_next(src, src_end - src, &is_ansi); - XASSERT(n > 0, "n is 0\n"); - if (is_ansi) - { - snprintf(buf, sizeof buf, "%.*s", (int)(n - 1), src + 1); - DEBUGF_B("ansi: %s\n", buf); - } - else - HEXDUMP(src, n); - src += n; - } -} -#endif - -static uint8_t cls_buf[8]; -static size_t cls_pos; struct _pat { char *data; @@ -767,28 +655,45 @@ static struct _pat cls_pattern[] = { // Parse through the ansi sequence until it is finished. // Return length of ansi sequence or 0 if more data is required (ansi sequence hasnt finished yet) static size_t -ansi_until_end(uint8_t *src, size_t src_sz) +ansi_until_end(uint8_t *src, size_t src_sz, int *ignore) { uint8_t *src_end = src + src_sz; uint8_t *src_orig = src; + // Must start with ^[ + XASSERT(*src == '\x1b', "src not starting with 0x1B (0x02%c)\n", *src); + src += 1; + *ignore = 0; + while (src < src_end) { - DEBUGF_B("%02x\n", *src); if (*src == '\x1B') { // Huh? An ESC inside an ansi sequence? + *ignore = 1; return src - src_orig; } - // Check here - if (*src == '[') - goto skip; + if (src > src_orig + 16) + { + // ESC sequence is to long. We are not interested.... + *ignore = 1; + return src - src_orig; + } - // Found the end of the ansi sequence (hoho) + // Check if this is the end of an ansi sequence + if ((*src >= 'a') && (*src <= 'z')) + { + src++; + break; + } + + if ((*src >= 'A') && (*src <= 'Z')) + { + src++; + break; + } - break; -skip: src++; } @@ -806,8 +711,8 @@ ansi_until_esc(uint8_t *src, size_t src_sz, int *in_esc) if (*src == '\x1B') { *in_esc = 1; - DEBUGF("at pos %zd=%02x\n", src - src_orig - 1, *src); - return src - src_orig; + // DEBUGF("at pos %zd=0x%02x\n", src - src_orig, *src); + break; } src++; } @@ -816,31 +721,26 @@ ansi_until_esc(uint8_t *src, size_t src_sz, int *in_esc) } static int in_esc; -static uint8_t ansi_buf[64]; -static size_t ansi_buf_len; + // Parse 'src' for an ansi sequence that we might be interested in. // *tail_len contains a number of bytes if there is an incomplete ansi-sequence (and we // do not have enough data yet) // // Return: Length of data in dst. -static size_t -ansi_parse(uint8_t *src, size_t src_sz, uint8_t *dst, size_t dst_sz, size_t *tail_len, int *cls_code) +static void +ansi_parse(uint8_t *src, size_t src_sz, GS_BUF *dst, size_t *tail_len, int *cls_code) { - uint8_t *src_orig = src; uint8_t *src_end = src + src_sz; - uint8_t *dst_orig = dst; - uint8_t *dst_end = dst + dst_sz; size_t len; + int ignore; - DEBUGF("ansi_buf_len=%zd\n", ansi_buf_len); while (src < src_end) { if (in_esc) { - DEBUGF_Y("IN esc\n"); - len = ansi_until_end(src, src_end - src); - DEBUGF("esc len = %zd\n", len); + len = ansi_until_end(src, src_end - src, &ignore); + // DEBUGF("esc len=%zd, ignore=%d, dst=%zd, left=%zd\n", len, ignore, GS_BUF_USED(dst), src_end - src); if (len == 0) { // Not enough data @@ -848,53 +748,85 @@ ansi_parse(uint8_t *src, size_t src_sz, uint8_t *dst, size_t dst_sz, size_t *tai break; } - // HERE: Got a full ansi sequence. Either in ansi_buf or src. - // Copy into ansi-buf to make it easier: - if (ansi_buf_len + len > sizeof ansi_buf) + in_esc = 0; + DEBUGF_B("ANSI %.*s\n", (int)len -1, src+1); + if (ignore) { - // Does not fit. - // Copy into dst - XASSERT(dst_end - dst <= ansi_buf_len, "Buffer to small\n"); - memcpy(dst, ansi_buf, ansi_buf_len); - dst += ansi_buf_len; - - XASSERT(dst_end - dst <= len, "Buffer to small\n"); - memcpy(dst, src, len); - dst += len; + GS_BUF_add_data(dst, src, len); src += len; - in_esc = 0; continue; } - STOP HERE: damn. need ot think this better. perhaps easier to have a temp buffer of 64 or so - and if ansi_buf contains data then just check on ansi_buf + src if there is a match and otherwise - check on src. - // Append to internal ansi buffer - memcpy(ansi_buf + ansi_buf_len, src, len); - ansi_buf_len += len; + // If console is not open then we do not have to check or substitute any ansi sequences + if (gopt.is_console == 0) + { + GS_BUF_add_data(dst, src, len); + src += len; + continue; + } + + // Check if this was a cursor-position request that moved the course + // outside its boundary (and into our console, like debian's top does (!)) + // '\x1b' + '[1;1h' + int is_substitute = 0; + while (1) + { + if (len < 6) + break; + // DEBUGF_W("len %d\n", len); + if ((src[len-1] != 'H') && (src[len-1] != 'h')) + break; + // search for ';' between src+2 and src+len + uint8_t *ptr = src+2; + for (ptr = src + 2; ptr < src+len; ptr++) + { + if (*ptr == ';') + break; + } + if (*ptr != ';') + break; + + int row = atoi((char *)src+2); + int col = atoi((char *)ptr+1); + // DEBUGF_W("pos %d:%d\n", row, col); + if (row > gopt.winsize.ws_row - GS_CONSOLE_ROWS) + { + char buf[32]; + snprintf(buf, sizeof buf, "\x1B[%d;%dH\r\n", gopt.winsize.ws_row - GS_CONSOLE_ROWS, col); + DEBUGF_R("DENIED. Changed to: %s\n", buf + 1); + + GS_BUF_add_data(dst, buf, strlen(buf)); + src += len; + is_substitute = 1; + } + break; + } + if (is_substitute) + continue; - // Check if we are interested in this ansi squence + // Check for any ANSI sequence that may have cleared the screen: + int i; + for (i = 0; i < sizeof cls_pattern / sizeof *cls_pattern; i++) + { + if (cls_pattern[i].len != len) + continue; + if (memcmp(cls_pattern[i].data, src, len) != 0) + continue; + DEBUGF_W("CLS found %d\n", cls_pattern[i].type); + *cls_code = cls_pattern[i].type; + } - // We let this sequence pass through to the terminal: - if (dst_end - dst >= ansi_buf_len) - memcpy(dst, ansi_buf, ansi_buf_len); - dst += ansi_buf_len; + // We are not interested to substitute it. Let it pass through. + GS_BUF_add_data(dst, src, len); src += len; - - // len is the length of the ansi sequence - ansi_buf_len = 0; - in_esc = 0; } else { - DEBUGF_Y("not esc\n"); + // DEBUGF_Y("#%zd not in esc\n", src - src_orig); len = ansi_until_esc(src, src_end - src, &in_esc); - memcpy(dst, src, len); - dst += len; + GS_BUF_add_data(dst, src, len); src += len; // *src points to ESC or is done. } } - - return dst - dst_orig; } #if 0 @@ -1059,6 +991,8 @@ ansi_parse(uint8_t *src, size_t src_sz, uint8_t *dst, size_t dst_sz, size_t *amo } #endif +GS_BUF g_dst; +GS_BUF g_ansi; /* * Buffered write to ansi terminal. All output to terminal needs to be analyzed * and checked for 'clear screen' ansi code. If found then the console needs @@ -1084,56 +1018,44 @@ ansi_parse(uint8_t *src, size_t src_sz, uint8_t *dst, size_t dst_sz, size_t *amo static ssize_t ansi_write(int fd, void *src, size_t src_len, int *cls_code) { - size_t amount = 0; - size_t dst_sz = src_len; - uint8_t dst[dst_sz + sizeof ansi_buf]; // alloc() - size_t dst_len; + // size_t amount = 0; size_t tail_len = 0; + size_t src_len_orig = src_len; - HEXDUMP(src, src_len); - dst_len = ansi_parse(src, src_len, dst, dst_sz, &tail_len, cls_code); + if (!GS_BUF_IS_INIT(&g_dst)) + { + GS_BUF_init(&g_dst, 1024); + GS_BUF_init(&g_ansi, 1024); + } + + // HEXDUMP(src, src_len); + if (GS_BUF_USED(&g_ansi) > 0) + { + GS_BUF_add_data(&g_ansi, src, src_len); + src = GS_BUF_DATA(&g_ansi); + src_len = GS_BUF_USED(&g_ansi); + } + ansi_parse(src, src_len, &g_dst, &tail_len, cls_code); - if (dst_len > 0) + if (GS_BUF_USED(&g_dst) > 0) { - if (write(fd, dst, dst_len) != dst_len) + if (write(fd, GS_BUF_DATA(&g_dst), GS_BUF_USED(&g_dst)) != GS_BUF_USED(&g_dst)) return -1; -#ifdef DEBUG - ansi_output(dst, dst_len); -#endif } + GS_BUF_empty(&g_dst); if (tail_len > 0) { - // Check if there is enough space in our ansi-buf - if (ansi_buf_len + tail_len < sizeof ansi_buf) - { - memcpy(ansi_buf + ansi_buf_len, src - tail_len, tail_len); - ansi_buf_len += tail_len; - goto done; - } - - // NOT enough space. - in_esc = 0; - - // ANSI esc sequence that does not fit into our ansi buffer. - // Output it (ignore such sequences - we are not interested) - if (ansi_buf_len > 0) - { - if (write(fd, ansi_buf, ansi_buf_len) != ansi_buf_len) - return -1; - ansi_buf_len = 0; - } - // And output the 'tail' that does not fit in. - if (write(fd, src - tail_len, tail_len) != tail_len) - return -1; + GS_BUF_empty(&g_ansi); + GS_BUF_add_data(&g_ansi, src + src_len - tail_len, tail_len); + DEBUGF_W("TAIL length %zd\n", GS_BUF_USED(&g_ansi)); } -done: // From the caller's perspective this function has processed all data // and this function will buffer (if needed) any data not yet passed // to 'write()'. Thus return 'len' here to satisfy caller that all supplied // data is or will be processed. - return src_len; + return src_len_orig; } static int is_console_before_sb; // before Alternate Screen Buffer @@ -1216,7 +1138,9 @@ CONSOLE_write(int fd, void *data, size_t len) // return sz; if (is_detected_clearscreen) + { console_draw(fd, 1 /*force*/); + } if (is_cursor_in_console) { From 95c6e89bdb424e64b2ecf8ba73e7dec7c0f6f91b Mon Sep 17 00:00:00 2001 From: rootTHC Date: Tue, 23 Feb 2021 15:51:51 +0000 Subject: [PATCH 4/4] ansi fix --- include/gsocket/buf.h | 3 +- lib/buf.c | 13 +- tools/common.h | 2 +- tools/console.c | 305 ++++++++++++++------------------------ tools/filetransfer-test.c | 2 +- tools/filetransfer.c | 2 +- tools/filetransfer_mgr.c | 2 +- 7 files changed, 131 insertions(+), 198 deletions(-) diff --git a/include/gsocket/buf.h b/include/gsocket/buf.h index ba9f0cfe..906be879 100644 --- a/include/gsocket/buf.h +++ b/include/gsocket/buf.h @@ -14,9 +14,10 @@ typedef struct void GS_BUF_init(GS_BUF *gsb, size_t sz_min_free); void GS_BUF_free(GS_BUF *gsb); int GS_BUF_resize(GS_BUF *gsb, size_t sz_new); -int GS_BUF_add(GS_BUF *gsb, size_t len); +int GS_BUF_add_length(GS_BUF *gsb, size_t len); int GS_BUF_add_data(GS_BUF *gsb, void *data, size_t len); int GS_BUF_del(GS_BUF *gsb, size_t len); +int GS_BUF_memmove(GS_BUF *gsb, void *data, size_t len); #define GS_BUF_empty(gsb) (gsb)->sz_used = 0; #define GS_BUF_DATA(gsb) (gsb)->data diff --git a/lib/buf.c b/lib/buf.c index 373623da..e368b8d0 100644 --- a/lib/buf.c +++ b/lib/buf.c @@ -40,7 +40,7 @@ GS_BUF_resize(GS_BUF *gsb, size_t sz_new) } int -GS_BUF_add(GS_BUF *gsb, size_t len) +GS_BUF_add_length(GS_BUF *gsb, size_t len) { // Bail. There is sz_max_add space available but looks like caller wrote // more ata... @@ -65,6 +65,17 @@ GS_BUF_add_data(GS_BUF *gsb, void *data, size_t len) return 0; } +int +GS_BUF_memmove(GS_BUF *gsb, void *data, size_t len) +{ + GS_BUF_resize(gsb, len); + memmove((uint8_t *)gsb->data + gsb->sz_used, data, len); + + gsb->sz_used += len; + + return 0; +} + /* * Consume data from beginning. */ diff --git a/tools/common.h b/tools/common.h index fa2bab7b..4f0fc98a 100755 --- a/tools/common.h +++ b/tools/common.h @@ -339,7 +339,7 @@ extern struct _g_debug_ctx g_dbg_ctx; // declared in utils.c #ifdef DEBUG # define HEXDUMP(a, _len) do { \ size_t _n = 0; \ - xfprintf(gopt.err_fp, "%s:%d HEX ", __FILE__, __LINE__); \ + xfprintf(gopt.err_fp, "%s:%d HEX[%zd] ", __FILE__, __LINE__, _len); \ while (_n < (_len)) xfprintf(gopt.err_fp, "%2.2x", ((unsigned char *)a)[_n++]); \ xfprintf(gopt.err_fp, "\n"); \ } while (0) diff --git a/tools/console.c b/tools/console.c index e55afd43..d1cbecfd 100644 --- a/tools/console.c +++ b/tools/console.c @@ -47,6 +47,13 @@ static const char *sb_color = "\x1B[44m\x1B[30m"; // Black on Blue #define GS_CONSOLE_BUF_SIZE (1024) #define GS_CONDIS_ROWS (GS_CONSOLE_ROWS - 2) +enum _gs_ut_cursor_flags { + GS_UT_CURSOR_ON = 0x01, + GS_UT_CURSOR_OFF = 0x02 +}; +enum _gs_ut_cursor_flags ut_cursor; + + struct _console_info { char statusbar[512]; @@ -141,15 +148,24 @@ tty_write(void *src, size_t len) static int is_cursor_in_console; static void -console_cursor_off(void) +cursor_to_ut(void) { - tty_write("\x1B""8", 2); // Move cursor to upper tier + char buf[64]; + char *end = buf + sizeof (buf); + char *ptr = buf; + + // If Upper Tier disabled the cursor then do NOT show it. + if (ut_cursor == GS_UT_CURSOR_OFF) + SXPRINTF(ptr, end - ptr, "\x1B[?25l"); + + SXPRINTF(ptr, end - ptr, "\x1B""8"); + tty_write(buf, ptr - buf); is_cursor_in_console = 0; } static void -console_cursor_on(void) +cursor_to_lt(void) { char buf[64]; char *end = buf + sizeof (buf); @@ -158,15 +174,20 @@ console_cursor_on(void) int row = gopt.winsize.ws_row; int col = 1 + GS_CONSOLE_PROMPT_LEN + MIN(rl.pos, rl.visible_len); - DEBUGF_W("Console Cursor ON (%d:%df)\n", row, col); - // ESC[?2004l = Reset bracketed paste mode + // DEBUGF_W("Cursor to CONSOLE (Lower Tier) (%d:%df)\n", row, col); SXPRINTF(ptr, end - ptr, "\x1B[%d;%df", row, col); + // ESC[?2004l = Reset bracketed paste mode if (is_console_cursor_needs_reset) { SXPRINTF(ptr, end - ptr, "\x1B[?2004l"); is_console_cursor_needs_reset = 0; } + // If Upper Tier disabled the cursor then show it in console + // DEBUGF_R("ut-cursor = %d\n", ut_cursor); + if (ut_cursor == GS_UT_CURSOR_OFF) + SXPRINTF(ptr, end - ptr, "\x1B[?25h"); + tty_write(buf, ptr - buf); is_cursor_in_console = 1; @@ -551,9 +572,7 @@ CONSOLE_check_esc(uint8_t c, uint8_t *submit) if (gopt.is_console == 0) return 0; // Ignore if no console - console_cursor_off(); - // console_stop(); - // gopt.is_console = 0; + cursor_to_ut(); return 0; case 'B': // DOWN if (esc == 0) @@ -561,7 +580,7 @@ CONSOLE_check_esc(uint8_t c, uint8_t *submit) if (gopt.is_console == 0) return 0; // Ignore if no console // Arrow Down - console_cursor_on(); + cursor_to_lt(); return 0; case GS_CONSOLE_ESC_CHR: case GS_CONSOLE_ESC_LCHR: @@ -685,19 +704,19 @@ ansi_until_end(uint8_t *src, size_t src_sz, int *ignore) if ((*src >= 'a') && (*src <= 'z')) { src++; - break; + return src - src_orig; } if ((*src >= 'A') && (*src <= 'Z')) { src++; - break; + return src - src_orig; } src++; } - return src - src_orig; + return 0; // Not enough data // src - src_orig; } static size_t @@ -722,7 +741,6 @@ ansi_until_esc(uint8_t *src, size_t src_sz, int *in_esc) static int in_esc; - // Parse 'src' for an ansi sequence that we might be interested in. // *tail_len contains a number of bytes if there is an incomplete ansi-sequence (and we // do not have enough data yet) @@ -735,6 +753,7 @@ ansi_parse(uint8_t *src, size_t src_sz, GS_BUF *dst, size_t *tail_len, int *cls_ size_t len; int ignore; + *tail_len = 0; while (src < src_end) { if (in_esc) @@ -744,12 +763,26 @@ ansi_parse(uint8_t *src, size_t src_sz, GS_BUF *dst, size_t *tail_len, int *cls_ if (len == 0) { // Not enough data + DEBUGF_R("Not Enough Data. TAIL %zd\n", src_end - src); + DEBUGF("esc len=%zd, ignore=%d, dst=%zd, left=%zd\n", len, ignore, GS_BUF_USED(dst), src_end - src); + HEXDUMP(src, src_end - src); *tail_len = src_end - src; - break; + return; //break; } in_esc = 0; - DEBUGF_B("ANSI %.*s\n", (int)len -1, src+1); +#ifdef DEBUG + // Output some ANSI but ignore some often re-occuring codes: + while (1) + { + if (len <= 4) + break; // Ignore short ones...like [1m + if ((len == 8) && (src[7] == 'm')) + break; // Ingore [39;49m to debug 'top' + DEBUGF_B("ANSI %.*s\n", (int)len -1, src+1); + break; + } +#endif if (ignore) { GS_BUF_add_data(dst, src, len); @@ -757,7 +790,43 @@ ansi_parse(uint8_t *src, size_t src_sz, GS_BUF *dst, size_t *tail_len, int *cls_ continue; } - // If console is not open then we do not have to check or substitute any ansi sequences + // Check if the Upper Tier (ut) wants the cursor prompt ON or OFF + // Check for this even if the console is closed so that when we open the console + // that the right cursor can be displayed + int is_substitute = 0; + while (len == 6) + { + if (memcmp(src + 1, "[?25l", 5) == 0) + ut_cursor = GS_UT_CURSOR_OFF; // OFF + else if (memcmp(src + 1, "[?25h", 5) == 0) + ut_cursor = GS_UT_CURSOR_ON; // ON + else + break; + + // DEBUGF_R("ut_cursor=%d, in-console=%d\n", ut_cursor, is_cursor_in_console); + // If cursor is in console then ignore all requests + if (is_cursor_in_console) + { + is_substitute = 1; + src += len; + break; + } + break; + } + if (is_substitute) + continue; + + // Check for Bracketed paste mode [?2004l + if (len == 8) + { + if (memcmp(src + 1, "[?2004l", 7) == 0) + is_console_cursor_needs_reset = 0; + else if (memcmp(src + 1, "[?2004h", 7) == 0) + is_console_cursor_needs_reset = 1; + } + + + // If console is not open then we do not have to check any other ansi symboles if (gopt.is_console == 0) { GS_BUF_add_data(dst, src, len); @@ -768,7 +837,7 @@ ansi_parse(uint8_t *src, size_t src_sz, GS_BUF *dst, size_t *tail_len, int *cls_ // Check if this was a cursor-position request that moved the course // outside its boundary (and into our console, like debian's top does (!)) // '\x1b' + '[1;1h' - int is_substitute = 0; + is_substitute = 0; while (1) { if (len < 6) @@ -828,168 +897,6 @@ ansi_parse(uint8_t *src, size_t src_sz, GS_BUF *dst, size_t *tail_len, int *cls_ } } -#if 0 - -static size_t -ansi_parse(uint8_t *src, size_t src_sz, uint8_t *dst, size_t dst_sz, size_t *amount, int *cls_code) -{ - static int in_esc; - static int in_esc_pos; - static int is_semicolon; - uint8_t *src_orig = src; - uint8_t *src_end = src + src_sz; - uint8_t *src_last = src; - uint8_t *dst_orig = dst; - uint8_t *dst_end = dst + dst_sz; - int rv = 0; - - while (src < src_end) - { - if (*src == '\x1B') - { - if (in_esc) - { - // Encountered a \x1b while inside an escape? Oops. - DEBUGF_R("SHOULD NOT HAPPEN\n"); - cls_pos = 0; - in_esc = 0; - goto skip; - } - in_esc = 1; - src_esc = src; - *amount = src - src_orig; - in_esc_pos = 0; - /* Start of pattern */ - cls_pos = 0; - - size_t len = src - src_last; - if (len > 1) - { - // Found an ESC-sequence. Copy all data until now into dst. - XASSERT(dst + len < dst_end, "Buffer to small!\n"); - memcpy(dst, src_last, len); - dst += len; - src_last = src; - } - - } else { - if (in_esc == 0) - goto skip; // ESC not yet encountered - } - - // Check when escape finishes - while (in_esc != 0) - { - if (*src == '\x1B') - break; - in_esc_pos++; - - if (in_esc_pos == 1) - { - // Check if multi character esc sequence - if (*src == '[') - break; - if (*src == '(') - break; - if (*src == ')') - break; - if (*src == '#') - break; // Esc-#2 - if (*src == '6') - break; // Esc-6n - if (*src == '5') - break; - if (*src == '0') - break; - if (*src == '3') - break; - } - - if (in_esc_pos >= 2) - { - if ((*src >= '0') && (*src <= '9')) - break; - if (*src == ';') - { - is_semicolon = 1; - break; - } - if (*src == '?') - break; - } - - // *src is last character of escape sequence - in_esc = 0; - break; - } - - - - // None of our sequences is longer than this. - if (cls_pos >= sizeof cls_buf) - goto skip; - - /* Record sequence */ - cls_buf[cls_pos] = *src; - cls_pos++; - - // Any sequence we are interested in is at least 2 chars long - if (cls_pos < 2) - goto skip; - - // Check if app tried to move out of screen area (into console) and drop - // such commands (like debian's TOP sends [26;1H] on exit even if scrolling area is - // is 25;80) - DEBUGF("is-semi = %d %c\n", is_semicolon, *src); - if ((in_esc == 0) && (cls_pos > 4) && (is_semicolon)) - { - is_semicolon = 0; - - if ((*src == 'H') || (*src == 'h')) - { - cls_buf[7] = '\0'; - DEBUGF("'%s'\n", (char *)(cls_buf + 1)); - char *ptr = strchr((char *)cls_buf, ';'); - if (ptr != NULL) - { - *ptr = '\0'; - int row = atoi((char *)(cls_buf + 2)); // skipe \x1b[ - DEBUGF("WANTS ROW %d %d\n", row, gopt.winsize.ws_row - GS_CONSOLE_ROWS); - if (row > gopt.winsize.ws_row - GS_CONSOLE_ROWS) - { - DEBUGF_R("DENIED\n"); - cls_pos = 0; - in_esc = 0; - goto skip; - } - } - } - - } - - //Check if any ESC sequence matches - int i; - for (i = 0; i < sizeof cls_pattern / sizeof *cls_pattern; i++) - { - if (cls_pattern[i].len != cls_pos) - continue; - if (memcmp(cls_pattern[i].data, cls_buf, cls_pos) != 0) - continue; - rv = cls_pattern[i].type; - cls_pos = 0; - } -skip: - src++; - } - // Not stuck inside esc sequence. - if (in_esc == 0) - *amount = len; - - *cls_code = rv; - - return dst - dst_orig; -} -#endif GS_BUF g_dst; GS_BUF g_ansi; @@ -1028,29 +935,34 @@ ansi_write(int fd, void *src, size_t src_len, int *cls_code) GS_BUF_init(&g_ansi, 1024); } - // HEXDUMP(src, src_len); if (GS_BUF_USED(&g_ansi) > 0) { GS_BUF_add_data(&g_ansi, src, src_len); src = GS_BUF_DATA(&g_ansi); src_len = GS_BUF_USED(&g_ansi); } + + // HEXDUMP(src, src_len); ansi_parse(src, src_len, &g_dst, &tail_len, cls_code); if (GS_BUF_USED(&g_dst) > 0) { if (write(fd, GS_BUF_DATA(&g_dst), GS_BUF_USED(&g_dst)) != GS_BUF_USED(&g_dst)) + { + DEBUGF_R("Failed to write() all data...\n"); // SHOULD NOT HAPPEN return -1; + } } GS_BUF_empty(&g_dst); + GS_BUF_empty(&g_ansi); if (tail_len > 0) { - GS_BUF_empty(&g_ansi); - GS_BUF_add_data(&g_ansi, src + src_len - tail_len, tail_len); - DEBUGF_W("TAIL length %zd\n", GS_BUF_USED(&g_ansi)); + // Use memmove() here because src might be pointing to same data but further along + GS_BUF_memmove(&g_ansi, src + src_len - tail_len, tail_len); } + // From the caller's perspective this function has processed all data // and this function will buffer (if needed) any data not yet passed // to 'write()'. Thus return 'len' here to satisfy caller that all supplied @@ -1087,7 +999,12 @@ CONSOLE_write(int fd, void *data, size_t len) /* Move cursor to upper tier if cursor inside console */ if (is_cursor_in_console) - tty_write("\x1B""8", 2); // Restore cursor to upper tier + { + if (ut_cursor == GS_UT_CURSOR_OFF) + tty_write("\x1B[?25l\x1B""8", 6+2); // Restore cursor to upper tier + else + tty_write("\x1B""8", 2); // Restore cursor to upper tier + } ssize_t sz; sz = ansi_write(fd, data, len, &is_detected_clearscreen); @@ -1096,8 +1013,8 @@ CONSOLE_write(int fd, void *data, size_t len) // The write() to upper tier may have set some funky paste modes // and we need to reset this for console input. - if (sz > 0) - is_console_cursor_needs_reset = 1; + // if (sz > 0) + // is_console_cursor_needs_reset = 1; // if (len > 16) // HEXDUMP(data, MIN(16, len)); @@ -1144,8 +1061,7 @@ CONSOLE_write(int fd, void *data, size_t len) if (is_cursor_in_console) { - DEBUGF("is_cursor_in_console is true\n"); - console_cursor_on(); + cursor_to_lt(); } return sz; @@ -1230,8 +1146,11 @@ console_start(void) SXPRINTF(ptr, end - ptr, "\x1b[1;%dr", row); // Restore cursor to saved location SXPRINTF(ptr, end - ptr, "\x1B""8"); - tty_write(buf, ptr - buf); + + gopt.is_console = 1; + + cursor_to_lt(); // Start with cursor in console } /* @@ -1249,10 +1168,15 @@ console_stop(void) SXPRINTF(ptr, end - ptr, "\x1B[J"); // Reset scroll size SXPRINTF(ptr, end - ptr, "\x1B[r"); + // Upper Tier wants cursor OFF + if (ut_cursor == GS_UT_CURSOR_OFF) + SXPRINTF(ptr, end - ptr, "\x1B[?25l"); // Restore cursor to upper tier (shell) SXPRINTF(ptr, end - ptr, "\x1B""8"); + tty_write(buf, ptr - buf); is_cursor_in_console = 0; + gopt.is_console = 0; } /* @@ -1298,12 +1222,10 @@ CONSOLE_action(struct _peer *p, uint8_t key) { // Close console and restore cursor console_stop(); - gopt.is_console = 0; return 0; } console_start(); - gopt.is_console = 1; GS_condis_pos(&gs_condis, (gopt.winsize.ws_row - GS_CONSOLE_ROWS) + 1 + 1, gopt.winsize.ws_col); if (is_console_welcome_msg == 0) @@ -1315,7 +1237,6 @@ CONSOLE_action(struct _peer *p, uint8_t key) GS_condis_add(&gs_condis, 0, "Type 'help' for a list of commands."); is_console_welcome_msg = 1; } - console_cursor_on(); // Start with cursor in console // Draw console needed? Resizing remote will trigger a CLEAR (=> re-draw) mk_statusbar(); console_draw(p->fd_out, 1); diff --git a/tools/filetransfer-test.c b/tools/filetransfer-test.c index 4ad3e443..c9bd374e 100644 --- a/tools/filetransfer-test.c +++ b/tools/filetransfer-test.c @@ -241,7 +241,7 @@ mk_packet(void) // DEBUGF("Packet type=%u length %zu + %zu\n", hdr->type, sizeof *hdr, sz); XASSERT(sz + sizeof *hdr <= GS_BUF_UNUSED(&gsb), "Oops, GS_FT_packet() to long. sz=%zu, unusued=%zu.\n", sz, GS_BUF_UNUSED(&gsb)); - GS_BUF_add(&gsb, sizeof *hdr + sz); + GS_BUF_add_length(&gsb, sizeof *hdr + sz); return 0; } diff --git a/tools/filetransfer.c b/tools/filetransfer.c index 676b748e..3bb63fa6 100644 --- a/tools/filetransfer.c +++ b/tools/filetransfer.c @@ -698,7 +698,7 @@ GS_FT_list_add_files(GS_FT *ft, uint32_t globbing_id, const char *pattern, size_ if (cwd_fd >= 0) { // Change back to original CWD. - fchdir(cwd_fd); + if (fchdir(cwd_fd) == 0) {} // ignore results close(cwd_fd); } XFREE(ptr); diff --git a/tools/filetransfer_mgr.c b/tools/filetransfer_mgr.c index 142be185..675b2633 100644 --- a/tools/filetransfer_mgr.c +++ b/tools/filetransfer_mgr.c @@ -233,7 +233,7 @@ GS_FTM_mk_packet(GS_FT *ft, uint8_t *dst, size_t dlen) // DEBUGF_G("TYPE NONE\n"); return 0; case GS_FT_TYPE_DONE: - DEBUGF_W("GS_FT_TYPE_DONE\n"); + // DEBUGF_W("GS_FT_TYPE_DONE\n"); // CLIENT only: done with all files. // FIXME: for a 'get' request this is triggered very late and not as soon // as the filetransfer is done (because select() only waits for reading