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.
 
 
 
 
 
 

198 lines
5.4 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. struct tcl_connection {
  26. int tc_linedrop;
  27. int tc_lineoffset;
  28. char tc_line[TCL_MAX_LINE];
  29. int tc_outerror; /* flag an output error */
  30. };
  31. static unsigned short tcl_port = 6666;
  32. /* handlers */
  33. static int tcl_new_connection(struct connection *connection);
  34. static int tcl_input(struct connection *connection);
  35. static int tcl_output(struct connection *connection, const void *buf, ssize_t len);
  36. static int tcl_closed(struct connection *connection);
  37. /* write data out to a socket.
  38. *
  39. * this is a blocking write, so the return value must equal the length, if
  40. * that is not the case then flag the connection with an output error.
  41. */
  42. int tcl_output(struct connection *connection, const void *data, ssize_t len)
  43. {
  44. ssize_t wlen;
  45. struct tcl_connection *tclc;
  46. tclc = connection->priv;
  47. if (tclc->tc_outerror)
  48. return ERROR_SERVER_REMOTE_CLOSED;
  49. wlen = write_socket(connection->fd, data, len);
  50. if (wlen == len)
  51. return ERROR_OK;
  52. LOG_ERROR("error during write: %d != %d", (int)wlen, (int)len);
  53. tclc->tc_outerror = 1;
  54. return ERROR_SERVER_REMOTE_CLOSED;
  55. }
  56. /* connections */
  57. static int tcl_new_connection(struct connection *connection)
  58. {
  59. struct tcl_connection *tclc;
  60. tclc = malloc(sizeof(struct tcl_connection));
  61. if (tclc == NULL)
  62. return ERROR_CONNECTION_REJECTED;
  63. memset(tclc, 0, sizeof(struct tcl_connection));
  64. connection->priv = tclc;
  65. return ERROR_OK;
  66. }
  67. static int tcl_input(struct connection *connection)
  68. {
  69. Jim_Interp *interp = (Jim_Interp *)connection->priv;
  70. int retval;
  71. int i;
  72. ssize_t rlen;
  73. const char *result;
  74. int reslen;
  75. struct tcl_connection *tclc;
  76. unsigned char in[256];
  77. rlen = read_socket(connection->fd, &in, sizeof(in));
  78. if (rlen <= 0) {
  79. if (rlen < 0)
  80. LOG_ERROR("error during read: %s", strerror(errno));
  81. return ERROR_SERVER_REMOTE_CLOSED;
  82. }
  83. tclc = connection->priv;
  84. if (tclc == NULL)
  85. return ERROR_CONNECTION_REJECTED;
  86. /* push as much data into the line as possible */
  87. for (i = 0; i < rlen; i++)
  88. {
  89. if (!isprint(in[i]) && !isspace(in[i]))
  90. {
  91. /* drop this line */
  92. tclc->tc_linedrop = 1;
  93. continue;
  94. }
  95. /* buffer the data */
  96. tclc->tc_line[tclc->tc_lineoffset] = in[i];
  97. if (tclc->tc_lineoffset < TCL_MAX_LINE)
  98. tclc->tc_lineoffset++;
  99. else
  100. tclc->tc_linedrop = 1;
  101. if (in[i] != '\n')
  102. continue;
  103. /* process the line */
  104. if (tclc->tc_linedrop) {
  105. #define ESTR "line too long\n"
  106. retval = tcl_output(connection, ESTR, sizeof(ESTR));
  107. if (retval != ERROR_OK)
  108. return retval;
  109. #undef ESTR
  110. }
  111. else {
  112. tclc->tc_line[tclc->tc_lineoffset-1] = '\0';
  113. retval = Jim_Eval_Named(interp, tclc->tc_line, "remote:connection",1);
  114. result = Jim_GetString(Jim_GetResult(interp), &reslen);
  115. retval = tcl_output(connection, result, reslen);
  116. if (retval != ERROR_OK)
  117. return retval;
  118. if (memchr(result, '\n', reslen) == NULL)
  119. tcl_output(connection, "\n", 1);
  120. }
  121. tclc->tc_lineoffset = 0;
  122. tclc->tc_linedrop = 0;
  123. }
  124. return ERROR_OK;
  125. }
  126. static int tcl_closed(struct connection *connection)
  127. {
  128. /* cleanup connection context */
  129. if (connection->priv) {
  130. free(connection->priv);
  131. connection->priv = NULL;
  132. }
  133. return ERROR_OK;
  134. }
  135. int tcl_init(struct command_context *cmd_ctx)
  136. {
  137. int retval;
  138. if (tcl_port == 0)
  139. {
  140. LOG_INFO("tcl port disabled");
  141. return ERROR_OK;
  142. }
  143. retval = add_service("tcl", CONNECTION_TCP, tcl_port, 1,
  144. &tcl_new_connection, &tcl_input,
  145. &tcl_closed, cmd_ctx->interp);
  146. return retval;
  147. }
  148. COMMAND_HANDLER(handle_tcl_port_command)
  149. {
  150. return CALL_COMMAND_HANDLER(server_port_command, &tcl_port);
  151. }
  152. static const struct command_registration tcl_command_handlers[] = {
  153. {
  154. .name = "tcl_port",
  155. .handler = handle_tcl_port_command,
  156. .mode = COMMAND_CONFIG,
  157. .help = "Specify port on which to listen "
  158. "for incoming Tcl syntax. "
  159. "No arguments reports Tcl port; zero disables.",
  160. .usage = "[port_num]",
  161. },
  162. COMMAND_REGISTRATION_DONE
  163. };
  164. int tcl_register_commands(struct command_context *cmd_ctx)
  165. {
  166. return register_commands(cmd_ctx, NULL, tcl_command_handlers);
  167. }