]> git.sur5r.net Git - openocd/blobdiff - src/server/tcl_server.c
target: use correct target in target-prefixed commands and event handlers
[openocd] / src / server / tcl_server.c
index a4270a8445667445a448730e8d627ad455342d29..7c40f7dce9c49908e09b234183137288f6ebc2ae 100644 (file)
@@ -13,9 +13,7 @@
  *   GNU General Public License for more details.                          *
  *                                                                         *
  *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 #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;
@@ -105,7 +105,7 @@ static int tcl_target_callback_trace_handler(struct target *target,
        if (tclc->tc_trace) {
                hex = malloc(hex_len);
                buf = malloc(max_len);
-               hexify(hex, (const char *)data, len, hex_len);
+               hexify(hex, data, len, hex_len);
                snprintf(buf, max_len, "%s%s%s", header, hex, trailer);
                tcl_output(connection, buf, strlen(buf));
                free(hex);
@@ -144,14 +144,20 @@ 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);
+       struct target *target = get_current_target(connection->cmd_ctx);
        if (target != NULL)
                tclc->tc_laststate = target->state;
 
@@ -175,6 +181,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 +199,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 +259,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;
        }