- fixed bug in Thumb sw breakpoint handling (thanks to Spen for this patch)
[openocd.git] / src / server / server.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #include "server.h"
21
22 #include "log.h"
23 #include "telnet_server.h"
24 #include "target.h"
25
26 #include <command.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <fcntl.h>
34 #include <signal.h>
35
36 service_t *services = NULL;
37
38 /* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
39 static int shutdown_openocd = 0;
40 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
41
42 int add_connection(service_t *service, command_context_t *cmd_ctx)
43 {
44 unsigned int address_size;
45 connection_t *c, *p;
46 int retval;
47
48 c = malloc(sizeof(connection_t));
49 c->fd = -1;
50 memset(&c->sin, 0, sizeof(c->sin));
51 c->cmd_ctx = copy_command_context(cmd_ctx);
52 c->service = service;
53 c->input_pending = 0;
54 c->priv = NULL;
55 c->next = NULL;
56
57 address_size = sizeof(c->sin);
58 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
59
60 if ((retval = service->new_connection(c)) == ERROR_OK)
61 {
62 INFO("accepted '%s' connection from %i", service->name, c->sin.sin_port);
63 }
64 else
65 {
66 close(c->fd);
67 INFO("attempted '%s' connection rejected", service->name);
68 free(c);
69 }
70
71 if (service->connections)
72 {
73 for (p = service->connections; p && p->next; p = p->next);
74 if (p)
75 p->next = c;
76 }
77 else
78 {
79 service->connections = c;
80 }
81
82 service->max_connections--;
83
84 return ERROR_OK;
85 }
86
87 int remove_connection(service_t *service, connection_t *connection)
88 {
89 connection_t *c = service->connections;
90
91 /* find connection */
92 while(c)
93 {
94 connection_t *next = c->next;
95
96 if (c->fd == connection->fd)
97 {
98 service->connections = next;
99 service->connection_closed(c);
100 close(c->fd);
101
102 command_done(c->cmd_ctx);
103
104 /* delete connection */
105 free(c);
106
107 service->max_connections++;
108 break;
109 }
110
111 /* remember the last connection for unlinking */
112 c = next;
113 }
114
115 return ERROR_OK;
116 }
117
118 int add_service(char *name, enum connection_type type, unsigned short port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t input_handler, connection_closed_handler_t connection_closed_handler, void *priv)
119 {
120 service_t *c, *p;
121 int so_reuseaddr_option = 1;
122 int oldopts;
123
124 c = malloc(sizeof(service_t));
125
126 c->name = strdup(name);
127 c->type = type;
128 c->port = port;
129 c->max_connections = max_connections;
130 c->fd = -1;
131 c->connections = NULL;
132 c->new_connection = new_connection_handler;
133 c->input = input_handler;
134 c->connection_closed = connection_closed_handler;
135 c->priv = priv;
136 c->next = NULL;
137
138 if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
139 {
140 ERROR("error creating socket: %s", strerror(errno));
141 exit(-1);
142 }
143
144 setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr_option, sizeof(int));
145
146 oldopts = fcntl(c->fd, F_GETFL, 0);
147 fcntl(c->fd, F_SETFL, oldopts | O_NONBLOCK);
148
149 memset(&c->sin, 0, sizeof(c->sin));
150 c->sin.sin_family = AF_INET;
151 c->sin.sin_addr.s_addr = INADDR_ANY;
152 c->sin.sin_port = htons(port);
153
154 if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
155 {
156 ERROR("couldn't bind to socket: %s", strerror(errno));
157 exit(-1);
158 }
159
160 if (listen(c->fd, 1) == -1)
161 {
162 ERROR("couldn't listen on socket: %s", strerror(errno));
163 exit(-1);
164 }
165
166 if (services)
167 {
168 for (p = services; p && p->next; p = p->next);
169 if (p)
170 p->next = c;
171 }
172 else
173 {
174 services = c;
175 }
176
177 return ERROR_OK;
178 }
179
180 int remove_service(unsigned short port)
181 {
182 service_t *c = services;
183
184 /* find service */
185 while(c)
186 {
187 service_t *next = c->next;
188
189 if (c->port == port)
190 {
191 if (c->name)
192 free(c->name);
193
194 if (c->priv)
195 free(c->priv);
196
197 /* delete service */
198 free(c);
199 }
200
201 /* remember the last service for unlinking */
202 c = next;
203 }
204
205 return ERROR_OK;
206 }
207
208 int server_loop(command_context_t *command_context)
209 {
210 service_t *service;
211
212 /* used in select() */
213 fd_set read_fds;
214 struct timeval tv;
215 int fd_max;
216
217 /* used in accept() */
218 int retval;
219
220 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
221 ERROR("couldn't set SIGPIPE to SIG_IGN");
222
223 /* do regular tasks after at most 10ms */
224 tv.tv_sec = 0;
225 tv.tv_usec = 10000;
226
227 while(!shutdown_openocd)
228 {
229 /* monitor sockets for acitvity */
230 fd_max = 0;
231 FD_ZERO(&read_fds);
232
233 /* add service and connection fds to read_fds */
234 for (service = services; service; service = service->next)
235 {
236 if (service->fd != -1)
237 {
238 /* listen for new connections */
239 FD_SET(service->fd, &read_fds);
240
241 if (service->fd > fd_max)
242 fd_max = service->fd;
243 }
244
245 if (service->connections)
246 {
247 connection_t *c;
248
249 for (c = service->connections; c; c = c->next)
250 {
251 /* check for activity on the connection */
252 FD_SET(c->fd, &read_fds);
253 if (c->fd > fd_max)
254 fd_max = c->fd;
255 }
256 }
257 }
258
259 /* add STDIN to read_fds */
260 FD_SET(fileno(stdin), &read_fds);
261
262 if ((retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv)) == -1)
263 {
264 if (errno == EINTR)
265 FD_ZERO(&read_fds);
266 else
267 {
268 ERROR("error during select: %s", strerror(errno));
269 exit(-1);
270 }
271 }
272
273 target_call_timer_callbacks();
274
275 if (retval == 0)
276 {
277 /* do regular tasks after at most 100ms */
278 tv.tv_sec = 0;
279 tv.tv_usec = 10000;
280
281 #if 0
282 if (shutdown_openocd)
283 return ERROR_COMMAND_CLOSE_CONNECTION;
284
285 handle_target();
286 #endif
287 }
288
289 for (service = services; service; service = service->next)
290 {
291 /* handle new connections on listeners */
292 if ((service->fd != -1)
293 && (FD_ISSET(service->fd, &read_fds)))
294 {
295 if (service->max_connections > 0)
296 add_connection(service, command_context);
297 else
298 {
299 struct sockaddr_in sin;
300 unsigned int address_size = sizeof(sin);
301 int tmp_fd;
302 tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
303 close(tmp_fd);
304 INFO("rejected '%s' connection, no more connections allowed", service->name);
305 }
306 }
307
308 /* handle activity on connections */
309 if (service->connections)
310 {
311 connection_t *c;
312
313 for (c = service->connections; c;)
314 {
315 if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
316 {
317 if (service->input(c) != ERROR_OK)
318 {
319 connection_t *next = c->next;
320 remove_connection(service, c);
321 INFO("dropped '%s' connection", service->name);
322 c = next;
323 continue;
324 }
325 }
326 c = c->next;
327 }
328 }
329 }
330
331 if (FD_ISSET(fileno(stdin), &read_fds))
332 {
333 if (getc(stdin) == 'x')
334 {
335 shutdown_openocd = 1;
336 }
337 }
338 }
339
340 return ERROR_OK;
341 }
342
343 int server_init()
344 {
345
346 return ERROR_OK;
347 }
348
349 int server_register_commands(command_context_t *context)
350 {
351 register_command(context, NULL, "shutdown", handle_shutdown_command,
352 COMMAND_ANY, "shut the server down");
353
354 return ERROR_OK;
355 }
356
357 /* tell the server we want to shut down */
358 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
359 {
360 shutdown_openocd = 1;
361
362 return ERROR_COMMAND_CLOSE_CONNECTION;
363 }
364

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)