You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

275 lines
8.0 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2010 √ėyvind Harboe *
  3. * oyvind.harboe@zylin.com *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 2 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write to the *
  17. * Free Software Foundation, Inc., *
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
  19. ***************************************************************************/
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #include "tcl_server.h"
  24. #include <target/target.h>
  25. #define TCL_SERVER_VERSION "TCL Server 0.1"
  26. #define TCL_MAX_LINE (4096)
  27. struct tcl_connection {
  28. int tc_linedrop;
  29. int tc_lineoffset;
  30. char tc_line[TCL_MAX_LINE];
  31. int tc_outerror;/* flag an output error */
  32. enum target_state tc_laststate;
  33. bool tc_notify;
  34. };
  35. static char *tcl_port;
  36. /* handlers */
  37. static int tcl_new_connection(struct connection *connection);
  38. static int tcl_input(struct connection *connection);
  39. static int tcl_output(struct connection *connection, const void *buf, ssize_t len);
  40. static int tcl_closed(struct connection *connection);
  41. static int tcl_target_callback_event_handler(struct target *target,
  42. enum target_event event, void *priv)
  43. {
  44. struct connection *connection = priv;
  45. struct tcl_connection *tclc;
  46. char buf[256];
  47. tclc = connection->priv;
  48. if (tclc->tc_notify) {
  49. snprintf(buf, sizeof(buf), "type target_event event %s\r\n\x1a", target_event_name(event));
  50. tcl_output(connection, buf, strlen(buf));
  51. }
  52. if (tclc->tc_laststate != target->state) {
  53. tclc->tc_laststate = target->state;
  54. if (tclc->tc_notify) {
  55. snprintf(buf, sizeof(buf), "type target_state state %s\r\n\x1a", target_state_name(target));
  56. tcl_output(connection, buf, strlen(buf));
  57. }
  58. }
  59. return ERROR_OK;
  60. }
  61. static int tcl_target_callback_reset_handler(struct target *target,
  62. enum target_reset_mode reset_mode, void *priv)
  63. {
  64. struct connection *connection = priv;
  65. struct tcl_connection *tclc;
  66. char buf[256];
  67. tclc = connection->priv;
  68. if (tclc->tc_notify) {
  69. snprintf(buf, sizeof(buf), "type target_reset mode %s\r\n\x1a", target_reset_mode_name(reset_mode));
  70. tcl_output(connection, buf, strlen(buf));
  71. }
  72. return ERROR_OK;
  73. }
  74. /* write data out to a socket.
  75. *
  76. * this is a blocking write, so the return value must equal the length, if
  77. * that is not the case then flag the connection with an output error.
  78. */
  79. int tcl_output(struct connection *connection, const void *data, ssize_t len)
  80. {
  81. ssize_t wlen;
  82. struct tcl_connection *tclc;
  83. tclc = connection->priv;
  84. if (tclc->tc_outerror)
  85. return ERROR_SERVER_REMOTE_CLOSED;
  86. wlen = connection_write(connection, data, len);
  87. if (wlen == len)
  88. return ERROR_OK;
  89. LOG_ERROR("error during write: %d != %d", (int)wlen, (int)len);
  90. tclc->tc_outerror = 1;
  91. return ERROR_SERVER_REMOTE_CLOSED;
  92. }
  93. /* connections */
  94. static int tcl_new_connection(struct connection *connection)
  95. {
  96. struct tcl_connection *tclc;
  97. tclc = malloc(sizeof(struct tcl_connection));
  98. if (tclc == NULL)
  99. return ERROR_CONNECTION_REJECTED;
  100. memset(tclc, 0, sizeof(struct tcl_connection));
  101. connection->priv = tclc;
  102. struct target *target = get_target_by_num(connection->cmd_ctx->current_target);
  103. if (target != NULL)
  104. tclc->tc_laststate = target->state;
  105. /* store the connection object on cmd_ctx so we can access it from command handlers */
  106. connection->cmd_ctx->output_handler_priv = connection;
  107. target_register_event_callback(tcl_target_callback_event_handler, connection);
  108. target_register_reset_callback(tcl_target_callback_reset_handler, connection);
  109. return ERROR_OK;
  110. }
  111. static int tcl_input(struct connection *connection)
  112. {
  113. Jim_Interp *interp = (Jim_Interp *)connection->cmd_ctx->interp;
  114. int retval;
  115. int i;
  116. ssize_t rlen;
  117. const char *result;
  118. int reslen;
  119. struct tcl_connection *tclc;
  120. unsigned char in[256];
  121. rlen = connection_read(connection, &in, sizeof(in));
  122. if (rlen <= 0) {
  123. if (rlen < 0)
  124. LOG_ERROR("error during read: %s", strerror(errno));
  125. return ERROR_SERVER_REMOTE_CLOSED;
  126. }
  127. tclc = connection->priv;
  128. if (tclc == NULL)
  129. return ERROR_CONNECTION_REJECTED;
  130. /* push as much data into the line as possible */
  131. for (i = 0; i < rlen; i++) {
  132. /* buffer the data */
  133. tclc->tc_line[tclc->tc_lineoffset] = in[i];
  134. if (tclc->tc_lineoffset < TCL_MAX_LINE)
  135. tclc->tc_lineoffset++;
  136. else
  137. tclc->tc_linedrop = 1;
  138. /* ctrl-z is end of command. When testing from telnet, just
  139. * press ctrl-z a couple of times first to put telnet into the
  140. * mode where it will send 0x1a in response to pressing ctrl-z
  141. */
  142. if (in[i] != '\x1a')
  143. continue;
  144. /* process the line */
  145. if (tclc->tc_linedrop) {
  146. #define ESTR "line too long\n"
  147. retval = tcl_output(connection, ESTR, sizeof(ESTR));
  148. if (retval != ERROR_OK)
  149. return retval;
  150. #undef ESTR
  151. } else {
  152. tclc->tc_line[tclc->tc_lineoffset-1] = '\0';
  153. retval = command_run_line(connection->cmd_ctx, tclc->tc_line);
  154. result = Jim_GetString(Jim_GetResult(interp), &reslen);
  155. retval = tcl_output(connection, result, reslen);
  156. if (retval != ERROR_OK)
  157. return retval;
  158. /* Always output ctrl-d as end of line to allow multiline results */
  159. tcl_output(connection, "\x1a", 1);
  160. }
  161. tclc->tc_lineoffset = 0;
  162. tclc->tc_linedrop = 0;
  163. }
  164. return ERROR_OK;
  165. }
  166. static int tcl_closed(struct connection *connection)
  167. {
  168. /* cleanup connection context */
  169. if (connection->priv) {
  170. free(connection->priv);
  171. connection->priv = NULL;
  172. }
  173. target_unregister_event_callback(tcl_target_callback_event_handler, connection);
  174. target_unregister_reset_callback(tcl_target_callback_reset_handler, connection);
  175. return ERROR_OK;
  176. }
  177. int tcl_init(void)
  178. {
  179. if (strcmp(tcl_port, "disabled") == 0) {
  180. LOG_INFO("tcl server disabled");
  181. return ERROR_OK;
  182. }
  183. return add_service("tcl", tcl_port, 1,
  184. &tcl_new_connection, &tcl_input,
  185. &tcl_closed, NULL);
  186. }
  187. COMMAND_HANDLER(handle_tcl_port_command)
  188. {
  189. return CALL_COMMAND_HANDLER(server_pipe_command, &tcl_port);
  190. }
  191. COMMAND_HANDLER(handle_tcl_notifications_command)
  192. {
  193. struct connection *connection = NULL;
  194. struct tcl_connection *tclc = NULL;
  195. if (CMD_CTX->output_handler_priv != NULL)
  196. connection = CMD_CTX->output_handler_priv;
  197. if (connection != NULL && !strcmp(connection->service->name, "tcl")) {
  198. tclc = connection->priv;
  199. return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_notify, "Target Notification output is");
  200. } else {
  201. LOG_ERROR("%s: can only be called from the tcl server", CMD_NAME);
  202. return ERROR_COMMAND_SYNTAX_ERROR;
  203. }
  204. }
  205. static const struct command_registration tcl_command_handlers[] = {
  206. {
  207. .name = "tcl_port",
  208. .handler = handle_tcl_port_command,
  209. .mode = COMMAND_ANY,
  210. .help = "Specify port on which to listen "
  211. "for incoming Tcl syntax. "
  212. "Read help on 'gdb_port'.",
  213. .usage = "[port_num]",
  214. },
  215. {
  216. .name = "tcl_notifications",
  217. .handler = handle_tcl_notifications_command,
  218. .mode = COMMAND_EXEC,
  219. .help = "Target Notification output",
  220. .usage = "[on|off]",
  221. },
  222. COMMAND_REGISTRATION_DONE
  223. };
  224. int tcl_register_commands(struct command_context *cmd_ctx)
  225. {
  226. tcl_port = strdup("6666");
  227. return register_commands(cmd_ctx, NULL, tcl_command_handlers);
  228. }