* fixed malloc corruption in target->debug_reason
[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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "replacements.h"
25
26 #include "server.h"
27
28 #include "log.h"
29 #include "telnet_server.h"
30 #include "target.h"
31
32 #include <command.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <fcntl.h>
39 #include <signal.h>
40
41 service_t *services = NULL;
42
43 /* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
44 static int shutdown_openocd = 0;
45 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
46
47 int add_connection(service_t *service, command_context_t *cmd_ctx)
48 {
49 unsigned int address_size;
50 connection_t *c, **p;
51 int retval;
52
53 c = malloc(sizeof(connection_t));
54 c->fd = -1;
55 memset(&c->sin, 0, sizeof(c->sin));
56 c->cmd_ctx = copy_command_context(cmd_ctx);
57 c->service = service;
58 c->input_pending = 0;
59 c->priv = NULL;
60 c->next = NULL;
61
62 address_size = sizeof(c->sin);
63 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
64
65 if ((retval = service->new_connection(c)) == ERROR_OK)
66 {
67 INFO("accepted '%s' connection from %i", service->name, c->sin.sin_port);
68 }
69 else
70 {
71 close_socket(c->fd);
72 INFO("attempted '%s' connection rejected", service->name);
73 free(c);
74 return retval;
75 }
76
77 /* add to the end of linked list */
78 for (p = &service->connections; *p; p = &(*p)->next);
79 *p = c;
80
81 service->max_connections--;
82
83 return ERROR_OK;
84 }
85
86 int remove_connection(service_t *service, connection_t *connection)
87 {
88 connection_t **p = &service->connections;
89 connection_t *c;
90
91 /* find connection */
92 while((c = *p))
93 {
94 if (c->fd == connection->fd)
95 {
96 service->connection_closed(c);
97 close_socket(c->fd);
98 command_done(c->cmd_ctx);
99
100 /* delete connection */
101 *p = c->next;
102 free(c);
103
104 service->max_connections++;
105 break;
106 }
107
108 /* redirect p to next list pointer */
109 p = &(*p)->next;
110 }
111
112 return ERROR_OK;
113 }
114
115 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)
116 {
117 service_t *c, **p;
118 int so_reuseaddr_option = 1;
119
120 c = malloc(sizeof(service_t));
121
122 c->name = strdup(name);
123 c->type = type;
124 c->port = port;
125 c->max_connections = max_connections;
126 c->fd = -1;
127 c->connections = NULL;
128 c->new_connection = new_connection_handler;
129 c->input = input_handler;
130 c->connection_closed = connection_closed_handler;
131 c->priv = priv;
132 c->next = NULL;
133
134 if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
135 {
136 ERROR("error creating socket: %s", strerror(errno));
137 exit(-1);
138 }
139
140 setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
141
142 socket_nonblock(c->fd);
143
144 memset(&c->sin, 0, sizeof(c->sin));
145 c->sin.sin_family = AF_INET;
146 c->sin.sin_addr.s_addr = INADDR_ANY;
147 c->sin.sin_port = htons(port);
148
149 if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
150 {
151 ERROR("couldn't bind to socket: %s", strerror(errno));
152 exit(-1);
153 }
154
155 if (listen(c->fd, 1) == -1)
156 {
157 ERROR("couldn't listen on socket: %s", strerror(errno));
158 exit(-1);
159 }
160
161 /* add to the end of linked list */
162 for (p = &services; *p; p = &(*p)->next);
163 *p = c;
164
165 return ERROR_OK;
166 }
167
168 int remove_service(unsigned short port)
169 {
170 service_t **p = &services;
171 service_t *c;
172
173 /* find service */
174 while((c = *p))
175 {
176 if (c->port == port)
177 {
178 if (c->name)
179 free(c->name);
180
181 if (c->priv)
182 free(c->priv);
183
184 /* delete service */
185 *p = c->next;
186 free(c);
187 }
188
189 /* redirect p to next list pointer */
190 p = &(*p)->next;
191 }
192
193 return ERROR_OK;
194 }
195
196 int remove_services()
197 {
198 service_t *c = services;
199
200 /* loop service */
201 while(c)
202 {
203 service_t *next = c->next;
204
205 if (c->name)
206 free(c->name);
207
208 if (c->priv)
209 free(c->priv);
210
211 /* delete service */
212 free(c);
213
214 /* remember the last service for unlinking */
215 c = next;
216 }
217
218 services = NULL;
219
220 return ERROR_OK;
221 }
222
223 int server_loop(command_context_t *command_context)
224 {
225 service_t *service;
226
227 /* used in select() */
228 fd_set read_fds;
229 struct timeval tv;
230 int fd_max;
231
232 /* used in accept() */
233 int retval;
234
235 #ifndef _WIN32
236 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
237 ERROR("couldn't set SIGPIPE to SIG_IGN");
238 #endif
239
240 /* do regular tasks after at most 10ms */
241 tv.tv_sec = 0;
242 tv.tv_usec = 10000;
243
244 while(!shutdown_openocd)
245 {
246 /* monitor sockets for acitvity */
247 fd_max = 0;
248 FD_ZERO(&read_fds);
249
250 /* add service and connection fds to read_fds */
251 for (service = services; service; service = service->next)
252 {
253 if (service->fd != -1)
254 {
255 /* listen for new connections */
256 FD_SET(service->fd, &read_fds);
257
258 if (service->fd > fd_max)
259 fd_max = service->fd;
260 }
261
262 if (service->connections)
263 {
264 connection_t *c;
265
266 for (c = service->connections; c; c = c->next)
267 {
268 /* check for activity on the connection */
269 FD_SET(c->fd, &read_fds);
270 if (c->fd > fd_max)
271 fd_max = c->fd;
272 }
273 }
274 }
275
276 #ifndef _WIN32
277 /* add STDIN to read_fds */
278 FD_SET(fileno(stdin), &read_fds);
279 #endif
280
281 retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv);
282
283 if (retval == -1)
284 {
285 #ifdef _WIN32
286
287 errno = WSAGetLastError();
288
289 if (errno == WSAEINTR)
290 FD_ZERO(&read_fds);
291 else
292 {
293 ERROR("error during select: %s", strerror(errno));
294 exit(-1);
295 }
296 #else
297
298 if (errno == EINTR)
299 {
300 FD_ZERO(&read_fds);
301 }
302 else
303 {
304 ERROR("error during select: %s", strerror(errno));
305 exit(-1);
306 }
307 #endif
308 }
309
310 target_call_timer_callbacks();
311
312 if (retval == 0)
313 {
314 /* do regular tasks after at most 100ms */
315 tv.tv_sec = 0;
316 tv.tv_usec = 10000;
317 FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
318 }
319
320 for (service = services; service; service = service->next)
321 {
322 /* handle new connections on listeners */
323 if ((service->fd != -1)
324 && (FD_ISSET(service->fd, &read_fds)))
325 {
326 if (service->max_connections > 0)
327 {
328 add_connection(service, command_context);
329 }
330 else
331 {
332 struct sockaddr_in sin;
333 unsigned int address_size = sizeof(sin);
334 int tmp_fd;
335 tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
336 close_socket(tmp_fd);
337 INFO("rejected '%s' connection, no more connections allowed", service->name);
338 }
339 }
340
341 /* handle activity on connections */
342 if (service->connections)
343 {
344 connection_t *c;
345
346 for (c = service->connections; c;)
347 {
348 if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
349 {
350 if (service->input(c) != ERROR_OK)
351 {
352 connection_t *next = c->next;
353 remove_connection(service, c);
354 INFO("dropped '%s' connection", service->name);
355 c = next;
356 continue;
357 }
358 }
359 c = c->next;
360 }
361 }
362 }
363
364 #ifndef _WIN32
365 if (FD_ISSET(fileno(stdin), &read_fds))
366 {
367 if (getc(stdin) == 'x')
368 {
369 shutdown_openocd = 1;
370 }
371 }
372 #else
373 MSG msg;
374 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
375 {
376 if (msg.message == WM_QUIT)
377 shutdown_openocd = 1;
378 }
379 #endif
380 }
381
382 return ERROR_OK;
383 }
384
385 #ifdef _WIN32
386 BOOL WINAPI ControlHandler(DWORD dwCtrlType)
387 {
388 shutdown_openocd = 1;
389 return TRUE;
390 }
391
392 void sig_handler(int sig) {
393 shutdown_openocd = 1;
394 }
395 #endif
396
397 int server_init()
398 {
399 #ifdef _WIN32
400 WORD wVersionRequested;
401 WSADATA wsaData;
402
403 wVersionRequested = MAKEWORD( 2, 2 );
404
405 if (WSAStartup(wVersionRequested, &wsaData) != 0)
406 {
407 ERROR("Failed to Open Winsock");
408 exit(-1);
409 }
410
411 SetConsoleCtrlHandler( ControlHandler, TRUE );
412
413 signal(SIGINT, sig_handler);
414 signal(SIGTERM, sig_handler);
415 signal(SIGBREAK, sig_handler);
416 signal(SIGABRT, sig_handler);
417 #endif
418
419
420 return ERROR_OK;
421 }
422
423 int server_quit()
424 {
425 remove_services();
426
427 #ifdef _WIN32
428 WSACleanup();
429 SetConsoleCtrlHandler( ControlHandler, FALSE );
430 #endif
431
432 return ERROR_OK;
433 }
434
435 int server_register_commands(command_context_t *context)
436 {
437 register_command(context, NULL, "shutdown", handle_shutdown_command,
438 COMMAND_ANY, "shut the server down");
439
440 return ERROR_OK;
441 }
442
443 /* tell the server we want to shut down */
444 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
445 {
446 shutdown_openocd = 1;
447
448 return ERROR_COMMAND_CLOSE_CONNECTION;
449 }
450
451

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)