server: read/write now goes through connection fn's
[fw/openocd] / src / server / tcl_server.c
index b5bdbc28935f2fb74b5da7632ed8e2783eaa9865..7d84de7320ba735465f6f094eec2732b2353d8bd 100644 (file)
@@ -1,5 +1,6 @@
 /***************************************************************************
- *   Copyright (C) 2008                                                    *
+ *   Copyright (C) 2010 Ã˜yvind Harboe                                      *
+ *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
@@ -37,17 +38,17 @@ struct tcl_connection {
 static unsigned short tcl_port = 6666;
 
 /* handlers */
-static int tcl_new_connection(connection_t *connection);
-static int tcl_input(connection_t *connection);
-static int tcl_output(connection_t *connection, const void *buf, ssize_t len);
-static int tcl_closed(connection_t *connection);
+static int tcl_new_connection(struct connection *connection);
+static int tcl_input(struct connection *connection);
+static int tcl_output(struct connection *connection, const void *buf, ssize_t len);
+static int tcl_closed(struct connection *connection);
 
 /* write data out to a socket.
  *
  * this is a blocking write, so the return value must equal the length, if
  * that is not the case then flag the connection with an output error.
  */
-int tcl_output(connection_t *connection, const void *data, ssize_t len)
+int tcl_output(struct connection *connection, const void *data, ssize_t len)
 {
        ssize_t wlen;
        struct tcl_connection *tclc;
@@ -56,7 +57,8 @@ int tcl_output(connection_t *connection, const void *data, ssize_t len)
        if (tclc->tc_outerror)
                return ERROR_SERVER_REMOTE_CLOSED;
 
-       wlen = write_socket(connection->fd, data, len);
+       wlen = connection_write(connection, data, len);
+
        if (wlen == len)
                return ERROR_OK;
 
@@ -66,7 +68,7 @@ int tcl_output(connection_t *connection, const void *data, ssize_t len)
 }
 
 /* connections */
-static int tcl_new_connection(connection_t *connection)
+static int tcl_new_connection(struct connection *connection)
 {
        struct tcl_connection *tclc;
 
@@ -79,17 +81,18 @@ static int tcl_new_connection(connection_t *connection)
        return ERROR_OK;
 }
 
-static int tcl_input(connection_t *connection)
+static int tcl_input(struct connection *connection)
 {
+       Jim_Interp *interp = (Jim_Interp *)connection->cmd_ctx->interp;
        int retval;
        int i;
        ssize_t rlen;
        const char *result;
        int reslen;
        struct tcl_connection *tclc;
-       char in[256];
+       unsigned char in[256];
 
-       rlen = read_socket(connection->fd, &in, sizeof(in));
+       rlen = connection_read(connection, &in, sizeof(in));
        if (rlen <= 0) {
                if (rlen < 0)
                        LOG_ERROR("error during read: %s", strerror(errno));
@@ -103,13 +106,6 @@ static int tcl_input(connection_t *connection)
        /* push as much data into the line as possible */
        for (i = 0; i < rlen; i++)
        {
-               if (!isprint(in[i]) && !isspace(in[i]))
-               {
-                       /* drop this line */
-                       tclc->tc_linedrop = 1;
-                       continue;
-               }
-
                /* buffer the data */
                tclc->tc_line[tclc->tc_lineoffset] = in[i];
                if (tclc->tc_lineoffset < TCL_MAX_LINE)
@@ -117,7 +113,11 @@ static int tcl_input(connection_t *connection)
                else
                        tclc->tc_linedrop = 1;
 
-               if (in[i] != '\n')
+               /* ctrl-z is end of command. When testing from telnet, just
+                * press ctrl-z a couple of times first to put telnet into the
+                * mode where it will send 0x1a in response to pressing ctrl-z
+                */
+               if (in[i] != '\x1a')
                        continue;
 
                /* process the line */
@@ -130,13 +130,15 @@ static int tcl_input(connection_t *connection)
                }
                else {
                        tclc->tc_line[tclc->tc_lineoffset-1] = '\0';
+                       LOG_DEBUG("Executing script:\n %s", tclc->tc_line);
                        retval = Jim_Eval_Named(interp, tclc->tc_line, "remote:connection",1);
+                       LOG_DEBUG("Result: %d\n %s", retval, Jim_GetString(Jim_GetResult(interp), &reslen));
                        result = Jim_GetString(Jim_GetResult(interp), &reslen);
                        retval = tcl_output(connection, result, reslen);
                        if (retval != ERROR_OK)
                                return retval;
-                       if (memchr(result, '\n', reslen) == NULL)
-                               tcl_output(connection, "\n", 1);
+                       /* Always output ctrl-d as end of line to allow multiline results */
+                       tcl_output(connection, "\x1a", 1);
                }
 
                tclc->tc_lineoffset = 0;
@@ -146,7 +148,7 @@ static int tcl_input(connection_t *connection)
        return ERROR_OK;
 }
 
-static int tcl_closed(connection_t *connection)
+static int tcl_closed(struct connection *connection)
 {
        /* cleanup connection context */
        if (connection->priv) {
@@ -166,7 +168,9 @@ int tcl_init(void)
                return ERROR_OK;
        }
 
-       retval = add_service("tcl", CONNECTION_TCP, tcl_port, 1, tcl_new_connection, tcl_input, tcl_closed, NULL);
+       retval = add_service("tcl", CONNECTION_TCP, tcl_port, 1,
+                       &tcl_new_connection, &tcl_input,
+                       &tcl_closed, NULL);
        return retval;
 }
 
@@ -175,10 +179,20 @@ COMMAND_HANDLER(handle_tcl_port_command)
        return CALL_COMMAND_HANDLER(server_port_command, &tcl_port);
 }
 
-int tcl_register_commands(command_context_t *cmd_ctx)
+static const struct command_registration tcl_command_handlers[] = {
+       {
+               .name = "tcl_port",
+               .handler = handle_tcl_port_command,
+               .mode = COMMAND_CONFIG,
+               .help = "Specify port on which to listen "
+                       "for incoming Tcl syntax.  "
+                       "No arguments reports Tcl port; zero disables.",
+               .usage = "[port_num]",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+int tcl_register_commands(struct command_context *cmd_ctx)
 {
-       register_command(cmd_ctx, NULL, "tcl_port",
-                       handle_tcl_port_command, COMMAND_CONFIG,
-                       "port on which to listen for incoming TCL syntax");
-       return ERROR_OK;
+       return register_commands(cmd_ctx, NULL, tcl_command_handlers);
 }