mirror of
https://github.com/openocd-org/openocd.git
synced 2026-10-12 02:20:28 +00:00
server: add 'services' command to list service information
This addes a 'services' command which outputs a TCL list
where each entry is a TCL dict containing information about
the service.
This allows obtaining the actual TCP port used when the
requested port is 0. Tested with the following script:
adapter driver dummy
gdb port 0
jtag newtap tap cpu -irlen 5
target create tap.cpu riscv -chain-position tap.cpu
init
echo [services]
shutdown
Output is:
...
Info : [tap.cpu] starting gdb server on 0
Info : Listening on port 53811 for gdb connections
{
name gdb
port 53811
target tap.cpu
}
Change-Id: I29bc2d352c0058f8b6a1c4296345f9ece4fbe03f
Signed-off-by: Tim Hutt <[email protected]>
Reviewed-on: https://review.openocd.org/c/openocd/+/9535
Tested-by: jenkins
Reviewed-by: Evgeniy Naydanov <[email protected]>
Reviewed-by: Antonio Borneo <[email protected]>
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <helper/tcl-common.h>
|
||||
#include <target/breakpoints.h>
|
||||
#include <target/target_request.h>
|
||||
#include <target/register.h>
|
||||
@@ -3913,6 +3914,20 @@ static void gdb_keep_client_alive(struct connection *connection)
|
||||
}
|
||||
}
|
||||
|
||||
static COMMAND_HELPER(gdb_service_info, const struct service *service)
|
||||
{
|
||||
struct gdb_service *gdb_service = service->priv;
|
||||
|
||||
char *cmd_name = tcl_escape_alloc(CMD_CTX->interp, gdb_service->target->cmd_name);
|
||||
if (!cmd_name) {
|
||||
LOG_ERROR("Unable to escape Tcl string");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
command_print(cmd, " target %s", cmd_name);
|
||||
free(cmd_name);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct service_driver gdb_service_driver = {
|
||||
.name = "gdb",
|
||||
.new_connection_during_keep_alive_handler = NULL,
|
||||
@@ -3920,6 +3935,7 @@ static const struct service_driver gdb_service_driver = {
|
||||
.input_handler = gdb_input,
|
||||
.connection_closed_handler = gdb_connection_closed,
|
||||
.keep_client_alive_handler = gdb_keep_client_alive,
|
||||
.service_info_handler = gdb_service_info,
|
||||
};
|
||||
|
||||
static int gdb_target_start(struct target *target, const char *port)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#endif
|
||||
|
||||
#include "server.h"
|
||||
#include <helper/tcl-common.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <target/target.h>
|
||||
#include <target/target_request.h>
|
||||
@@ -231,6 +232,7 @@ int add_service(const struct service_driver *driver, const char *port,
|
||||
c->connection_closed = driver->connection_closed_handler;
|
||||
c->keep_client_alive = driver->keep_client_alive_handler;
|
||||
c->service_dtor = driver->service_dtor_handler;
|
||||
c->service_info = driver->service_info_handler;
|
||||
c->priv = priv;
|
||||
c->next = NULL;
|
||||
|
||||
@@ -873,6 +875,51 @@ COMMAND_HANDLER(handle_bindto_command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_services_command)
|
||||
{
|
||||
if (CMD_ARGC != 0)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
for (const struct service *s = services; s; s = s->next) {
|
||||
command_print(CMD, "{");
|
||||
|
||||
/* Escape the name in case it contains special characters. */
|
||||
char *escaped_name = tcl_escape_alloc(CMD_CTX->interp, s->name);
|
||||
if (!escaped_name) {
|
||||
command_print(CMD, "Unable to escape Tcl string");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
command_print(CMD, " name %s", escaped_name);
|
||||
free(escaped_name);
|
||||
|
||||
struct sockaddr_in addr_in;
|
||||
addr_in.sin_port = 0;
|
||||
socklen_t addr_in_size = sizeof(addr_in);
|
||||
/* If it's a TCP connection and they specified port 0 try to get the real port. */
|
||||
if (s->type == CONNECTION_TCP &&
|
||||
s->portnumber == 0 &&
|
||||
getsockname(s->fd, (struct sockaddr *)&addr_in, &addr_in_size) == 0) {
|
||||
command_print(CMD, " port %hu", ntohs(addr_in.sin_port));
|
||||
} else {
|
||||
/* Need to escape port because it could be a FIFO path which is
|
||||
* allowed to contain basically any character. */
|
||||
char *escaped_port = tcl_escape_alloc(CMD_CTX->interp, s->port);
|
||||
if (!escaped_port) {
|
||||
command_print(CMD, "Unable to escape Tcl string");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
command_print(CMD, " port %s", escaped_port);
|
||||
free(escaped_port);
|
||||
}
|
||||
|
||||
if (s->service_info)
|
||||
CALL_COMMAND_HANDLER(s->service_info, s);
|
||||
|
||||
command_print(CMD, "}");
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration server_command_handlers[] = {
|
||||
{
|
||||
.name = "shutdown",
|
||||
@@ -903,6 +950,13 @@ static const struct command_registration server_command_handlers[] = {
|
||||
.help = "Specify address by name on which to listen for "
|
||||
"incoming TCP/IP connections",
|
||||
},
|
||||
{
|
||||
.name = "services",
|
||||
.handler = &handle_services_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.usage = "",
|
||||
.help = "return information about running services"
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ struct service_driver {
|
||||
/** callback to handle incoming data */
|
||||
int (*input_handler)(struct connection *connection);
|
||||
void (*service_dtor_handler)(struct service *service);
|
||||
/** Callback to provide more details for the `services` command. */
|
||||
COMMAND_HELPER((*service_info_handler), const struct service *service);
|
||||
/** callback to tear down the connection */
|
||||
int (*connection_closed_handler)(struct connection *connection);
|
||||
/** called periodically to send keep-alive messages on the connection */
|
||||
@@ -68,7 +70,12 @@ struct service_driver {
|
||||
struct service {
|
||||
char *name;
|
||||
enum connection_type type;
|
||||
/**
|
||||
* The 'port', which can be an integer for TCP, or 'disabled',
|
||||
* 'pipe' (stdin/out) or a FIFO path.
|
||||
*/
|
||||
char *port;
|
||||
/** If port is an integer it is parsed and saved here. */
|
||||
unsigned short portnumber;
|
||||
int fd;
|
||||
struct sockaddr_in sin;
|
||||
@@ -78,6 +85,7 @@ struct service {
|
||||
int (*new_connection)(struct connection *connection);
|
||||
int (*input)(struct connection *connection);
|
||||
void (*service_dtor)(struct service *service);
|
||||
COMMAND_HELPER((*service_info), const struct service *service);
|
||||
int (*connection_closed)(struct connection *connection);
|
||||
void (*keep_client_alive)(struct connection *connection);
|
||||
void *priv;
|
||||
|
||||
Reference in New Issue
Block a user