This is an automated email from Gerrit.

"Antonio Borneo <[email protected]>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/6703

-- gerrit

commit 5cf99c6678d4f5c0affc8dca1fc012af5ed442b4
Author: Antonio Borneo <[email protected]>
Date:   Tue Nov 16 01:44:07 2021 +0100

    [WIP] server: accept connections during keep_alive
    
    GDB requires OpenOCD to reply to the first command within a delay
    of 6 seconds (3x remotetimeout). This is not always possible due
    to OpenOCD simple scheduler.
    
    Reuse the keep_alive() mechanism to sense an incoming connection,
    accept it and, in case of GDB, send keep-alive packets to prevent
    GDB to timeout.
    
    It doesn't work with LLDB, yet.
    
    Change-Id: I4b3418a46f147392a4f965db6c34c6ab1f50926b
    Signed-off-by: Antonio Borneo <[email protected]>

diff --git a/src/helper/command.c b/src/helper/command.c
index 53ee2508a..1e769d719 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -1145,6 +1145,7 @@ COMMAND_HANDLER(handle_sleep_command)
                int64_t then = timeval_ms();
                while (timeval_ms() - then < (int64_t)duration) {
                        target_call_timer_callbacks_now();
+                       keep_alive();
                        usleep(1000);
                }
        } else
diff --git a/src/helper/log.c b/src/helper/log.c
index caa0a66bf..9e0aecee1 100644
--- a/src/helper/log.c
+++ b/src/helper/log.c
@@ -429,6 +429,7 @@ static void gdb_timeout_warning(int64_t delta_time)
                        delta_time);
 }
 
+void handle_keep_alive(void);
 void keep_alive(void)
 {
        current_time = timeval_ms();
@@ -444,6 +445,7 @@ void keep_alive(void)
        if (delta_time > KEEP_ALIVE_KICK_TIME_MS) {
                last_time = current_time;
 
+               handle_keep_alive();
                /* this will keep the GDB connection alive */
                LOG_USER_N("%s", "");
 
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index a16b4ccbe..e1fb158bb 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -960,15 +960,44 @@ static int gdb_target_callback_event_handler(struct 
target *target,
        return ERROR_OK;
 }
 
-static int gdb_new_connection(struct connection *connection)
+static void gdb_log_callback_dummy(void *priv, const char *file, unsigned line,
+               const char *function, const char *string)
 {
-       struct gdb_connection *gdb_connection = malloc(sizeof(struct 
gdb_connection));
+       struct connection *connection = priv;
+
+       /* just send something? not really:
+        * for gdb anything except '$' and '%'
+        * for lldb '+' is not ok */
+       gdb_write(connection, "\n", 1);
+}
+
+static int gdb_new_connection(struct connection *connection, enum 
add_connection_mode mode)
+{
+       struct gdb_connection *gdb_connection;
+
+       if (mode == ADD_CONNECTION_TOP) {
+               gdb_connection = malloc(sizeof(struct gdb_connection));
+               connection->priv = gdb_connection;
+               gdb_connection->closed = false;
+               log_add_callback(gdb_log_callback_dummy, connection);
+               return ERROR_OK;
+       }
+
+       if (mode == ADD_CONNECTION_BOTTOM)
+               log_remove_callback(gdb_log_callback_dummy, connection);
+
+       if (mode == ADD_CONNECTION_FULL) {
+               gdb_connection = malloc(sizeof(struct gdb_connection));
+               connection->priv = gdb_connection;
+               gdb_connection->closed = false;
+       }
+
+       gdb_connection = connection->priv;
        struct target *target;
        int retval;
        int initial_ack;
 
        target = get_target_from_connection(connection);
-       connection->priv = gdb_connection;
        connection->cmd_ctx->current_target = target;
 
        /* initialize gdb connection information */
@@ -977,7 +1006,6 @@ static int gdb_new_connection(struct connection 
*connection)
        gdb_connection->ctrl_c = false;
        gdb_connection->frontend_state = TARGET_HALTED;
        gdb_connection->vflash_image = NULL;
-       gdb_connection->closed = false;
        gdb_connection->busy = false;
        gdb_connection->noack_mode = 0;
        gdb_connection->sync = false;
diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c
index ec2fae8c0..cd324af39 100644
--- a/src/server/ipdbg.c
+++ b/src/server/ipdbg.c
@@ -535,8 +535,11 @@ static int ipdbg_stop_polling(struct ipdbg_service 
*service)
        return ERROR_OK;
 }
 
-static int ipdbg_on_new_connection(struct connection *connection)
+static int ipdbg_on_new_connection(struct connection *connection, enum 
add_connection_mode mode)
 {
+       if (mode == ADD_CONNECTION_TOP)
+               return ERROR_OK;
+
        struct ipdbg_service *service = connection->service->priv;
        connection->priv = &service->connection;
        /* initialize ipdbg connection information */
diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c
index d49e4d000..797eb9245 100644
--- a/src/server/rtt_server.c
+++ b/src/server/rtt_server.c
@@ -58,11 +58,14 @@ static int read_callback(unsigned int channel, const 
uint8_t *buffer,
        return ERROR_OK;
 }
 
-static int rtt_new_connection(struct connection *connection)
+static int rtt_new_connection(struct connection *connection, enum 
add_connection_mode mode)
 {
        int ret;
        struct rtt_service *service;
 
+       if (mode == ADD_CONNECTION_TOP)
+               return ERROR_OK;
+
        service = connection->service->priv;
 
        LOG_DEBUG("rtt: New connection for channel %u", service->channel);
diff --git a/src/server/server.c b/src/server/server.c
index 3f579bfc6..48e0a35fe 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -64,7 +64,95 @@ static int polling_period = 100;
 /* address by name on which to listen for incoming TCP/IP connections */
 static char *bindto_name;
 
-static int add_connection(struct service *service, struct command_context 
*cmd_ctx)
+static int add_connection(struct service *service, struct command_context 
*cmd_ctx,
+               int *new_fd, enum add_connection_mode mode);
+static int remove_connection(struct service *service, struct connection 
*connection);
+
+/* list of fds to listen during keep_alive() */
+static fd_set keep_alive_listen_fds;
+static fd_set keep_alive_accepted_fds;
+static int keep_alive_listen_fd_max;
+static bool keep_alive_accepted;
+static struct command_context *keep_alive_cmd_ctx;
+
+static void prepare_keep_alive(struct command_context *cmd_ctx)
+{
+       /* prepare list of fds for keep_alive() */
+       keep_alive_listen_fd_max = -1;
+       FD_ZERO(&keep_alive_listen_fds);
+       FD_ZERO(&keep_alive_accepted_fds);
+       keep_alive_accepted = false;
+       keep_alive_cmd_ctx = cmd_ctx;
+
+       for (struct service *service = services; service; service = 
service->next) {
+               if (service->fd != -1) {
+                       FD_SET(service->fd, &keep_alive_listen_fds);
+                       if (keep_alive_listen_fd_max < service->fd)
+                               keep_alive_listen_fd_max = service->fd;
+               }
+       }
+}
+
+void handle_keep_alive(void)
+{
+       if (keep_alive_listen_fd_max == -1)
+               return;
+
+       struct timeval tv = {0, 0};
+       fd_set tmp_fds = keep_alive_listen_fds;
+       int retval = socket_select(keep_alive_listen_fd_max + 1, &tmp_fds, 
NULL, NULL, &tv);
+       if (retval <= 0)
+               return;
+
+       for (struct service *service = services; service; service = 
service->next) {
+               /* handle new connections on listeners */
+               if (service->fd != -1 && FD_ISSET(service->fd, &tmp_fds)) {
+                       if (service->max_connections != 0) {
+                               int fd = service->fd;
+                               int new_fd;
+                               retval = add_connection(service, 
keep_alive_cmd_ctx, &new_fd, ADD_CONNECTION_TOP);
+                               if (retval == ERROR_OK) {
+                                       FD_SET(new_fd, 
&keep_alive_accepted_fds);
+                                       keep_alive_accepted = true;
+                               }
+                               if (service->fd == -1)
+                                       FD_CLR(fd, &keep_alive_listen_fds);
+                       } else {
+                               if (service->type == CONNECTION_TCP) {
+                                       struct sockaddr_in sin;
+                                       socklen_t address_size = sizeof(sin);
+                                       int tmp_fd;
+                                       tmp_fd = accept(service->fd,
+                                                       (struct sockaddr 
*)&service->sin,
+                                                       &address_size);
+                                       close_socket(tmp_fd);
+                               }
+                               LOG_INFO("rejected '%s' connection, no more 
connections allowed", service->name);
+                       }
+               }
+       }
+}
+
+static void finalize_keep_alive(void)
+{
+       if (keep_alive_accepted == false)
+               return;
+
+       for (struct service *service = services; service; service = 
service->next) {
+               struct connection *next;
+               for (struct connection *c = service->connections; c; c = next) {
+                       next = c->next;
+                       if (c->fd == -1 || !FD_ISSET(c->fd, 
&keep_alive_accepted_fds))
+                               continue;
+                       int retval = service->new_connection(c, 
ADD_CONNECTION_BOTTOM);
+                       if (retval != ERROR_OK)
+                               remove_connection(service, c);
+               }
+       }
+}
+
+static int add_connection(struct service *service, struct command_context 
*cmd_ctx,
+               int *new_fd, enum add_connection_mode mode)
 {
        socklen_t address_size;
        struct connection *c, **p;
@@ -85,6 +173,8 @@ static int add_connection(struct service *service, struct 
command_context *cmd_c
                address_size = sizeof(c->sin);
 
                c->fd = accept(service->fd, (struct sockaddr *)&service->sin, 
&address_size);
+               if (new_fd)
+                       *new_fd = c->fd;
                c->fd_out = c->fd;
 
                /* This increases performance dramatically for e.g. GDB load 
which
@@ -99,7 +189,7 @@ static int add_connection(struct service *service, struct 
command_context *cmd_c
                        sizeof(int));                   /* length of option 
value */
 
                LOG_INFO("accepting '%s' connection on tcp/%s", service->name, 
service->port);
-               retval = service->new_connection(c);
+               retval = service->new_connection(c, mode);
                if (retval != ERROR_OK) {
                        close_socket(c->fd);
                        LOG_ERROR("attempted '%s' connection rejected", 
service->name);
@@ -109,6 +199,8 @@ static int add_connection(struct service *service, struct 
command_context *cmd_c
                }
        } else if (service->type == CONNECTION_STDINOUT) {
                c->fd = service->fd;
+               if (new_fd)
+                       *new_fd = c->fd;
                c->fd_out = fileno(stdout);
 
 #ifdef _WIN32
@@ -120,7 +212,7 @@ static int add_connection(struct service *service, struct 
command_context *cmd_c
                service->fd = -1;
 
                LOG_INFO("accepting '%s' connection from pipe", service->name);
-               retval = service->new_connection(c);
+               retval = service->new_connection(c, mode);
                if (retval != ERROR_OK) {
                        LOG_ERROR("attempted '%s' connection rejected", 
service->name);
                        command_done(c->cmd_ctx);
@@ -129,6 +221,8 @@ static int add_connection(struct service *service, struct 
command_context *cmd_c
                }
        } else if (service->type == CONNECTION_PIPE) {
                c->fd = service->fd;
+               if (new_fd)
+                       *new_fd = c->fd;
                /* do not check for new connections again on stdin */
                service->fd = -1;
 
@@ -143,7 +237,7 @@ static int add_connection(struct service *service, struct 
command_context *cmd_c
                }
 
                LOG_INFO("accepting '%s' connection from pipe %s", 
service->name, service->port);
-               retval = service->new_connection(c);
+               retval = service->new_connection(c, mode);
                if (retval != ERROR_OK) {
                        LOG_ERROR("attempted '%s' connection rejected", 
service->name);
                        command_done(c->cmd_ctx);
@@ -544,7 +638,7 @@ int server_loop(struct command_context *command_context)
                        if ((service->fd != -1)
                                && (FD_ISSET(service->fd, &read_fds))) {
                                if (service->max_connections != 0)
-                                       add_connection(service, 
command_context);
+                                       add_connection(service, 
command_context, NULL, ADD_CONNECTION_FULL);
                                else {
                                        if (service->type == CONNECTION_TCP) {
                                                struct sockaddr_in sin;
@@ -561,6 +655,8 @@ int server_loop(struct command_context *command_context)
                                }
                        }
 
+                       prepare_keep_alive(command_context);
+
                        /* handle activity on connections */
                        if (service->connections) {
                                struct connection *c;
@@ -586,6 +682,8 @@ int server_loop(struct command_context *command_context)
                                        c = c->next;
                                }
                        }
+
+                       finalize_keep_alive();
                }
 
 #ifdef _WIN32
diff --git a/src/server/server.h b/src/server/server.h
index de18d2b4b..cd3102ac1 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -42,6 +42,12 @@ enum connection_type {
        CONNECTION_STDINOUT
 };
 
+enum add_connection_mode {
+       ADD_CONNECTION_FULL,
+       ADD_CONNECTION_TOP,
+       ADD_CONNECTION_BOTTOM,
+};
+
 #define CONNECTION_LIMIT_UNLIMITED             (-1)
 
 struct connection {
@@ -55,7 +61,7 @@ struct connection {
        struct connection *next;
 };
 
-typedef int (*new_connection_handler_t)(struct connection *connection);
+typedef int (*new_connection_handler_t)(struct connection *connection, enum 
add_connection_mode mode);
 typedef int (*input_handler_t)(struct connection *connection);
 typedef int (*connection_closed_handler_t)(struct connection *connection);
 
diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c
index e08823224..c1822e14d 100644
--- a/src/server/tcl_server.c
+++ b/src/server/tcl_server.c
@@ -42,7 +42,7 @@ struct tcl_connection {
 static char *tcl_port;
 
 /* handlers */
-static int tcl_new_connection(struct connection *connection);
+static int tcl_new_connection(struct connection *connection, enum 
add_connection_mode mode);
 static int tcl_input(struct connection *connection);
 static int tcl_output(struct connection *connection, const void *buf, ssize_t 
len);
 static int tcl_closed(struct connection *connection);
@@ -140,10 +140,13 @@ int tcl_output(struct connection *connection, const void 
*data, ssize_t len)
 }
 
 /* connections */
-static int tcl_new_connection(struct connection *connection)
+static int tcl_new_connection(struct connection *connection, enum 
add_connection_mode mode)
 {
        struct tcl_connection *tclc;
 
+       if (mode == ADD_CONNECTION_TOP)
+               return ERROR_OK;
+
        tclc = calloc(1, sizeof(struct tcl_connection));
        if (!tclc)
                return ERROR_CONNECTION_REJECTED;
diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c
index 2ebcff163..7ccf6605c 100644
--- a/src/server/telnet_server.c
+++ b/src/server/telnet_server.c
@@ -218,8 +218,11 @@ static void telnet_save_history(struct telnet_connection 
*t_con)
        free(history);
 }
 
-static int telnet_new_connection(struct connection *connection)
+static int telnet_new_connection(struct connection *connection, enum 
add_connection_mode mode)
 {
+       if (mode == ADD_CONNECTION_TOP)
+               return ERROR_OK;
+
        struct telnet_connection *telnet_connection;
        struct telnet_service *telnet_service = connection->service->priv;
        int i;
diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c
index 024521364..ef02d4a9e 100644
--- a/src/target/arm_tpiu_swo.c
+++ b/src/target/arm_tpiu_swo.c
@@ -241,8 +241,11 @@ int arm_tpiu_swo_cleanup_all(void)
        return ERROR_OK;
 }
 
-static int arm_tpiu_swo_service_new_connection(struct connection *connection)
+static int arm_tpiu_swo_service_new_connection(struct connection *connection, 
enum add_connection_mode mode)
 {
+       if (mode == ADD_CONNECTION_TOP)
+               return ERROR_OK;
+
        struct arm_tpiu_swo_priv_connection *priv = connection->service->priv;
        struct arm_tpiu_swo_object *obj = priv->obj;
        struct arm_tpiu_swo_connection *c = malloc(sizeof(*c));
diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c
index e0a4475cf..f5ede28fe 100644
--- a/src/target/openrisc/jsp_server.c
+++ b/src/target/openrisc/jsp_server.c
@@ -77,8 +77,11 @@ static int jsp_poll_read(void *priv)
        return ERROR_OK;
 }
 
-static int jsp_new_connection(struct connection *connection)
+static int jsp_new_connection(struct connection *connection, enum 
add_connection_mode mode)
 {
+       if (mode == ADD_CONNECTION_TOP)
+               return ERROR_OK;
+
        struct telnet_connection *telnet_connection = malloc(sizeof(struct 
telnet_connection));
        struct jsp_service *jsp_service = connection->service->priv;
 

-- 

Reply via email to