1 /***************************************************************************
2 * Copyright (C) 2010 Øyvind Harboe *
3 * oyvind.harboe@zylin.com *
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. *
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. *
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 ***************************************************************************/
25 #include "tcl_server.h"
27 #define TCL_SERVER_VERSION "TCL Server 0.1"
28 #define TCL_MAX_LINE (4096)
30 struct tcl_connection
{
33 char tc_line
[TCL_MAX_LINE
];
34 int tc_outerror
;/* flag an output error */
37 static char *tcl_port
;
40 static int tcl_new_connection(struct connection
*connection
);
41 static int tcl_input(struct connection
*connection
);
42 static int tcl_output(struct connection
*connection
, const void *buf
, ssize_t len
);
43 static int tcl_closed(struct connection
*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(struct connection
*connection
, const void *data
, ssize_t len
)
53 struct tcl_connection
*tclc
;
55 tclc
= connection
->priv
;
56 if (tclc
->tc_outerror
)
57 return ERROR_SERVER_REMOTE_CLOSED
;
59 wlen
= connection_write(connection
, data
, len
);
64 LOG_ERROR("error during write: %d != %d", (int)wlen
, (int)len
);
65 tclc
->tc_outerror
= 1;
66 return ERROR_SERVER_REMOTE_CLOSED
;
70 static int tcl_new_connection(struct connection
*connection
)
72 struct tcl_connection
*tclc
;
74 tclc
= malloc(sizeof(struct tcl_connection
));
76 return ERROR_CONNECTION_REJECTED
;
78 memset(tclc
, 0, sizeof(struct tcl_connection
));
79 connection
->priv
= tclc
;
83 static int tcl_input(struct connection
*connection
)
85 Jim_Interp
*interp
= (Jim_Interp
*)connection
->cmd_ctx
->interp
;
91 struct tcl_connection
*tclc
;
92 unsigned char in
[256];
94 rlen
= connection_read(connection
, &in
, sizeof(in
));
97 LOG_ERROR("error during read: %s", strerror(errno
));
98 return ERROR_SERVER_REMOTE_CLOSED
;
101 tclc
= connection
->priv
;
103 return ERROR_CONNECTION_REJECTED
;
105 /* push as much data into the line as possible */
106 for (i
= 0; i
< rlen
; i
++) {
107 /* buffer the data */
108 tclc
->tc_line
[tclc
->tc_lineoffset
] = in
[i
];
109 if (tclc
->tc_lineoffset
< TCL_MAX_LINE
)
110 tclc
->tc_lineoffset
++;
112 tclc
->tc_linedrop
= 1;
114 /* ctrl-z is end of command. When testing from telnet, just
115 * press ctrl-z a couple of times first to put telnet into the
116 * mode where it will send 0x1a in response to pressing ctrl-z
121 /* process the line */
122 if (tclc
->tc_linedrop
) {
123 #define ESTR "line too long\n"
124 retval
= tcl_output(connection
, ESTR
, sizeof(ESTR
));
125 if (retval
!= ERROR_OK
)
129 tclc
->tc_line
[tclc
->tc_lineoffset
-1] = '\0';
130 LOG_DEBUG("Executing script:\n %s", tclc
->tc_line
);
131 retval
= Jim_Eval_Named(interp
, tclc
->tc_line
, "remote:connection", 1);
132 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
133 LOG_DEBUG("Result: %d\n %s", retval
, result
);
134 retval
= tcl_output(connection
, result
, reslen
);
135 if (retval
!= ERROR_OK
)
137 /* Always output ctrl-d as end of line to allow multiline results */
138 tcl_output(connection
, "\x1a", 1);
141 tclc
->tc_lineoffset
= 0;
142 tclc
->tc_linedrop
= 0;
148 static int tcl_closed(struct connection
*connection
)
150 /* cleanup connection context */
151 if (connection
->priv
) {
152 free(connection
->priv
);
153 connection
->priv
= NULL
;
160 if (strcmp(tcl_port
, "disabled") == 0) {
161 LOG_INFO("tcl server disabled");
165 return add_service("tcl", tcl_port
, 1,
166 &tcl_new_connection
, &tcl_input
,
170 COMMAND_HANDLER(handle_tcl_port_command
)
172 return CALL_COMMAND_HANDLER(server_pipe_command
, &tcl_port
);
175 static const struct command_registration tcl_command_handlers
[] = {
178 .handler
= handle_tcl_port_command
,
180 .help
= "Specify port on which to listen "
181 "for incoming Tcl syntax. "
182 "Read help on 'gdb_port'.",
183 .usage
= "[port_num]",
185 COMMAND_REGISTRATION_DONE
188 int tcl_register_commands(struct command_context
*cmd_ctx
)
190 tcl_port
= strdup("6666");
191 return register_commands(cmd_ctx
, NULL
, tcl_command_handlers
);