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