]> git.gag.com Git - fw/openocd/blob - src/server/rtt_server.c
smp: deprecate legacy SMP core switching support
[fw/openocd] / src / server / rtt_server.c
1 /*
2  * Copyright (C) 2016-2017 by Marc Schink <dev@zapb.de>
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, see <http://www.gnu.org/licenses/>.
16  */
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <stdint.h>
23 #include <rtt/rtt.h>
24
25 #include "server.h"
26 #include "rtt_server.h"
27
28 /**
29  * @file
30  *
31  * RTT server.
32  *
33  * This server allows access to Real Time Transfer (RTT) channels via TCP
34  * connections.
35  */
36
37 struct rtt_service {
38         unsigned int channel;
39 };
40
41 static int read_callback(unsigned int channel, const uint8_t *buffer,
42                 size_t length, void *user_data)
43 {
44         int ret;
45         struct connection *connection;
46         size_t offset;
47
48         connection = (struct connection *)user_data;
49         offset = 0;
50
51         while (offset < length) {
52                 ret = connection_write(connection, buffer + offset, length - offset);
53
54                 if (ret < 0) {
55                         LOG_ERROR("Failed to write data to socket.");
56                         return ERROR_FAIL;
57                 }
58
59                 offset += ret;
60         }
61
62         return ERROR_OK;
63 }
64
65 static int rtt_new_connection(struct connection *connection)
66 {
67         int ret;
68         struct rtt_service *service;
69
70         service = connection->service->priv;
71
72         LOG_DEBUG("rtt: New connection for channel %u", service->channel);
73
74         ret = rtt_register_sink(service->channel, &read_callback, connection);
75
76         if (ret != ERROR_OK)
77                 return ret;
78
79         return ERROR_OK;
80 }
81
82 static int rtt_connection_closed(struct connection *connection)
83 {
84         struct rtt_service *service;
85
86         service = (struct rtt_service *)connection->service->priv;
87         rtt_unregister_sink(service->channel, &read_callback, connection);
88
89         LOG_DEBUG("rtt: Connection for channel %u closed", service->channel);
90
91         return ERROR_OK;
92 }
93
94 static int rtt_input(struct connection *connection)
95 {
96         int bytes_read;
97         unsigned char buffer[1024];
98         struct rtt_service *service;
99         size_t length;
100
101         service = (struct rtt_service *)connection->service->priv;
102         bytes_read = connection_read(connection, buffer, sizeof(buffer));
103
104         if (!bytes_read)
105                 return ERROR_SERVER_REMOTE_CLOSED;
106         else if (bytes_read < 0) {
107                 LOG_ERROR("error during read: %s", strerror(errno));
108                 return ERROR_SERVER_REMOTE_CLOSED;
109         }
110
111         length = bytes_read;
112         rtt_write_channel(service->channel, buffer, &length);
113
114         return ERROR_OK;
115 }
116
117 static const struct service_driver rtt_service_driver = {
118         .name = "rtt",
119         .new_connection_during_keep_alive_handler = NULL,
120         .new_connection_handler = rtt_new_connection,
121         .input_handler = rtt_input,
122         .connection_closed_handler = rtt_connection_closed,
123         .keep_client_alive_handler = NULL,
124 };
125
126 COMMAND_HANDLER(handle_rtt_start_command)
127 {
128         int ret;
129         struct rtt_service *service;
130
131         if (CMD_ARGC != 2)
132                 return ERROR_COMMAND_SYNTAX_ERROR;
133
134         service = malloc(sizeof(struct rtt_service));
135
136         if (!service)
137                 return ERROR_FAIL;
138
139         COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel);
140
141         ret = add_service(&rtt_service_driver, CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED, service);
142
143         if (ret != ERROR_OK) {
144                 free(service);
145                 return ERROR_FAIL;
146         }
147
148         return ERROR_OK;
149 }
150
151 COMMAND_HANDLER(handle_rtt_stop_command)
152 {
153         if (CMD_ARGC != 1)
154                 return ERROR_COMMAND_SYNTAX_ERROR;
155
156         remove_service("rtt", CMD_ARGV[0]);
157
158         return ERROR_OK;
159 }
160
161 static const struct command_registration rtt_server_subcommand_handlers[] = {
162         {
163                 .name = "start",
164                 .handler = handle_rtt_start_command,
165                 .mode = COMMAND_ANY,
166                 .help = "Start a RTT server",
167                 .usage = "<port> <channel>"
168         },
169         {
170                 .name = "stop",
171                 .handler = handle_rtt_stop_command,
172                 .mode = COMMAND_ANY,
173                 .help = "Stop a RTT server",
174                 .usage = "<port>"
175         },
176         COMMAND_REGISTRATION_DONE
177 };
178
179 static const struct command_registration rtt_server_command_handlers[] = {
180         {
181                 .name = "server",
182                 .mode = COMMAND_ANY,
183                 .help = "RTT server",
184                 .usage = "",
185                 .chain = rtt_server_subcommand_handlers
186         },
187         COMMAND_REGISTRATION_DONE
188 };
189
190 static const struct command_registration rtt_command_handlers[] = {
191         {
192                 .name = "rtt",
193                 .mode = COMMAND_ANY,
194                 .help = "RTT",
195                 .usage = "",
196                 .chain = rtt_server_command_handlers
197         },
198         COMMAND_REGISTRATION_DONE
199 };
200
201 int rtt_server_register_commands(struct command_context *ctx)
202 {
203         return register_commands(ctx, NULL, rtt_command_handlers);
204 }