lpc4350_spifi_generic: Clean up work area size
[fw/openocd] / src / server / tcl_server.c
index a4270a8445667445a448730e8d627ad455342d29..789eee8b6f35f645a7157d39a4601e9bf7b86716 100644 (file)
 #include <helper/binarybuffer.h>
 
 #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;
        }