1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2005 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
7 * Copyright (C) 2007-2010 Øyvind Harboe *
8 * oyvind.harboe@zylin.com *
10 * Copyright (C) 2008 by Spencer Oliver *
11 * spen@spen-soft.co.uk *
12 ***************************************************************************/
19 #include <helper/time_support.h>
20 #include <target/target.h>
21 #include <target/target_request.h>
22 #include <target/openrisc/jsp_server.h>
24 #include "tcl_server.h"
25 #include "telnet_server.h"
35 #include <netinet/tcp.h>
38 static struct service
*services
;
40 enum shutdown_reason
{
41 CONTINUE_MAIN_LOOP
, /* stay in main event loop */
42 SHUTDOWN_REQUESTED
, /* set by shutdown command; exit the event loop and quit the debugger */
43 SHUTDOWN_WITH_ERROR_CODE
, /* set by shutdown command; quit with non-zero return code */
44 SHUTDOWN_WITH_SIGNAL_CODE
/* set by sig_handler; exec shutdown then exit with signal as return code */
46 static enum shutdown_reason shutdown_openocd
= CONTINUE_MAIN_LOOP
;
48 /* store received signal to exit application by killing ourselves */
49 static int last_signal
;
51 /* set the polling period to 100ms */
52 static int polling_period
= 100;
54 /* address by name on which to listen for incoming TCP/IP connections */
55 static char *bindto_name
;
57 static int add_connection(struct service
*service
, struct command_context
*cmd_ctx
)
59 socklen_t address_size
;
60 struct connection
*c
, **p
;
64 c
= malloc(sizeof(struct connection
));
67 memset(&c
->sin
, 0, sizeof(c
->sin
));
68 c
->cmd_ctx
= copy_command_context(cmd_ctx
);
70 c
->input_pending
= false;
74 if (service
->type
== CONNECTION_TCP
) {
75 address_size
= sizeof(c
->sin
);
77 c
->fd
= accept(service
->fd
, (struct sockaddr
*)&service
->sin
, &address_size
);
80 /* This increases performance dramatically for e.g. GDB load which
81 * does not have a sliding window protocol.
83 * Ignore errors from this fn as it probably just means less performance
85 setsockopt(c
->fd
, /* socket affected */
86 IPPROTO_TCP
, /* set option at TCP level */
87 TCP_NODELAY
, /* name of option */
88 (char *)&flag
, /* the cast is historical cruft */
89 sizeof(int)); /* length of option value */
91 LOG_INFO("accepting '%s' connection on tcp/%s", service
->name
, service
->port
);
92 retval
= service
->new_connection(c
);
93 if (retval
!= ERROR_OK
) {
95 LOG_ERROR("attempted '%s' connection rejected", service
->name
);
96 command_done(c
->cmd_ctx
);
100 } else if (service
->type
== CONNECTION_STDINOUT
) {
102 c
->fd_out
= fileno(stdout
);
105 /* we are using stdin/out so ignore ctrl-c under windoze */
106 SetConsoleCtrlHandler(NULL
, TRUE
);
109 /* do not check for new connections again on stdin */
112 LOG_INFO("accepting '%s' connection from pipe", service
->name
);
113 retval
= service
->new_connection(c
);
114 if (retval
!= ERROR_OK
) {
115 LOG_ERROR("attempted '%s' connection rejected", service
->name
);
116 command_done(c
->cmd_ctx
);
120 } else if (service
->type
== CONNECTION_PIPE
) {
122 /* do not check for new connections again on stdin */
125 char *out_file
= alloc_printf("%so", service
->port
);
126 c
->fd_out
= open(out_file
, O_WRONLY
);
128 if (c
->fd_out
== -1) {
129 LOG_ERROR("could not open %s", service
->port
);
130 command_done(c
->cmd_ctx
);
135 LOG_INFO("accepting '%s' connection from pipe %s", service
->name
, service
->port
);
136 retval
= service
->new_connection(c
);
137 if (retval
!= ERROR_OK
) {
138 LOG_ERROR("attempted '%s' connection rejected", service
->name
);
139 command_done(c
->cmd_ctx
);
145 /* add to the end of linked list */
146 for (p
= &service
->connections
; *p
; p
= &(*p
)->next
)
150 if (service
->max_connections
!= CONNECTION_LIMIT_UNLIMITED
)
151 service
->max_connections
--;
156 static int remove_connection(struct service
*service
, struct connection
*connection
)
158 struct connection
**p
= &service
->connections
;
159 struct connection
*c
;
161 /* find connection */
163 if (c
->fd
== connection
->fd
) {
164 service
->connection_closed(c
);
165 if (service
->type
== CONNECTION_TCP
)
167 else if (service
->type
== CONNECTION_PIPE
) {
168 /* The service will listen to the pipe again */
169 c
->service
->fd
= c
->fd
;
172 command_done(c
->cmd_ctx
);
174 /* delete connection */
178 if (service
->max_connections
!= CONNECTION_LIMIT_UNLIMITED
)
179 service
->max_connections
++;
184 /* redirect p to next list pointer */
191 static void free_service(struct service
*c
)
198 int add_service(const struct service_driver
*driver
, const char *port
,
199 int max_connections
, void *priv
)
201 struct service
*c
, **p
;
203 int so_reuseaddr_option
= 1;
205 c
= malloc(sizeof(struct service
));
207 c
->name
= strdup(driver
->name
);
208 c
->port
= strdup(port
);
209 c
->max_connections
= 1; /* Only TCP/IP ports can support more than one connection */
211 c
->connections
= NULL
;
212 c
->new_connection_during_keep_alive
= driver
->new_connection_during_keep_alive_handler
;
213 c
->new_connection
= driver
->new_connection_handler
;
214 c
->input
= driver
->input_handler
;
215 c
->connection_closed
= driver
->connection_closed_handler
;
216 c
->keep_client_alive
= driver
->keep_client_alive_handler
;
220 if (strcmp(c
->port
, "pipe") == 0)
221 c
->type
= CONNECTION_STDINOUT
;
224 portnumber
= strtol(c
->port
, &end
, 0);
225 if (!*end
&& (parse_long(c
->port
, &portnumber
) == ERROR_OK
)) {
226 c
->portnumber
= portnumber
;
227 c
->type
= CONNECTION_TCP
;
229 c
->type
= CONNECTION_PIPE
;
232 if (c
->type
== CONNECTION_TCP
) {
233 c
->max_connections
= max_connections
;
235 c
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
237 LOG_ERROR("error creating socket: %s", strerror(errno
));
245 (void *)&so_reuseaddr_option
,
248 socket_nonblock(c
->fd
);
250 memset(&c
->sin
, 0, sizeof(c
->sin
));
251 c
->sin
.sin_family
= AF_INET
;
254 c
->sin
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
256 hp
= gethostbyname(bindto_name
);
258 LOG_ERROR("couldn't resolve bindto address: %s", bindto_name
);
263 memcpy(&c
->sin
.sin_addr
, hp
->h_addr_list
[0], hp
->h_length
);
265 c
->sin
.sin_port
= htons(c
->portnumber
);
267 if (bind(c
->fd
, (struct sockaddr
*)&c
->sin
, sizeof(c
->sin
)) == -1) {
268 LOG_ERROR("couldn't bind %s to socket on port %d: %s", c
->name
, c
->portnumber
, strerror(errno
));
276 setsockopt(c
->fd
, IPPROTO_TCP
, TCP_MAXSEG
, &segsize
, sizeof(int));
278 int window_size
= 128 * 1024;
280 /* These setsockopt()s must happen before the listen() */
282 setsockopt(c
->fd
, SOL_SOCKET
, SO_SNDBUF
,
283 (char *)&window_size
, sizeof(window_size
));
284 setsockopt(c
->fd
, SOL_SOCKET
, SO_RCVBUF
,
285 (char *)&window_size
, sizeof(window_size
));
287 if (listen(c
->fd
, 1) == -1) {
288 LOG_ERROR("couldn't listen on socket: %s", strerror(errno
));
294 struct sockaddr_in addr_in
;
295 addr_in
.sin_port
= 0;
296 socklen_t addr_in_size
= sizeof(addr_in
);
297 if (getsockname(c
->fd
, (struct sockaddr
*)&addr_in
, &addr_in_size
) == 0)
298 LOG_INFO("Listening on port %hu for %s connections",
299 ntohs(addr_in
.sin_port
), c
->name
);
300 } else if (c
->type
== CONNECTION_STDINOUT
) {
301 c
->fd
= fileno(stdin
);
304 /* for win32 set stdin/stdout to binary mode */
305 if (_setmode(_fileno(stdout
), _O_BINARY
) < 0)
306 LOG_WARNING("cannot change stdout mode to binary");
307 if (_setmode(_fileno(stdin
), _O_BINARY
) < 0)
308 LOG_WARNING("cannot change stdin mode to binary");
309 if (_setmode(_fileno(stderr
), _O_BINARY
) < 0)
310 LOG_WARNING("cannot change stderr mode to binary");
312 socket_nonblock(c
->fd
);
314 } else if (c
->type
== CONNECTION_PIPE
) {
316 /* we currently do not support named pipes under win32
317 * so exit openocd for now */
318 LOG_ERROR("Named pipes currently not supported under this os");
322 /* Pipe we're reading from */
323 c
->fd
= open(c
->port
, O_RDONLY
| O_NONBLOCK
);
325 LOG_ERROR("could not open %s", c
->port
);
332 /* add to the end of linked list */
333 for (p
= &services
; *p
; p
= &(*p
)->next
)
340 static void remove_connections(struct service
*service
)
342 struct connection
*connection
;
344 connection
= service
->connections
;
347 struct connection
*tmp
;
349 tmp
= connection
->next
;
350 remove_connection(service
, connection
);
355 int remove_service(const char *name
, const char *port
)
358 struct service
*prev
;
362 for (tmp
= services
; tmp
; prev
= tmp
, tmp
= tmp
->next
) {
363 if (!strcmp(tmp
->name
, name
) && !strcmp(tmp
->port
, port
)) {
364 remove_connections(tmp
);
367 services
= tmp
->next
;
369 prev
->next
= tmp
->next
;
371 if (tmp
->type
!= CONNECTION_STDINOUT
)
372 close_socket(tmp
->fd
);
384 static int remove_services(void)
386 struct service
*c
= services
;
390 struct service
*next
= c
->next
;
392 remove_connections(c
);
396 if (c
->type
== CONNECTION_PIPE
) {
405 /* remember the last service for unlinking */
414 void server_keep_clients_alive(void)
416 for (struct service
*s
= services
; s
; s
= s
->next
)
417 if (s
->keep_client_alive
)
418 for (struct connection
*c
= s
->connections
; c
; c
= c
->next
)
419 s
->keep_client_alive(c
);
422 int server_loop(struct command_context
*command_context
)
424 struct service
*service
;
428 /* used in select() */
432 /* used in accept() */
435 int64_t next_event
= timeval_ms() + polling_period
;
438 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
)
439 LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
442 while (shutdown_openocd
== CONTINUE_MAIN_LOOP
) {
443 /* monitor sockets for activity */
447 /* add service and connection fds to read_fds */
448 for (service
= services
; service
; service
= service
->next
) {
449 if (service
->fd
!= -1) {
450 /* listen for new connections */
451 FD_SET(service
->fd
, &read_fds
);
453 if (service
->fd
> fd_max
)
454 fd_max
= service
->fd
;
457 if (service
->connections
) {
458 struct connection
*c
;
460 for (c
= service
->connections
; c
; c
= c
->next
) {
461 /* check for activity on the connection */
462 FD_SET(c
->fd
, &read_fds
);
472 /* we're just polling this iteration, this is faster on embedded
475 retval
= socket_select(fd_max
+ 1, &read_fds
, NULL
, NULL
, &tv
);
477 /* Timeout socket_select() when a target timer expires or every polling_period */
478 int timeout_ms
= next_event
- timeval_ms();
481 else if (timeout_ms
> polling_period
)
482 timeout_ms
= polling_period
;
483 tv
.tv_usec
= timeout_ms
* 1000;
484 /* Only while we're sleeping we'll let others run */
485 retval
= socket_select(fd_max
+ 1, &read_fds
, NULL
, NULL
, &tv
);
491 errno
= WSAGetLastError();
493 if (errno
== WSAEINTR
)
496 LOG_ERROR("error during select: %s", strerror(errno
));
504 LOG_ERROR("error during select: %s", strerror(errno
));
511 /* Execute callbacks of expired timers when
512 * - there was nothing to do if poll_ok was true
513 * - socket_select() timed out if poll_ok was false, now one or more
514 * timers expired or the polling period elapsed
516 target_call_timer_callbacks();
517 next_event
= target_timer_next_event();
518 process_jim_events(command_context
);
520 FD_ZERO(&read_fds
); /* eCos leaves read_fds unchanged in this case! */
522 /* We timed out/there was nothing to do, timeout rather than poll next time
526 /* There was something to do, next time we'll just poll */
530 /* This is a simple back-off algorithm where we immediately
531 * re-poll if we did something this time around.
533 * This greatly improves performance of DCC.
535 poll_ok
= poll_ok
|| target_got_message();
537 for (service
= services
; service
; service
= service
->next
) {
538 /* handle new connections on listeners */
539 if ((service
->fd
!= -1)
540 && (FD_ISSET(service
->fd
, &read_fds
))) {
541 if (service
->max_connections
!= 0)
542 add_connection(service
, command_context
);
544 if (service
->type
== CONNECTION_TCP
) {
545 struct sockaddr_in sin
;
546 socklen_t address_size
= sizeof(sin
);
548 tmp_fd
= accept(service
->fd
,
549 (struct sockaddr
*)&service
->sin
,
551 close_socket(tmp_fd
);
554 "rejected '%s' connection, no more connections allowed",
559 /* handle activity on connections */
560 if (service
->connections
) {
561 struct connection
*c
;
563 for (c
= service
->connections
; c
; ) {
564 if ((c
->fd
>= 0 && FD_ISSET(c
->fd
, &read_fds
)) || c
->input_pending
) {
565 retval
= service
->input(c
);
566 if (retval
!= ERROR_OK
) {
567 struct connection
*next
= c
->next
;
568 if (service
->type
== CONNECTION_PIPE
||
569 service
->type
== CONNECTION_STDINOUT
) {
570 /* if connection uses a pipe then
571 * shutdown openocd on error */
572 shutdown_openocd
= SHUTDOWN_REQUESTED
;
574 remove_connection(service
, c
);
575 LOG_INFO("dropped '%s' connection",
588 while (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
589 if (msg
.message
== WM_QUIT
)
590 shutdown_openocd
= SHUTDOWN_WITH_SIGNAL_CODE
;
595 /* when quit for signal or CTRL-C, run (eventually user implemented) "shutdown" */
596 if (shutdown_openocd
== SHUTDOWN_WITH_SIGNAL_CODE
)
597 command_run_line(command_context
, "shutdown");
599 return shutdown_openocd
== SHUTDOWN_WITH_ERROR_CODE
? ERROR_FAIL
: ERROR_OK
;
602 static void sig_handler(int sig
)
604 /* store only first signal that hits us */
605 if (shutdown_openocd
== CONTINUE_MAIN_LOOP
) {
606 shutdown_openocd
= SHUTDOWN_WITH_SIGNAL_CODE
;
608 LOG_DEBUG("Terminating on Signal %d", sig
);
610 LOG_DEBUG("Ignored extra Signal %d", sig
);
615 BOOL WINAPI
control_handler(DWORD ctrl_type
)
617 shutdown_openocd
= SHUTDOWN_WITH_SIGNAL_CODE
;
621 static void sigkey_handler(int sig
)
623 /* ignore keystroke generated signals if not in foreground process group */
625 if (tcgetpgrp(STDIN_FILENO
) > 0)
628 LOG_DEBUG("Ignored Signal %d", sig
);
633 int server_host_os_entry(void)
635 /* this currently only calls WSAStartup on native win32 systems
636 * before any socket operations are performed.
637 * This is an issue if you call init in your config script */
640 WORD version_requested
;
643 version_requested
= MAKEWORD(2, 2);
645 if (WSAStartup(version_requested
, &wsadata
) != 0) {
646 LOG_ERROR("Failed to Open Winsock");
653 int server_host_os_close(void)
661 int server_preinit(void)
664 /* register ctrl-c handler */
665 SetConsoleCtrlHandler(control_handler
, TRUE
);
667 signal(SIGBREAK
, sig_handler
);
668 signal(SIGINT
, sig_handler
);
670 signal(SIGHUP
, sig_handler
);
671 signal(SIGPIPE
, sig_handler
);
672 signal(SIGQUIT
, sigkey_handler
);
673 signal(SIGINT
, sigkey_handler
);
675 signal(SIGTERM
, sig_handler
);
676 signal(SIGABRT
, sig_handler
);
681 int server_init(struct command_context
*cmd_ctx
)
683 int ret
= tcl_init();
688 ret
= telnet_init("Open On-Chip Debugger");
690 if (ret
!= ERROR_OK
) {
698 int server_quit(void)
704 SetConsoleCtrlHandler(control_handler
, FALSE
);
709 /* return signal number so we can kill ourselves */
713 void server_free(void)
716 telnet_service_free();
723 void exit_on_signal(int sig
)
726 /* bring back default system handler and kill yourself */
727 signal(sig
, SIG_DFL
);
732 int connection_write(struct connection
*connection
, const void *data
, int len
)
735 /* successful no-op. Sockets and pipes behave differently here... */
738 if (connection
->service
->type
== CONNECTION_TCP
)
739 return write_socket(connection
->fd_out
, data
, len
);
741 return write(connection
->fd_out
, data
, len
);
744 int connection_read(struct connection
*connection
, void *data
, int len
)
746 if (connection
->service
->type
== CONNECTION_TCP
)
747 return read_socket(connection
->fd
, data
, len
);
749 return read(connection
->fd
, data
, len
);
752 bool openocd_is_shutdown_pending(void)
754 return shutdown_openocd
!= CONTINUE_MAIN_LOOP
;
757 /* tell the server we want to shut down */
758 COMMAND_HANDLER(handle_shutdown_command
)
760 LOG_USER("shutdown command invoked");
762 shutdown_openocd
= SHUTDOWN_REQUESTED
;
764 command_run_line(CMD_CTX
, "_run_pre_shutdown_commands");
767 if (!strcmp(CMD_ARGV
[0], "error")) {
768 shutdown_openocd
= SHUTDOWN_WITH_ERROR_CODE
;
773 return ERROR_COMMAND_CLOSE_CONNECTION
;
776 COMMAND_HANDLER(handle_poll_period_command
)
779 LOG_WARNING("You need to set a period value");
781 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], polling_period
);
783 LOG_INFO("set servers polling period to %ums", polling_period
);
788 COMMAND_HANDLER(handle_bindto_command
)
792 command_print(CMD
, "bindto name: %s", bindto_name
);
796 bindto_name
= strdup(CMD_ARGV
[0]);
799 return ERROR_COMMAND_SYNTAX_ERROR
;
804 static const struct command_registration server_command_handlers
[] = {
807 .handler
= &handle_shutdown_command
,
810 .help
= "shut the server down",
813 .name
= "poll_period",
814 .handler
= &handle_poll_period_command
,
817 .help
= "set the servers polling period",
821 .handler
= &handle_bindto_command
,
822 .mode
= COMMAND_CONFIG
,
824 .help
= "Specify address by name on which to listen for "
825 "incoming TCP/IP connections",
827 COMMAND_REGISTRATION_DONE
830 int server_register_commands(struct command_context
*cmd_ctx
)
832 int retval
= telnet_register_commands(cmd_ctx
);
833 if (retval
!= ERROR_OK
)
836 retval
= tcl_register_commands(cmd_ctx
);
837 if (retval
!= ERROR_OK
)
840 retval
= jsp_register_commands(cmd_ctx
);
841 if (retval
!= ERROR_OK
)
844 return register_commands(cmd_ctx
, NULL
, server_command_handlers
);
847 COMMAND_HELPER(server_port_command
, unsigned short *out
)
851 command_print(CMD
, "%d", *out
);
856 COMMAND_PARSE_NUMBER(u16
, CMD_ARGV
[0], port
);
861 return ERROR_COMMAND_SYNTAX_ERROR
;
866 COMMAND_HELPER(server_pipe_command
, char **out
)
870 command_print(CMD
, "%s", *out
);
874 if (CMD_CTX
->mode
== COMMAND_EXEC
) {
875 LOG_WARNING("unable to change server port after init");
876 return ERROR_COMMAND_ARGUMENT_INVALID
;
879 *out
= strdup(CMD_ARGV
[0]);
883 return ERROR_COMMAND_SYNTAX_ERROR
;
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)