e53f37d0b8ee05c341730be64ce6becf84eeed76
[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, see <http://www.gnu.org/licenses/>. *
23 ***************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "server.h"
30 #include <target/target.h>
31 #include <target/target_request.h>
32 #include <target/openrisc/jsp_server.h>
33 #include "openocd.h"
34 #include "tcl_server.h"
35 #include "telnet_server.h"
36
37 #include <signal.h>
38
39 #ifdef HAVE_NETDB_H
40 #include <netdb.h>
41 #endif
42
43 #ifndef _WIN32
44 #include <netinet/tcp.h>
45 #endif
46
47 static struct service *services;
48
49 enum shutdown_reason {
50 CONTINUE_MAIN_LOOP, /* stay in main event loop */
51 SHUTDOWN_REQUESTED, /* set by shutdown command; exit the event loop and quit the debugger */
52 SHUTDOWN_WITH_ERROR_CODE, /* set by shutdown command; quit with non-zero return code */
53 SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */
54 };
55 static enum shutdown_reason shutdown_openocd = CONTINUE_MAIN_LOOP;
56
57 /* store received signal to exit application by killing ourselves */
58 static int last_signal;
59
60 /* set the polling period to 100ms */
61 static int polling_period = 100;
62
63 /* address by name on which to listen for incoming TCP/IP connections */
64 static char *bindto_name;
65
66 static int add_connection(struct service *service, struct command_context *cmd_ctx)
67 {
68 socklen_t address_size;
69 struct connection *c, **p;
70 int retval;
71 int flag = 1;
72
73 c = malloc(sizeof(struct connection));
74 c->fd = -1;
75 c->fd_out = -1;
76 memset(&c->sin, 0, sizeof(c->sin));
77 c->cmd_ctx = copy_command_context(cmd_ctx);
78 c->service = service;
79 c->input_pending = false;
80 c->priv = NULL;
81 c->next = NULL;
82
83 if (service->type == CONNECTION_TCP) {
84 address_size = sizeof(c->sin);
85
86 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
87 c->fd_out = c->fd;
88
89 /* This increases performance dramatically for e.g. GDB load which
90 * does not have a sliding window protocol.
91 *
92 * Ignore errors from this fn as it probably just means less performance
93 */
94 setsockopt(c->fd, /* socket affected */
95 IPPROTO_TCP, /* set option at TCP level */
96 TCP_NODELAY, /* name of option */
97 (char *)&flag, /* the cast is historical cruft */
98 sizeof(int)); /* length of option value */
99
100 LOG_INFO("accepting '%s' connection on tcp/%s", service->name, service->port);
101 retval = service->new_connection(c);
102 if (retval != ERROR_OK) {
103 close_socket(c->fd);
104 LOG_ERROR("attempted '%s' connection rejected", service->name);
105 command_done(c->cmd_ctx);
106 free(c);
107 return retval;
108 }
109 } else if (service->type == CONNECTION_STDINOUT) {
110 c->fd = service->fd;
111 c->fd_out = fileno(stdout);
112
113 #ifdef _WIN32
114 /* we are using stdin/out so ignore ctrl-c under windoze */
115 SetConsoleCtrlHandler(NULL, TRUE);
116 #endif
117
118 /* do not check for new connections again on stdin */
119 service->fd = -1;
120
121 LOG_INFO("accepting '%s' connection from pipe", service->name);
122 retval = service->new_connection(c);
123 if (retval != ERROR_OK) {
124 LOG_ERROR("attempted '%s' connection rejected", service->name);
125 command_done(c->cmd_ctx);
126 free(c);
127 return retval;
128 }
129 } else if (service->type == CONNECTION_PIPE) {
130 c->fd = service->fd;
131 /* do not check for new connections again on stdin */
132 service->fd = -1;
133
134 char *out_file = alloc_printf("%so", service->port);
135 c->fd_out = open(out_file, O_WRONLY);
136 free(out_file);
137 if (c->fd_out == -1) {
138 LOG_ERROR("could not open %s", service->port);
139 command_done(c->cmd_ctx);
140 free(c);
141 return ERROR_FAIL;
142 }
143
144 LOG_INFO("accepting '%s' connection from pipe %s", service->name, service->port);
145 retval = service->new_connection(c);
146 if (retval != ERROR_OK) {
147 LOG_ERROR("attempted '%s' connection rejected", service->name);
148 command_done(c->cmd_ctx);
149 free(c);
150 return retval;
151 }
152 }
153
154 /* add to the end of linked list */
155 for (p = &service->connections; *p; p = &(*p)->next)
156 ;
157 *p = c;
158
159 if (service->max_connections != CONNECTION_LIMIT_UNLIMITED)
160 service->max_connections--;
161
162 return ERROR_OK;
163 }
164
165 static int remove_connection(struct service *service, struct connection *connection)
166 {
167 struct connection **p = &service->connections;
168 struct connection *c;
169
170 /* find connection */
171 while ((c = *p)) {
172 if (c->fd == connection->fd) {
173 service->connection_closed(c);
174 if (service->type == CONNECTION_TCP)
175 close_socket(c->fd);
176 else if (service->type == CONNECTION_PIPE) {
177 /* The service will listen to the pipe again */
178 c->service->fd = c->fd;
179 }
180
181 command_done(c->cmd_ctx);
182
183 /* delete connection */
184 *p = c->next;
185 free(c);
186
187 if (service->max_connections != CONNECTION_LIMIT_UNLIMITED)
188 service->max_connections++;
189
190 break;
191 }
192
193 /* redirect p to next list pointer */
194 p = &(*p)->next;
195 }
196
197 return ERROR_OK;
198 }
199
200 static void free_service(struct service *c)
201 {
202 free(c->name);
203 free(c->port);
204 free(c);
205 }
206
207 int add_service(char *name,
208 const char *port,
209 int max_connections,
210 new_connection_handler_t new_connection_handler,
211 input_handler_t input_handler,
212 connection_closed_handler_t connection_closed_handler,
213 void *priv)
214 {
215 struct service *c, **p;
216 struct hostent *hp;
217 int so_reuseaddr_option = 1;
218
219 c = malloc(sizeof(struct service));
220
221 c->name = strdup(name);
222 c->port = strdup(port);
223 c->max_connections = 1; /* Only TCP/IP ports can support more than one connection */
224 c->fd = -1;
225 c->connections = NULL;
226 c->new_connection = new_connection_handler;
227 c->input = input_handler;
228 c->connection_closed = connection_closed_handler;
229 c->priv = priv;
230 c->next = NULL;
231 long portnumber;
232 if (strcmp(c->port, "pipe") == 0)
233 c->type = CONNECTION_STDINOUT;
234 else {
235 char *end;
236 portnumber = strtol(c->port, &end, 0);
237 if (!*end && (parse_long(c->port, &portnumber) == ERROR_OK)) {
238 c->portnumber = portnumber;
239 c->type = CONNECTION_TCP;
240 } else
241 c->type = CONNECTION_PIPE;
242 }
243
244 if (c->type == CONNECTION_TCP) {
245 c->max_connections = max_connections;
246
247 c->fd = socket(AF_INET, SOCK_STREAM, 0);
248 if (c->fd == -1) {
249 LOG_ERROR("error creating socket: %s", strerror(errno));
250 free_service(c);
251 return ERROR_FAIL;
252 }
253
254 setsockopt(c->fd,
255 SOL_SOCKET,
256 SO_REUSEADDR,
257 (void *)&so_reuseaddr_option,
258 sizeof(int));
259
260 socket_nonblock(c->fd);
261
262 memset(&c->sin, 0, sizeof(c->sin));
263 c->sin.sin_family = AF_INET;
264
265 if (bindto_name == NULL)
266 c->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
267 else {
268 hp = gethostbyname(bindto_name);
269 if (hp == NULL) {
270 LOG_ERROR("couldn't resolve bindto address: %s", bindto_name);
271 close_socket(c->fd);
272 free_service(c);
273 return ERROR_FAIL;
274 }
275 memcpy(&c->sin.sin_addr, hp->h_addr_list[0], hp->h_length);
276 }
277 c->sin.sin_port = htons(c->portnumber);
278
279 if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) {
280 LOG_ERROR("couldn't bind %s to socket on port %d: %s", name, c->portnumber, strerror(errno));
281 close_socket(c->fd);
282 free_service(c);
283 return ERROR_FAIL;
284 }
285
286 #ifndef _WIN32
287 int segsize = 65536;
288 setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int));
289 #endif
290 int window_size = 128 * 1024;
291
292 /* These setsockopt()s must happen before the listen() */
293
294 setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF,
295 (char *)&window_size, sizeof(window_size));
296 setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF,
297 (char *)&window_size, sizeof(window_size));
298
299 if (listen(c->fd, 1) == -1) {
300 LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
301 close_socket(c->fd);
302 free_service(c);
303 return ERROR_FAIL;
304 }
305
306 struct sockaddr_in addr_in;
307 addr_in.sin_port = 0;
308 socklen_t addr_in_size = sizeof(addr_in);
309 if (getsockname(c->fd, (struct sockaddr *)&addr_in, &addr_in_size) == 0)
310 LOG_INFO("Listening on port %hu for %s connections",
311 ntohs(addr_in.sin_port), name);
312 } else if (c->type == CONNECTION_STDINOUT) {
313 c->fd = fileno(stdin);
314
315 #ifdef _WIN32
316 /* for win32 set stdin/stdout to binary mode */
317 if (_setmode(_fileno(stdout), _O_BINARY) < 0)
318 LOG_WARNING("cannot change stdout mode to binary");
319 if (_setmode(_fileno(stdin), _O_BINARY) < 0)
320 LOG_WARNING("cannot change stdin mode to binary");
321 if (_setmode(_fileno(stderr), _O_BINARY) < 0)
322 LOG_WARNING("cannot change stderr mode to binary");
323 #else
324 socket_nonblock(c->fd);
325 #endif
326 } else if (c->type == CONNECTION_PIPE) {
327 #ifdef _WIN32
328 /* we currently do not support named pipes under win32
329 * so exit openocd for now */
330 LOG_ERROR("Named pipes currently not supported under this os");
331 free_service(c);
332 return ERROR_FAIL;
333 #else
334 /* Pipe we're reading from */
335 c->fd = open(c->port, O_RDONLY | O_NONBLOCK);
336 if (c->fd == -1) {
337 LOG_ERROR("could not open %s", c->port);
338 free_service(c);
339 return ERROR_FAIL;
340 }
341 #endif
342 }
343
344 /* add to the end of linked list */
345 for (p = &services; *p; p = &(*p)->next)
346 ;
347 *p = c;
348
349 return ERROR_OK;
350 }
351
352 static void remove_connections(struct service *service)
353 {
354 struct connection *connection;
355
356 connection = service->connections;
357
358 while (connection) {
359 struct connection *tmp;
360
361 tmp = connection->next;
362 remove_connection(service, connection);
363 connection = tmp;
364 }
365 }
366
367 int remove_service(const char *name, const char *port)
368 {
369 struct service *tmp;
370 struct service *prev;
371
372 prev = services;
373
374 for (tmp = services; tmp; prev = tmp, tmp = tmp->next) {
375 if (!strcmp(tmp->name, name) && !strcmp(tmp->port, port)) {
376 remove_connections(tmp);
377
378 if (tmp == services)
379 services = tmp->next;
380 else
381 prev->next = tmp->next;
382
383 if (tmp->type != CONNECTION_STDINOUT)
384 close_socket(tmp->fd);
385
386 free(tmp->priv);
387 free_service(tmp);
388
389 return ERROR_OK;
390 }
391 }
392
393 return ERROR_OK;
394 }
395
396 static int remove_services(void)
397 {
398 struct service *c = services;
399
400 /* loop service */
401 while (c) {
402 struct service *next = c->next;
403
404 remove_connections(c);
405
406 free(c->name);
407
408 if (c->type == CONNECTION_PIPE) {
409 if (c->fd != -1)
410 close(c->fd);
411 }
412 free(c->port);
413 free(c->priv);
414 /* delete service */
415 free(c);
416
417 /* remember the last service for unlinking */
418 c = next;
419 }
420
421 services = NULL;
422
423 return ERROR_OK;
424 }
425
426 int server_loop(struct command_context *command_context)
427 {
428 struct service *service;
429
430 bool poll_ok = true;
431
432 /* used in select() */
433 fd_set read_fds;
434 int fd_max;
435
436 /* used in accept() */
437 int retval;
438
439 #ifndef _WIN32
440 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
441 LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
442 #endif
443
444 while (shutdown_openocd == CONTINUE_MAIN_LOOP) {
445 /* monitor sockets for activity */
446 fd_max = 0;
447 FD_ZERO(&read_fds);
448
449 /* add service and connection fds to read_fds */
450 for (service = services; service; service = service->next) {
451 if (service->fd != -1) {
452 /* listen for new connections */
453 FD_SET(service->fd, &read_fds);
454
455 if (service->fd > fd_max)
456 fd_max = service->fd;
457 }
458
459 if (service->connections) {
460 struct connection *c;
461
462 for (c = service->connections; c; c = c->next) {
463 /* check for activity on the connection */
464 FD_SET(c->fd, &read_fds);
465 if (c->fd > fd_max)
466 fd_max = c->fd;
467 }
468 }
469 }
470
471 struct timeval tv;
472 tv.tv_sec = 0;
473 if (poll_ok) {
474 /* we're just polling this iteration, this is faster on embedded
475 * hosts */
476 tv.tv_usec = 0;
477 retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
478 } else {
479 /* Every 100ms, can be changed with "poll_period" command */
480 tv.tv_usec = polling_period * 1000;
481 /* Only while we're sleeping we'll let others run */
482 openocd_sleep_prelude();
483 kept_alive();
484 retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
485 openocd_sleep_postlude();
486 }
487
488 if (retval == -1) {
489 #ifdef _WIN32
490
491 errno = WSAGetLastError();
492
493 if (errno == WSAEINTR)
494 FD_ZERO(&read_fds);
495 else {
496 LOG_ERROR("error during select: %s", strerror(errno));
497 return ERROR_FAIL;
498 }
499 #else
500
501 if (errno == EINTR)
502 FD_ZERO(&read_fds);
503 else {
504 LOG_ERROR("error during select: %s", strerror(errno));
505 return ERROR_FAIL;
506 }
507 #endif
508 }
509
510 if (retval == 0) {
511 /* We only execute these callbacks when there was nothing to do or we timed
512 *out */
513 target_call_timer_callbacks();
514 process_jim_events(command_context);
515
516 FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
517
518 /* We timed out/there was nothing to do, timeout rather than poll next time
519 **/
520 poll_ok = false;
521 } else {
522 /* There was something to do, next time we'll just poll */
523 poll_ok = true;
524 }
525
526 /* This is a simple back-off algorithm where we immediately
527 * re-poll if we did something this time around.
528 *
529 * This greatly improves performance of DCC.
530 */
531 poll_ok = poll_ok || target_got_message();
532
533 for (service = services; service; service = service->next) {
534 /* handle new connections on listeners */
535 if ((service->fd != -1)
536 && (FD_ISSET(service->fd, &read_fds))) {
537 if (service->max_connections != 0)
538 add_connection(service, command_context);
539 else {
540 if (service->type == CONNECTION_TCP) {
541 struct sockaddr_in sin;
542 socklen_t address_size = sizeof(sin);
543 int tmp_fd;
544 tmp_fd = accept(service->fd,
545 (struct sockaddr *)&service->sin,
546 &address_size);
547 close_socket(tmp_fd);
548 }
549 LOG_INFO(
550 "rejected '%s' connection, no more connections allowed",
551 service->name);
552 }
553 }
554
555 /* handle activity on connections */
556 if (service->connections) {
557 struct connection *c;
558
559 for (c = service->connections; c; ) {
560 if ((c->fd >= 0 && FD_ISSET(c->fd, &read_fds)) || c->input_pending) {
561 retval = service->input(c);
562 if (retval != ERROR_OK) {
563 struct connection *next = c->next;
564 if (service->type == CONNECTION_PIPE ||
565 service->type == CONNECTION_STDINOUT) {
566 /* if connection uses a pipe then
567 * shutdown openocd on error */
568 shutdown_openocd = SHUTDOWN_REQUESTED;
569 }
570 remove_connection(service, c);
571 LOG_INFO("dropped '%s' connection",
572 service->name);
573 c = next;
574 continue;
575 }
576 }
577 c = c->next;
578 }
579 }
580 }
581
582 #ifdef _WIN32
583 MSG msg;
584 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
585 if (msg.message == WM_QUIT)
586 shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
587 }
588 #endif
589 }
590
591 /* when quit for signal or CTRL-C, run (eventually user implemented) "shutdown" */
592 if (shutdown_openocd == SHUTDOWN_WITH_SIGNAL_CODE)
593 command_run_line(command_context, "shutdown");
594
595 return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK;
596 }
597
598 static void sig_handler(int sig)
599 {
600 /* store only first signal that hits us */
601 if (shutdown_openocd == CONTINUE_MAIN_LOOP) {
602 shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
603 last_signal = sig;
604 LOG_DEBUG("Terminating on Signal %d", sig);
605 } else
606 LOG_DEBUG("Ignored extra Signal %d", sig);
607 }
608
609
610 #ifdef _WIN32
611 BOOL WINAPI ControlHandler(DWORD dwCtrlType)
612 {
613 shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
614 return TRUE;
615 }
616 #else
617 static void sigkey_handler(int sig)
618 {
619 /* ignore keystroke generated signals if not in foreground process group */
620
621 if (tcgetpgrp(STDIN_FILENO) > 0)
622 sig_handler(sig);
623 else
624 LOG_DEBUG("Ignored Signal %d", sig);
625 }
626 #endif
627
628
629 int server_host_os_entry(void)
630 {
631 /* this currently only calls WSAStartup on native win32 systems
632 * before any socket operations are performed.
633 * This is an issue if you call init in your config script */
634
635 #ifdef _WIN32
636 WORD wVersionRequested;
637 WSADATA wsaData;
638
639 wVersionRequested = MAKEWORD(2, 2);
640
641 if (WSAStartup(wVersionRequested, &wsaData) != 0) {
642 LOG_ERROR("Failed to Open Winsock");
643 return ERROR_FAIL;
644 }
645 #endif
646 return ERROR_OK;
647 }
648
649 int server_host_os_close(void)
650 {
651 #ifdef _WIN32
652 WSACleanup();
653 #endif
654 return ERROR_OK;
655 }
656
657 int server_preinit(void)
658 {
659 #ifdef _WIN32
660 /* register ctrl-c handler */
661 SetConsoleCtrlHandler(ControlHandler, TRUE);
662
663 signal(SIGBREAK, sig_handler);
664 signal(SIGINT, sig_handler);
665 #else
666 signal(SIGHUP, sig_handler);
667 signal(SIGPIPE, sig_handler);
668 signal(SIGQUIT, sigkey_handler);
669 signal(SIGINT, sigkey_handler);
670 #endif
671 signal(SIGTERM, sig_handler);
672 signal(SIGABRT, sig_handler);
673
674 return ERROR_OK;
675 }
676
677 int server_init(struct command_context *cmd_ctx)
678 {
679 int ret = tcl_init();
680
681 if (ret != ERROR_OK)
682 return ret;
683
684 ret = telnet_init("Open On-Chip Debugger");
685
686 if (ret != ERROR_OK) {
687 remove_services();
688 return ret;
689 }
690
691 return ERROR_OK;
692 }
693
694 int server_quit(void)
695 {
696 remove_services();
697 target_quit();
698
699 #ifdef _WIN32
700 SetConsoleCtrlHandler(ControlHandler, FALSE);
701
702 return ERROR_OK;
703 #endif
704
705 /* return signal number so we can kill ourselves */
706 return last_signal;
707 }
708
709 void server_free(void)
710 {
711 tcl_service_free();
712 telnet_service_free();
713 jsp_service_free();
714
715 free(bindto_name);
716 }
717
718 void exit_on_signal(int sig)
719 {
720 #ifndef _WIN32
721 /* bring back default system handler and kill yourself */
722 signal(sig, SIG_DFL);
723 kill(getpid(), sig);
724 #endif
725 }
726
727 int connection_write(struct connection *connection, const void *data, int len)
728 {
729 if (len == 0) {
730 /* successful no-op. Sockets and pipes behave differently here... */
731 return 0;
732 }
733 if (connection->service->type == CONNECTION_TCP)
734 return write_socket(connection->fd_out, data, len);
735 else
736 return write(connection->fd_out, data, len);
737 }
738
739 int connection_read(struct connection *connection, void *data, int len)
740 {
741 if (connection->service->type == CONNECTION_TCP)
742 return read_socket(connection->fd, data, len);
743 else
744 return read(connection->fd, data, len);
745 }
746
747 /* tell the server we want to shut down */
748 COMMAND_HANDLER(handle_shutdown_command)
749 {
750 LOG_USER("shutdown command invoked");
751
752 shutdown_openocd = SHUTDOWN_REQUESTED;
753
754 if (CMD_ARGC == 1) {
755 if (!strcmp(CMD_ARGV[0], "error")) {
756 shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE;
757 return ERROR_FAIL;
758 }
759 }
760
761 return ERROR_COMMAND_CLOSE_CONNECTION;
762 }
763
764 COMMAND_HANDLER(handle_poll_period_command)
765 {
766 if (CMD_ARGC == 0)
767 LOG_WARNING("You need to set a period value");
768 else
769 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], polling_period);
770
771 LOG_INFO("set servers polling period to %ums", polling_period);
772
773 return ERROR_OK;
774 }
775
776 COMMAND_HANDLER(handle_bindto_command)
777 {
778 switch (CMD_ARGC) {
779 case 0:
780 command_print(CMD, "bindto name: %s", bindto_name);
781 break;
782 case 1:
783 free(bindto_name);
784 bindto_name = strdup(CMD_ARGV[0]);
785 break;
786 default:
787 return ERROR_COMMAND_SYNTAX_ERROR;
788 }
789 return ERROR_OK;
790 }
791
792 static const struct command_registration server_command_handlers[] = {
793 {
794 .name = "shutdown",
795 .handler = &handle_shutdown_command,
796 .mode = COMMAND_ANY,
797 .usage = "",
798 .help = "shut the server down",
799 },
800 {
801 .name = "poll_period",
802 .handler = &handle_poll_period_command,
803 .mode = COMMAND_ANY,
804 .usage = "",
805 .help = "set the servers polling period",
806 },
807 {
808 .name = "bindto",
809 .handler = &handle_bindto_command,
810 .mode = COMMAND_CONFIG,
811 .usage = "[name]",
812 .help = "Specify address by name on which to listen for "
813 "incoming TCP/IP connections",
814 },
815 COMMAND_REGISTRATION_DONE
816 };
817
818 int server_register_commands(struct command_context *cmd_ctx)
819 {
820 int retval = telnet_register_commands(cmd_ctx);
821 if (ERROR_OK != retval)
822 return retval;
823
824 retval = tcl_register_commands(cmd_ctx);
825 if (ERROR_OK != retval)
826 return retval;
827
828 retval = jsp_register_commands(cmd_ctx);
829 if (ERROR_OK != retval)
830 return retval;
831
832 return register_commands(cmd_ctx, NULL, server_command_handlers);
833 }
834
835 COMMAND_HELPER(server_port_command, unsigned short *out)
836 {
837 switch (CMD_ARGC) {
838 case 0:
839 command_print(CMD, "%d", *out);
840 break;
841 case 1:
842 {
843 uint16_t port;
844 COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
845 *out = port;
846 break;
847 }
848 default:
849 return ERROR_COMMAND_SYNTAX_ERROR;
850 }
851 return ERROR_OK;
852 }
853
854 COMMAND_HELPER(server_pipe_command, char **out)
855 {
856 switch (CMD_ARGC) {
857 case 0:
858 command_print(CMD, "%s", *out);
859 break;
860 case 1:
861 {
862 if (CMD_CTX->mode == COMMAND_EXEC) {
863 LOG_WARNING("unable to change server port after init");
864 return ERROR_COMMAND_ARGUMENT_INVALID;
865 }
866 free(*out);
867 *out = strdup(CMD_ARGV[0]);
868 break;
869 }
870 default:
871 return ERROR_COMMAND_SYNTAX_ERROR;
872 }
873 return ERROR_OK;
874 }

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)