1 /***************************************************************************
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. *
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. *
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 ***************************************************************************/
24 #include "tcl_server.h"
27 #define TCL_SERVER_VERSION "TCL Server 0.1"
28 #define TCL_MAX_LINE (4096)
30 typedef struct tcl_connection_s
{
33 char tc_line
[TCL_MAX_LINE
];
34 int tc_outerror
; /* flag an output error */
37 static unsigned short tcl_port
= 6666;
40 static int tcl_new_connection(connection_t
*connection
);
41 static int tcl_input(connection_t
*connection
);
42 static int tcl_output(connection_t
*connection
, const void *buf
, ssize_t len
);
43 static int tcl_closed(connection_t
*connection
);
45 /* write data out to a socket.
47 * this is a blocking write, so the return value must equal the length, if
48 * that is not the case then flag the connection with an output error.
50 int tcl_output(connection_t
*connection
, const void *data
, ssize_t len
)
53 tcl_connection_t
*tclc
;
55 tclc
= connection
->priv
;
56 if (tclc
->tc_outerror
)
57 return ERROR_SERVER_REMOTE_CLOSED
;
59 wlen
= write_socket(connection
->fd
, data
, len
);
63 LOG_ERROR("error during write: %d != %d", (int)wlen
, (int)len
);
64 tclc
->tc_outerror
= 1;
65 return ERROR_SERVER_REMOTE_CLOSED
;
69 static int tcl_new_connection(connection_t
*connection
)
71 tcl_connection_t
*tclc
;
73 tclc
= malloc(sizeof(tcl_connection_t
));
75 return ERROR_CONNECTION_REJECTED
;
77 memset(tclc
, 0, sizeof(tcl_connection_t
));
78 connection
->priv
= tclc
;
82 static int tcl_input(connection_t
*connection
)
89 tcl_connection_t
*tclc
;
92 rlen
= read_socket(connection
->fd
, &in
, sizeof(in
));
95 LOG_ERROR("error during read: %s", strerror(errno
));
96 return ERROR_SERVER_REMOTE_CLOSED
;
99 tclc
= connection
->priv
;
101 return ERROR_CONNECTION_REJECTED
;
103 /* push as much data into the line as possible */
104 for (i
= 0; i
< rlen
; i
++)
106 if (!isprint(in
[i
]) && !isspace(in
[i
]))
109 tclc
->tc_linedrop
= 1;
113 /* buffer the data */
114 tclc
->tc_line
[tclc
->tc_lineoffset
] = in
[i
];
115 if (tclc
->tc_lineoffset
< TCL_MAX_LINE
)
116 tclc
->tc_lineoffset
++;
118 tclc
->tc_linedrop
= 1;
123 /* process the line */
124 if (tclc
->tc_linedrop
) {
125 #define ESTR "line too long\n"
126 retval
= tcl_output(connection
, ESTR
, sizeof(ESTR
));
127 if (retval
!= ERROR_OK
)
132 tclc
->tc_line
[tclc
->tc_lineoffset
-1] = '\0';
133 retval
= Jim_Eval_Named(interp
, tclc
->tc_line
, "remote:connection",1);
134 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
135 retval
= tcl_output(connection
, result
, reslen
);
136 if (retval
!= ERROR_OK
)
138 if (memchr(result
, '\n', reslen
) == NULL
)
139 tcl_output(connection
, "\n", 1);
142 tclc
->tc_lineoffset
= 0;
143 tclc
->tc_linedrop
= 0;
149 static int tcl_closed(connection_t
*connection
)
151 /* cleanup connection context */
152 if (connection
->priv
) {
153 free(connection
->priv
);
154 connection
->priv
= NULL
;
165 LOG_INFO("tcl port disabled");
169 retval
= add_service("tcl", CONNECTION_TCP
, tcl_port
, 1, tcl_new_connection
, tcl_input
, tcl_closed
, NULL
);
173 static int handle_tcl_port_command(struct command_context_s
*cmd_ctx
,
174 char *cmd
, char **args
, int argc
)
176 return server_port_command(cmd_ctx
, cmd
, args
, argc
, &tcl_port
);
179 int tcl_register_commands(command_context_t
*cmd_ctx
)
181 register_command(cmd_ctx
, NULL
, "tcl_port",
182 handle_tcl_port_command
, COMMAND_CONFIG
,
183 "port on which to listen for incoming TCL syntax");