server: add support for pipes
[openocd.git] / src / server / server.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2007-2010 Øyvind Harboe *
6 * oyvind.harboe@zylin.com *
7 * *
8 * Copyright (C) 2008 by Spencer Oliver *
9 * spen@spen-soft.co.uk *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25 ***************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "server.h"
31 #include <target/target.h>
32 #include "openocd.h"
33 #include "tcl_server.h"
34 #include "telnet_server.h"
35
36 #include <signal.h>
37
38 #ifndef _WIN32
39 #include <netinet/tcp.h>
40 #endif
41
42
43 static struct service *services = NULL;
44
45 /* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
46 static int shutdown_openocd = 0;
47
48 static int add_connection(struct service *service, struct command_context *cmd_ctx)
49 {
50 socklen_t address_size;
51 struct connection *c, **p;
52 int retval;
53 int flag = 1;
54
55 c = malloc(sizeof(struct connection));
56 c->fd = -1;
57 c->fd_out = -1;
58 memset(&c->sin, 0, sizeof(c->sin));
59 c->cmd_ctx = copy_command_context(cmd_ctx);
60 c->service = service;
61 c->input_pending = 0;
62 c->priv = NULL;
63 c->next = NULL;
64
65 if (service->type == CONNECTION_TCP)
66 {
67 address_size = sizeof(c->sin);
68
69 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
70 c->fd_out = c->fd;
71
72 /* This increases performance dramatically for e.g. GDB load which
73 * does not have a sliding window protocol. */
74 retval = setsockopt(c->fd, /* socket affected */
75 IPPROTO_TCP, /* set option at TCP level */
76 TCP_NODELAY, /* name of option */
77 (char *)&flag, /* the cast is historical cruft */
78 sizeof(int)); /* length of option value */
79
80 LOG_INFO("accepting '%s' connection from %s", service->name, service->port);
81 if ((retval = service->new_connection(c)) != ERROR_OK)
82 {
83 close_socket(c->fd);
84 LOG_ERROR("attempted '%s' connection rejected", service->name);
85 free(c);
86 return retval;
87 }
88 } else if (service->type == CONNECTION_STDINOUT)
89 {
90 c->fd = service->fd;
91 c->fd_out = fileno(stdout);
92
93 /* do not check for new connections again on stdin */
94 service->fd = -1;
95
96 LOG_INFO("accepting '%s' connection from pipe", service->name);
97 if ((retval = service->new_connection(c)) != ERROR_OK)
98 {
99 LOG_ERROR("attempted '%s' connection rejected", service->name);
100 free(c);
101 return retval;
102 }
103 } else if (service->type == CONNECTION_PIPE)
104 {
105 c->fd = service->fd;
106 /* do not check for new connections again on stdin */
107 service->fd = -1;
108
109 char * out_file = alloc_printf("%so", service->port);
110 c->fd_out = open(out_file, O_WRONLY);
111 free(out_file);
112 if (c->fd_out == -1)
113 {
114 LOG_ERROR("could not open %s", service->port);
115 exit(1);
116 }
117
118 LOG_INFO("accepting '%s' connection from pipe %s", service->name, service->port);
119 if ((retval = service->new_connection(c)) != ERROR_OK)
120 {
121 LOG_ERROR("attempted '%s' connection rejected", service->name);
122 free(c);
123 return retval;
124 }
125 }
126
127 /* add to the end of linked list */
128 for (p = &service->connections; *p; p = &(*p)->next);
129 *p = c;
130
131 service->max_connections--;
132
133 return ERROR_OK;
134 }
135
136 static int remove_connection(struct service *service, struct connection *connection)
137 {
138 struct connection **p = &service->connections;
139 struct connection *c;
140
141 /* find connection */
142 while ((c = *p))
143 {
144 if (c->fd == connection->fd)
145 {
146 service->connection_closed(c);
147 if (service->type == CONNECTION_TCP)
148 {
149 close_socket(c->fd);
150 } else if (service->type == CONNECTION_PIPE)
151 {
152 /* The service will listen to the pipe again */
153 c->service->fd = c->fd;
154 }
155
156 command_done(c->cmd_ctx);
157
158 /* delete connection */
159 *p = c->next;
160 free(c);
161
162 service->max_connections++;
163 break;
164 }
165
166 /* redirect p to next list pointer */
167 p = &(*p)->next;
168 }
169
170 return ERROR_OK;
171 }
172
173 /* FIX! make service return error instead of invoking exit() */
174 int add_service(char *name, const char *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)
175 {
176 struct service *c, **p;
177 int so_reuseaddr_option = 1;
178
179 c = malloc(sizeof(struct service));
180
181 c->name = strdup(name);
182 c->port = strdup(port);
183 c->max_connections = 1; /* Only TCP/IP ports can support more than one connection */
184 c->fd = -1;
185 c->connections = NULL;
186 c->new_connection = new_connection_handler;
187 c->input = input_handler;
188 c->connection_closed = connection_closed_handler;
189 c->priv = priv;
190 c->next = NULL;
191 long portnumber;
192 if (strcmp(c->port, "pipe") == 0)
193 {
194 c->type = CONNECTION_STDINOUT;
195 } else
196 {
197 char *end;
198 strtol(c->port, &end, 0);
199 if (!*end && (parse_long(c->port, &portnumber) == ERROR_OK))
200 {
201 c->portnumber = portnumber;
202 c->type = CONNECTION_TCP;
203 } else
204 {
205 c->type = CONNECTION_PIPE;
206 }
207 }
208
209 if (c->type == CONNECTION_TCP)
210 {
211 c->max_connections = max_connections;
212
213 if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
214 {
215 LOG_ERROR("error creating socket: %s", strerror(errno));
216 exit(-1);
217 }
218
219 setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
220
221 socket_nonblock(c->fd);
222
223 memset(&c->sin, 0, sizeof(c->sin));
224 c->sin.sin_family = AF_INET;
225 c->sin.sin_addr.s_addr = INADDR_ANY;
226 c->sin.sin_port = htons(c->portnumber);
227
228 if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
229 {
230 LOG_ERROR("couldn't bind to socket: %s", strerror(errno));
231 exit(-1);
232 }
233
234 #ifndef _WIN32
235 int segsize = 65536;
236 setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int));
237 #endif
238 int window_size = 128 * 1024;
239
240 /* These setsockopt()s must happen before the listen() */
241
242 setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF,
243 (char *)&window_size, sizeof(window_size));
244 setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF,
245 (char *)&window_size, sizeof(window_size));
246
247 if (listen(c->fd, 1) == -1)
248 {
249 LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
250 exit(-1);
251 }
252 }
253 else if (c->type == CONNECTION_STDINOUT)
254 {
255 c->fd = fileno(stdin);
256
257 #ifdef _WIN32
258 /* for win32 set stdin/stdout to binary mode */
259 if (_setmode(_fileno(stdout), _O_BINARY) < 0)
260 LOG_WARNING("cannot change stdout mode to binary");
261 if (_setmode(_fileno(stdin), _O_BINARY) < 0)
262 LOG_WARNING("cannot change stdin mode to binary");
263 if (_setmode(_fileno(stderr), _O_BINARY) < 0)
264 LOG_WARNING("cannot change stderr mode to binary");
265 #else
266 socket_nonblock(c->fd);
267 #endif
268 }
269 else if (c->type == CONNECTION_PIPE)
270 {
271 /* Pipe we're reading from */
272 c->fd = open(c->port, O_RDONLY | O_NONBLOCK);
273 if (c->fd == -1)
274 {
275 LOG_ERROR("could not open %s", c->port);
276 exit(1);
277 }
278 }
279
280 /* add to the end of linked list */
281 for (p = &services; *p; p = &(*p)->next);
282 *p = c;
283
284 return ERROR_OK;
285 }
286
287 static int remove_services(void)
288 {
289 struct service *c = services;
290
291 /* loop service */
292 while (c)
293 {
294 struct service *next = c->next;
295
296 if (c->name)
297 free(c->name);
298
299 if (c->type == CONNECTION_PIPE)
300 {
301 if (c->fd != -1)
302 close(c->fd);
303 }
304 if (c->port)
305 free((void *)c->port);
306
307 if (c->priv)
308 free(c->priv);
309
310 /* delete service */
311 free(c);
312
313 /* remember the last service for unlinking */
314 c = next;
315 }
316
317 services = NULL;
318
319 return ERROR_OK;
320 }
321
322 int server_loop(struct command_context *command_context)
323 {
324 struct service *service;
325
326 bool poll_ok = true;
327
328 /* used in select() */
329 fd_set read_fds;
330 int fd_max;
331
332 /* used in accept() */
333 int retval;
334
335 #ifndef _WIN32
336 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
337 LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
338 #endif
339
340 while (!shutdown_openocd)
341 {
342 /* monitor sockets for activity */
343 fd_max = 0;
344 FD_ZERO(&read_fds);
345
346 /* add service and connection fds to read_fds */
347 for (service = services; service; service = service->next)
348 {
349 if (service->fd != -1)
350 {
351 /* listen for new connections */
352 FD_SET(service->fd, &read_fds);
353
354 if (service->fd > fd_max)
355 fd_max = service->fd;
356 }
357
358 if (service->connections)
359 {
360 struct connection *c;
361
362 for (c = service->connections; c; c = c->next)
363 {
364 /* check for activity on the connection */
365 FD_SET(c->fd, &read_fds);
366 if (c->fd > fd_max)
367 fd_max = c->fd;
368 }
369 }
370 }
371
372 struct timeval tv;
373 tv.tv_sec = 0;
374 if (poll_ok)
375 {
376 /* we're just polling this iteration, this is faster on embedded
377 * hosts */
378 tv.tv_usec = 0;
379 retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
380 } else
381 {
382 /* Every 100ms */
383 tv.tv_usec = 100000;
384 /* Only while we're sleeping we'll let others run */
385 openocd_sleep_prelude();
386 kept_alive();
387 retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
388 openocd_sleep_postlude();
389 }
390
391 if (retval == -1)
392 {
393 #ifdef _WIN32
394
395 errno = WSAGetLastError();
396
397 if (errno == WSAEINTR)
398 FD_ZERO(&read_fds);
399 else
400 {
401 LOG_ERROR("error during select: %s", strerror(errno));
402 exit(-1);
403 }
404 #else
405
406 if (errno == EINTR)
407 {
408 FD_ZERO(&read_fds);
409 }
410 else
411 {
412 LOG_ERROR("error during select: %s", strerror(errno));
413 exit(-1);
414 }
415 #endif
416 }
417
418 if (retval == 0)
419 {
420 /* We only execute these callbacks when there was nothing to do or we timed out */
421 target_call_timer_callbacks();
422 process_jim_events(command_context);
423
424 FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
425
426 /* We timed out/there was nothing to do, timeout rather than poll next time */
427 poll_ok = false;
428 } else
429 {
430 /* There was something to do, next time we'll just poll */
431 poll_ok = true;
432 }
433
434 for (service = services; service; service = service->next)
435 {
436 /* handle new connections on listeners */
437 if ((service->fd != -1)
438 && (FD_ISSET(service->fd, &read_fds)))
439 {
440 if (service->max_connections > 0)
441 {
442 add_connection(service, command_context);
443 }
444 else
445 {
446 if (service->type == CONNECTION_TCP)
447 {
448 struct sockaddr_in sin;
449 socklen_t address_size = sizeof(sin);
450 int tmp_fd;
451 tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
452 close_socket(tmp_fd);
453 }
454 LOG_INFO("rejected '%s' connection, no more connections allowed", service->name);
455 }
456 }
457
458 /* handle activity on connections */
459 if (service->connections)
460 {
461 struct connection *c;
462
463 for (c = service->connections; c;)
464 {
465 if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
466 {
467 if ((retval = service->input(c)) != ERROR_OK)
468 {
469 struct connection *next = c->next;
470 if (service->type == CONNECTION_PIPE)
471 {
472 /* if connection uses a pipe then shutdown openocd on error */
473 shutdown_openocd = 1;
474 }
475 remove_connection(service, c);
476 LOG_INFO("dropped '%s' connection - error %d", service->name, retval);
477 c = next;
478 continue;
479 }
480 }
481 c = c->next;
482 }
483 }
484 }
485
486 #ifdef _WIN32
487 MSG msg;
488 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
489 {
490 if (msg.message == WM_QUIT)
491 shutdown_openocd = 1;
492 }
493 #endif
494 }
495
496 return ERROR_OK;
497 }
498
499 #ifdef _WIN32
500 BOOL WINAPI ControlHandler(DWORD dwCtrlType)
501 {
502 shutdown_openocd = 1;
503 return TRUE;
504 }
505
506 void sig_handler(int sig) {
507 shutdown_openocd = 1;
508 }
509 #endif
510
511 int server_preinit(void)
512 {
513 /* this currently only calls WSAStartup on native win32 systems
514 * before any socket operations are performed.
515 * This is an issue if you call init in your config script */
516
517 #ifdef _WIN32
518 WORD wVersionRequested;
519 WSADATA wsaData;
520
521 wVersionRequested = MAKEWORD(2, 2);
522
523 if (WSAStartup(wVersionRequested, &wsaData) != 0)
524 {
525 LOG_ERROR("Failed to Open Winsock");
526 exit(-1);
527 }
528
529 if (server_use_pipes == 0)
530 {
531 /* register ctrl-c handler */
532 SetConsoleCtrlHandler(ControlHandler, TRUE);
533 }
534 else
535 {
536 /* we are using pipes so ignore ctrl-c */
537 SetConsoleCtrlHandler(NULL, TRUE);
538 }
539
540 signal(SIGINT, sig_handler);
541 signal(SIGTERM, sig_handler);
542 signal(SIGBREAK, sig_handler);
543 signal(SIGABRT, sig_handler);
544 #endif
545
546 return ERROR_OK;
547 }
548
549 int server_init(struct command_context *cmd_ctx)
550 {
551 int ret = tcl_init();
552 if (ERROR_OK != ret)
553 return ret;
554
555 return telnet_init("Open On-Chip Debugger");
556 }
557
558 int server_quit(void)
559 {
560 remove_services();
561
562 #ifdef _WIN32
563 WSACleanup();
564 SetConsoleCtrlHandler(ControlHandler, FALSE);
565 #endif
566
567 return ERROR_OK;
568 }
569
570 int connection_write(struct connection *connection, const void *data, int len)
571 {
572 if (len == 0)
573 {
574 /* successful no-op. Sockets and pipes behave differently here... */
575 return 0;
576 }
577 if (connection->service->type == CONNECTION_TCP)
578 {
579 return write_socket(connection->fd_out, data, len);
580 } else
581 {
582 return write(connection->fd_out, data, len);
583 }
584 }
585
586 int connection_read(struct connection *connection, void *data, int len)
587 {
588 if (connection->service->type == CONNECTION_TCP)
589 {
590 return read_socket(connection->fd, data, len);
591 } else
592 {
593 return read(connection->fd, data, len);
594 }
595 }
596
597 /* tell the server we want to shut down */
598 COMMAND_HANDLER(handle_shutdown_command)
599 {
600 LOG_USER("shutdown command invoked");
601
602 shutdown_openocd = 1;
603
604 return ERROR_OK;
605 }
606
607 static const struct command_registration server_command_handlers[] = {
608 {
609 .name = "shutdown",
610 .handler = &handle_shutdown_command,
611 .mode = COMMAND_ANY,
612 .help = "shut the server down",
613 },
614 COMMAND_REGISTRATION_DONE
615 };
616
617 int server_register_commands(struct command_context *cmd_ctx)
618 {
619 int retval = telnet_register_commands(cmd_ctx);
620 if (ERROR_OK != retval)
621 return retval;
622
623 retval = tcl_register_commands(cmd_ctx);
624 if (ERROR_OK != retval)
625 return retval;
626
627 return register_commands(cmd_ctx, NULL, server_command_handlers);
628 }
629
630 SERVER_PORT_COMMAND()
631 {
632 switch (CMD_ARGC) {
633 case 0:
634 command_print(CMD_CTX, "%d", *out);
635 break;
636 case 1:
637 {
638 uint16_t port;
639 COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
640 *out = port;
641 break;
642 }
643 default:
644 return ERROR_INVALID_ARGUMENTS;
645 }
646 return ERROR_OK;
647 }
648
649 SERVER_PIPE_COMMAND()
650 {
651 switch (CMD_ARGC) {
652 case 0:
653 command_print(CMD_CTX, "%s", *out);
654 break;
655 case 1:
656 {
657 const char * t = strdup(CMD_ARGV[0]);
658 free((void *)*out);
659 *out = t;
660 break;
661 }
662 default:
663 return ERROR_INVALID_ARGUMENTS;
664 }
665 return ERROR_OK;
666 }
667

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)