X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fserver%2Ftcl_server.c;h=789eee8b6f35f645a7157d39a4601e9bf7b86716;hp=a4270a8445667445a448730e8d627ad455342d29;hb=4b0477abc196d1488628131c18de742c092ad289;hpb=8bffcc0cd4fd6a92c8f9bbb28ccc14e4b51a576a diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index a4270a8445..789eee8b6f 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -27,12 +27,14 @@ #include #define TCL_SERVER_VERSION "TCL Server 0.1" -#define TCL_MAX_LINE (4096) +#define TCL_LINE_INITIAL (4*1024) +#define TCL_LINE_MAX (4*1024*1024) struct tcl_connection { int tc_linedrop; int tc_lineoffset; - char tc_line[TCL_MAX_LINE]; + int tc_line_size; + char *tc_line; int tc_outerror;/* flag an output error */ enum target_state tc_laststate; bool tc_notify; @@ -144,11 +146,17 @@ static int tcl_new_connection(struct connection *connection) { struct tcl_connection *tclc; - tclc = malloc(sizeof(struct tcl_connection)); + tclc = calloc(1, sizeof(struct tcl_connection)); if (tclc == NULL) return ERROR_CONNECTION_REJECTED; - memset(tclc, 0, sizeof(struct tcl_connection)); + tclc->tc_line_size = TCL_LINE_INITIAL; + tclc->tc_line = malloc(tclc->tc_line_size); + if (tclc->tc_line == NULL) { + free(tclc); + return ERROR_CONNECTION_REJECTED; + } + connection->priv = tclc; struct target *target = get_target_by_num(connection->cmd_ctx->current_target); @@ -175,6 +183,8 @@ static int tcl_input(struct connection *connection) int reslen; struct tcl_connection *tclc; unsigned char in[256]; + char *tc_line_new; + int tc_line_size_new; rlen = connection_read(connection, &in, sizeof(in)); if (rlen <= 0) { @@ -191,10 +201,31 @@ static int tcl_input(struct connection *connection) for (i = 0; i < rlen; i++) { /* buffer the data */ tclc->tc_line[tclc->tc_lineoffset] = in[i]; - if (tclc->tc_lineoffset < TCL_MAX_LINE) + if (tclc->tc_lineoffset < tclc->tc_line_size) { tclc->tc_lineoffset++; - else + } else if (tclc->tc_line_size >= TCL_LINE_MAX) { + /* maximum line size reached, drop line */ tclc->tc_linedrop = 1; + } else { + /* grow line buffer: exponential below 1 MB, linear above */ + if (tclc->tc_line_size <= 1*1024*1024) + tc_line_size_new = tclc->tc_line_size * 2; + else + tc_line_size_new = tclc->tc_line_size + 1*1024*1024; + + if (tc_line_size_new > TCL_LINE_MAX) + tc_line_size_new = TCL_LINE_MAX; + + tc_line_new = realloc(tclc->tc_line, tc_line_size_new); + if (tc_line_new == NULL) { + tclc->tc_linedrop = 1; + } else { + tclc->tc_line = tc_line_new; + tclc->tc_line_size = tc_line_size_new; + tclc->tc_lineoffset++; + } + + } /* ctrl-z is end of command. When testing from telnet, just * press ctrl-z a couple of times first to put telnet into the @@ -230,9 +261,13 @@ static int tcl_input(struct connection *connection) static int tcl_closed(struct connection *connection) { + struct tcl_connection *tclc; + tclc = connection->priv; + /* cleanup connection context */ - if (connection->priv) { - free(connection->priv); + if (tclc) { + free(tclc->tc_line); + free(tclc); connection->priv = NULL; }