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