]> git.sur5r.net Git - openocd/blob - src/server/tcl_server.c
Remove whitespace at end of lines, step 2.
[openocd] / src / server / tcl_server.c
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
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "tcl_server.h"
25
26
27 #define TCL_SERVER_VERSION      "TCL Server 0.1"
28 #define TCL_MAX_LINE            (4096)
29
30 typedef struct tcl_connection_s {
31         int tc_linedrop;
32         int tc_lineoffset;
33         char tc_line[TCL_MAX_LINE];
34         int tc_outerror; /* flag an output error */
35 } tcl_connection_t;
36
37 static unsigned short tcl_port = 6666;
38
39 /* commands */
40 static int handle_tcl_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
41
42 /* handlers */
43 static int tcl_new_connection(connection_t *connection);
44 static int tcl_input(connection_t *connection);
45 static int tcl_output(connection_t *connection, const void *buf, ssize_t len);
46 static int tcl_closed(connection_t *connection);
47
48 /* write data out to a socket.
49  *
50  * this is a blocking write, so the return value must equal the length, if
51  * that is not the case then flag the connection with an output error.
52  */
53 int tcl_output(connection_t *connection, const void *data, ssize_t len)
54 {
55         ssize_t wlen;
56         tcl_connection_t *tclc;
57
58         tclc = connection->priv;
59         if (tclc->tc_outerror)
60                 return ERROR_SERVER_REMOTE_CLOSED;
61
62         wlen = write_socket(connection->fd, data, len);
63         if (wlen == len)
64                 return ERROR_OK;
65
66         LOG_ERROR("error during write: %d != %d", (int)wlen, (int)len);
67         tclc->tc_outerror = 1;
68         return ERROR_SERVER_REMOTE_CLOSED;
69 }
70
71 /* connections */
72 static int tcl_new_connection(connection_t *connection)
73 {
74         tcl_connection_t *tclc;
75
76         tclc = malloc(sizeof(tcl_connection_t));
77         if (tclc == NULL)
78                 return ERROR_CONNECTION_REJECTED;
79
80         memset(tclc, 0, sizeof(tcl_connection_t));
81         connection->priv = tclc;
82         return ERROR_OK;
83 }
84
85 static int tcl_input(connection_t *connection)
86 {
87         int retval;
88         int i;
89         ssize_t rlen;
90         const char *result;
91         int reslen;
92         tcl_connection_t *tclc;
93         char in[256];
94
95         rlen = read_socket(connection->fd, &in, sizeof(in));
96         if (rlen <= 0) {
97                 if (rlen < 0)
98                         LOG_ERROR("error during read: %s", strerror(errno));
99                 return ERROR_SERVER_REMOTE_CLOSED;
100         }
101
102         tclc = connection->priv;
103         if (tclc == NULL)
104                 return ERROR_CONNECTION_REJECTED;
105
106         /* push as much data into the line as possible */
107         for (i = 0; i < rlen; i++)
108         {
109                 if (!isprint(in[i]) && !isspace(in[i]))
110                 {
111                         /* drop this line */
112                         tclc->tc_linedrop = 1;
113                         continue;
114                 }
115
116                 /* buffer the data */
117                 tclc->tc_line[tclc->tc_lineoffset] = in[i];
118                 if (tclc->tc_lineoffset < TCL_MAX_LINE)
119                         tclc->tc_lineoffset++;
120                 else
121                         tclc->tc_linedrop = 1;
122
123                 if (in[i] != '\n')
124                         continue;
125
126                 /* process the line */
127                 if (tclc->tc_linedrop) {
128 #define ESTR "line too long\n"
129                         retval = tcl_output(connection, ESTR, sizeof(ESTR));
130                         if (retval != ERROR_OK)
131                                 return retval;
132 #undef ESTR
133                 }
134                 else {
135                         tclc->tc_line[tclc->tc_lineoffset-1] = '\0';
136                         retval = Jim_Eval_Named(interp, tclc->tc_line, "remote:connection",1);
137                         result = Jim_GetString(Jim_GetResult(interp), &reslen);
138                         retval = tcl_output(connection, result, reslen);
139                         if (retval != ERROR_OK)
140                                 return retval;
141                         if (memchr(result, '\n', reslen) == NULL)
142                                 tcl_output(connection, "\n", 1);
143                 }
144
145                 tclc->tc_lineoffset = 0;
146                 tclc->tc_linedrop = 0;
147         }
148
149         return ERROR_OK;
150 }
151
152 static int tcl_closed(connection_t *connection)
153 {
154         /* cleanup connection context */
155         if (connection->priv) {
156                 free(connection->priv);
157                 connection->priv = NULL;
158         }
159         return ERROR_OK;
160 }
161
162 int tcl_init(void)
163 {
164         int retval;
165
166         if (tcl_port == 0)
167         {
168                 LOG_INFO("tcl port disabled");
169                 return ERROR_OK;
170         }
171
172         retval = add_service("tcl", CONNECTION_TCP, tcl_port, 1, tcl_new_connection, tcl_input, tcl_closed, NULL);
173         return retval;
174 }
175
176 int tcl_register_commands(command_context_t *cmd_ctx)
177 {
178         register_command(cmd_ctx, NULL, "tcl_port", handle_tcl_port_command, COMMAND_CONFIG, "port on which to listen for incoming TCL syntax");
179         return ERROR_OK;
180 }
181
182 static int handle_tcl_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
183 {
184         if (argc == 1) {
185                 tcl_port = strtoul(args[0], NULL, 0);
186         }
187         return ERROR_OK;
188 }