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
read_callback(unsigned int channel,const uint8_t * buffer,size_t length,void * user_data)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
rtt_new_connection(struct connection * connection)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
rtt_connection_closed(struct connection * connection)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
rtt_input(struct connection * connection)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
COMMAND_HANDLER(handle_rtt_start_command)113 COMMAND_HANDLER(handle_rtt_start_command)
114 {
115 int ret;
116 struct rtt_service *service;
117
118 if (CMD_ARGC != 2)
119 return ERROR_COMMAND_SYNTAX_ERROR;
120
121 service = malloc(sizeof(struct rtt_service));
122
123 if (!service)
124 return ERROR_FAIL;
125
126 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel);
127
128 ret = add_service("rtt", CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED,
129 rtt_new_connection, rtt_input, rtt_connection_closed, service, NULL);
130
131 if (ret != ERROR_OK) {
132 free(service);
133 return ERROR_FAIL;
134 }
135
136 return ERROR_OK;
137 }
138
COMMAND_HANDLER(handle_rtt_stop_command)139 COMMAND_HANDLER(handle_rtt_stop_command)
140 {
141 if (CMD_ARGC != 1)
142 return ERROR_COMMAND_SYNTAX_ERROR;
143
144 remove_service("rtt", CMD_ARGV[0]);
145
146 return ERROR_OK;
147 }
148
149 static const struct command_registration rtt_server_subcommand_handlers[] = {
150 {
151 .name = "start",
152 .handler = handle_rtt_start_command,
153 .mode = COMMAND_ANY,
154 .help = "Start a RTT server",
155 .usage = "<port> <channel>"
156 },
157 {
158 .name = "stop",
159 .handler = handle_rtt_stop_command,
160 .mode = COMMAND_ANY,
161 .help = "Stop a RTT server",
162 .usage = "<port>"
163 },
164 COMMAND_REGISTRATION_DONE
165 };
166
167 static const struct command_registration rtt_server_command_handlers[] = {
168 {
169 .name = "server",
170 .mode = COMMAND_ANY,
171 .help = "RTT server",
172 .usage = "",
173 .chain = rtt_server_subcommand_handlers
174 },
175 COMMAND_REGISTRATION_DONE
176 };
177
178 static const struct command_registration rtt_command_handlers[] = {
179 {
180 .name = "rtt",
181 .mode = COMMAND_ANY,
182 .help = "RTT",
183 .usage = "",
184 .chain = rtt_server_command_handlers
185 },
186 COMMAND_REGISTRATION_DONE
187 };
188
rtt_server_register_commands(struct command_context * ctx)189 int rtt_server_register_commands(struct command_context *ctx)
190 {
191 return register_commands(ctx, NULL, rtt_command_handlers);
192 }
193