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