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.
 
 
 
 
 
 

189 lines
5.2 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2008 *
  3. * *
  4. * This program is free software; you can redistribute it and/or modify *
  5. * it under the terms of the GNU General Public License as published by *
  6. * the Free Software Foundation; either version 2 of the License, or *
  7. * (at your option) any later version. *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "tcl_server.h"
  23. #define TCL_SERVER_VERSION "TCL Server 0.1"
  24. #define TCL_MAX_LINE (4096)
  25. typedef struct tcl_connection_s {
  26. int tc_linedrop;
  27. int tc_lineoffset;
  28. char tc_line[TCL_MAX_LINE];
  29. int tc_outerror; /* flag an output error */
  30. } tcl_connection_t;
  31. static unsigned short tcl_port = 6666;
  32. /* commands */
  33. static int handle_tcl_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
  34. /* handlers */
  35. static int tcl_new_connection(connection_t *connection);
  36. static int tcl_input(connection_t *connection);
  37. static int tcl_output(connection_t *connection, const void *buf, ssize_t len);
  38. static int tcl_closed(connection_t *connection);
  39. /* write data out to a socket.
  40. *
  41. * this is a blocking write, so the return value must equal the length, if
  42. * that is not the case then flag the connection with an output error.
  43. */
  44. int tcl_output(connection_t *connection, const void *data, ssize_t len)
  45. {
  46. ssize_t wlen;
  47. tcl_connection_t *tclc;
  48. tclc = connection->priv;
  49. if (tclc->tc_outerror)
  50. return ERROR_SERVER_REMOTE_CLOSED;
  51. wlen = write_socket(connection->fd, data, len);
  52. if (wlen == len)
  53. return ERROR_OK;
  54. LOG_ERROR("error during write: %d != %d", (int)wlen, (int)len);
  55. tclc->tc_outerror = 1;
  56. return ERROR_SERVER_REMOTE_CLOSED;
  57. }
  58. /* connections */
  59. static int tcl_new_connection(connection_t *connection)
  60. {
  61. tcl_connection_t *tclc;
  62. tclc = malloc(sizeof(tcl_connection_t));
  63. if (tclc == NULL)
  64. return ERROR_CONNECTION_REJECTED;
  65. memset(tclc, 0, sizeof(tcl_connection_t));
  66. connection->priv = tclc;
  67. return ERROR_OK;
  68. }
  69. static int tcl_input(connection_t *connection)
  70. {
  71. int retval;
  72. int i;
  73. ssize_t rlen;
  74. const char *result;
  75. int reslen;
  76. tcl_connection_t *tclc;
  77. char in[256];
  78. rlen = read_socket(connection->fd, &in, sizeof(in));
  79. if (rlen <= 0) {
  80. if (rlen < 0)
  81. LOG_ERROR("error during read: %s", strerror(errno));
  82. return ERROR_SERVER_REMOTE_CLOSED;
  83. }
  84. tclc = connection->priv;
  85. if (tclc == NULL)
  86. return ERROR_CONNECTION_REJECTED;
  87. /* push as much data into the line as possible */
  88. for (i = 0; i < rlen; i++)
  89. {
  90. if (!isprint(in[i]) && !isspace(in[i]))
  91. {
  92. /* drop this line */
  93. tclc->tc_linedrop = 1;
  94. continue;
  95. }
  96. /* buffer the data */
  97. tclc->tc_line[tclc->tc_lineoffset] = in[i];
  98. if (tclc->tc_lineoffset < TCL_MAX_LINE)
  99. tclc->tc_lineoffset++;
  100. else
  101. tclc->tc_linedrop = 1;
  102. if (in[i] != '\n')
  103. continue;
  104. /* process the line */
  105. if (tclc->tc_linedrop) {
  106. #define ESTR "line too long\n"
  107. retval = tcl_output(connection, ESTR, sizeof(ESTR));
  108. if (retval != ERROR_OK)
  109. return retval;
  110. #undef ESTR
  111. }
  112. else {
  113. tclc->tc_line[tclc->tc_lineoffset-1] = '\0';
  114. retval = Jim_Eval_Named(interp, tclc->tc_line, "remote:connection",1);
  115. result = Jim_GetString(Jim_GetResult(interp), &reslen);
  116. retval = tcl_output(connection, result, reslen);
  117. if (retval != ERROR_OK)
  118. return retval;
  119. if (memchr(result, '\n', reslen) == NULL)
  120. tcl_output(connection, "\n", 1);
  121. }
  122. tclc->tc_lineoffset = 0;
  123. tclc->tc_linedrop = 0;
  124. }
  125. return ERROR_OK;
  126. }
  127. static int tcl_closed(connection_t *connection)
  128. {
  129. /* cleanup connection context */
  130. if (connection->priv) {
  131. free(connection->priv);
  132. connection->priv = NULL;
  133. }
  134. return ERROR_OK;
  135. }
  136. int tcl_init(void)
  137. {
  138. int retval;
  139. if (tcl_port == 0)
  140. {
  141. LOG_INFO("tcl port disabled");
  142. return ERROR_OK;
  143. }
  144. retval = add_service("tcl", CONNECTION_TCP, tcl_port, 1, tcl_new_connection, tcl_input, tcl_closed, NULL);
  145. return retval;
  146. }
  147. int tcl_register_commands(command_context_t *cmd_ctx)
  148. {
  149. register_command(cmd_ctx, NULL, "tcl_port", handle_tcl_port_command, COMMAND_CONFIG, "port on which to listen for incoming TCL syntax");
  150. return ERROR_OK;
  151. }
  152. static int handle_tcl_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
  153. {
  154. if (argc == 1) {
  155. tcl_port = strtoul(args[0], NULL, 0);
  156. }
  157. return ERROR_OK;
  158. }