#endif
#include "server.h"
+#include <helper/time_support.h>
#include <target/target.h>
#include <target/target_request.h>
#include <target/openrisc/jsp_server.h>
static struct service *services;
-/* shutdown_openocd == 1: exit the main event loop, and quit the
- * debugger; 2: quit with non-zero return code */
-static int shutdown_openocd;
+enum shutdown_reason {
+ CONTINUE_MAIN_LOOP, /* stay in main event loop */
+ SHUTDOWN_REQUESTED, /* set by shutdown command; exit the event loop and quit the debugger */
+ SHUTDOWN_WITH_ERROR_CODE, /* set by shutdown command; quit with non-zero return code */
+ SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */
+};
+static enum shutdown_reason shutdown_openocd = CONTINUE_MAIN_LOOP;
/* store received signal to exit application by killing ourselves */
static int last_signal;
memset(&c->sin, 0, sizeof(c->sin));
c->cmd_ctx = copy_command_context(cmd_ctx);
c->service = service;
- c->input_pending = 0;
+ c->input_pending = false;
c->priv = NULL;
c->next = NULL;
memset(&c->sin, 0, sizeof(c->sin));
c->sin.sin_family = AF_INET;
- if (bindto_name == NULL)
- c->sin.sin_addr.s_addr = INADDR_ANY;
+ if (!bindto_name)
+ c->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else {
hp = gethostbyname(bindto_name);
- if (hp == NULL) {
+ if (!hp) {
LOG_ERROR("couldn't resolve bindto address: %s", bindto_name);
close_socket(c->fd);
free_service(c);
c->sin.sin_port = htons(c->portnumber);
if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) {
- LOG_ERROR("couldn't bind %s to socket: %s", name, strerror(errno));
+ LOG_ERROR("couldn't bind %s to socket on port %d: %s", name, c->portnumber, strerror(errno));
close_socket(c->fd);
free_service(c);
return ERROR_FAIL;
free_service(c);
return ERROR_FAIL;
}
+
+ struct sockaddr_in addr_in;
+ addr_in.sin_port = 0;
+ socklen_t addr_in_size = sizeof(addr_in);
+ if (getsockname(c->fd, (struct sockaddr *)&addr_in, &addr_in_size) == 0)
+ LOG_INFO("Listening on port %hu for %s connections",
+ ntohs(addr_in.sin_port), name);
} else if (c->type == CONNECTION_STDINOUT) {
c->fd = fileno(stdin);
#endif
} else if (c->type == CONNECTION_PIPE) {
#ifdef _WIN32
- /* we currenty do not support named pipes under win32
+ /* we currently do not support named pipes under win32
* so exit openocd for now */
LOG_ERROR("Named pipes currently not supported under this os");
free_service(c);
return ERROR_OK;
}
+static void remove_connections(struct service *service)
+{
+ struct connection *connection;
+
+ connection = service->connections;
+
+ while (connection) {
+ struct connection *tmp;
+
+ tmp = connection->next;
+ remove_connection(service, connection);
+ connection = tmp;
+ }
+}
+
+int remove_service(const char *name, const char *port)
+{
+ struct service *tmp;
+ struct service *prev;
+
+ prev = services;
+
+ for (tmp = services; tmp; prev = tmp, tmp = tmp->next) {
+ if (!strcmp(tmp->name, name) && !strcmp(tmp->port, port)) {
+ remove_connections(tmp);
+
+ if (tmp == services)
+ services = tmp->next;
+ else
+ prev->next = tmp->next;
+
+ if (tmp->type != CONNECTION_STDINOUT)
+ close_socket(tmp->fd);
+
+ free(tmp->priv);
+ free_service(tmp);
+
+ return ERROR_OK;
+ }
+ }
+
+ return ERROR_OK;
+}
+
static int remove_services(void)
{
struct service *c = services;
while (c) {
struct service *next = c->next;
- if (c->name)
- free(c->name);
+ remove_connections(c);
+
+ free(c->name);
if (c->type == CONNECTION_PIPE) {
if (c->fd != -1)
close(c->fd);
}
- if (c->port)
- free(c->port);
-
- if (c->priv)
- free(c->priv);
-
+ free(c->port);
+ free(c->priv);
/* delete service */
free(c);
/* used in accept() */
int retval;
+ int64_t next_event = timeval_ms() + polling_period;
+
#ifndef _WIN32
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
#endif
- while (!shutdown_openocd) {
+ while (shutdown_openocd == CONTINUE_MAIN_LOOP) {
/* monitor sockets for activity */
fd_max = 0;
FD_ZERO(&read_fds);
retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
} else {
/* Every 100ms, can be changed with "poll_period" command */
- tv.tv_usec = polling_period * 1000;
+ int timeout_ms = next_event - timeval_ms();
+ if (timeout_ms < 0)
+ timeout_ms = 0;
+ else if (timeout_ms > polling_period)
+ timeout_ms = polling_period;
+ tv.tv_usec = timeout_ms * 1000;
/* Only while we're sleeping we'll let others run */
openocd_sleep_prelude();
kept_alive();
if (retval == 0) {
/* We only execute these callbacks when there was nothing to do or we timed
*out */
- target_call_timer_callbacks();
+ target_call_timer_callbacks_now();
+ next_event = target_timer_next_event();
process_jim_events(command_context);
FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
for (service = services; service; service = service->next) {
/* handle new connections on listeners */
if ((service->fd != -1)
- && (FD_ISSET(service->fd, &read_fds))) {
+ && (FD_ISSET(service->fd, &read_fds))) {
if (service->max_connections != 0)
add_connection(service, command_context);
else {
struct connection *c;
for (c = service->connections; c; ) {
- if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) {
+ if ((c->fd >= 0 && FD_ISSET(c->fd, &read_fds)) || c->input_pending) {
retval = service->input(c);
if (retval != ERROR_OK) {
struct connection *next = c->next;
service->type == CONNECTION_STDINOUT) {
/* if connection uses a pipe then
* shutdown openocd on error */
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_REQUESTED;
}
remove_connection(service, c);
LOG_INFO("dropped '%s' connection",
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
}
#endif
}
- return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL;
+ /* when quit for signal or CTRL-C, run (eventually user implemented) "shutdown" */
+ if (shutdown_openocd == SHUTDOWN_WITH_SIGNAL_CODE)
+ command_run_line(command_context, "shutdown");
+
+ return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK;
+}
+
+static void sig_handler(int sig)
+{
+ /* store only first signal that hits us */
+ if (shutdown_openocd == CONTINUE_MAIN_LOOP) {
+ shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
+ last_signal = sig;
+ LOG_DEBUG("Terminating on Signal %d", sig);
+ } else
+ LOG_DEBUG("Ignored extra Signal %d", sig);
}
+
#ifdef _WIN32
-BOOL WINAPI ControlHandler(DWORD dwCtrlType)
+BOOL WINAPI control_handler(DWORD ctrl_type)
{
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
return TRUE;
}
-#endif
-
-void sig_handler(int sig)
+#else
+static void sigkey_handler(int sig)
{
- /* store only first signal that hits us */
- if (!last_signal)
- last_signal = sig;
- shutdown_openocd = 1;
+ /* ignore keystroke generated signals if not in foreground process group */
+
+ if (tcgetpgrp(STDIN_FILENO) > 0)
+ sig_handler(sig);
+ else
+ LOG_DEBUG("Ignored Signal %d", sig);
}
+#endif
-int server_preinit(void)
+
+int server_host_os_entry(void)
{
/* this currently only calls WSAStartup on native win32 systems
* before any socket operations are performed.
* This is an issue if you call init in your config script */
#ifdef _WIN32
- WORD wVersionRequested;
- WSADATA wsaData;
+ WORD version_requested;
+ WSADATA wsadata;
- wVersionRequested = MAKEWORD(2, 2);
+ version_requested = MAKEWORD(2, 2);
- if (WSAStartup(wVersionRequested, &wsaData) != 0) {
+ if (WSAStartup(version_requested, &wsadata) != 0) {
LOG_ERROR("Failed to Open Winsock");
return ERROR_FAIL;
}
+#endif
+ return ERROR_OK;
+}
+
+int server_host_os_close(void)
+{
+#ifdef _WIN32
+ WSACleanup();
+#endif
+ return ERROR_OK;
+}
+int server_preinit(void)
+{
+#ifdef _WIN32
/* register ctrl-c handler */
- SetConsoleCtrlHandler(ControlHandler, TRUE);
+ SetConsoleCtrlHandler(control_handler, TRUE);
signal(SIGBREAK, sig_handler);
-#endif
signal(SIGINT, sig_handler);
+#else
+ signal(SIGHUP, sig_handler);
+ signal(SIGPIPE, sig_handler);
+ signal(SIGQUIT, sigkey_handler);
+ signal(SIGINT, sigkey_handler);
+#endif
signal(SIGTERM, sig_handler);
signal(SIGABRT, sig_handler);
target_quit();
#ifdef _WIN32
- WSACleanup();
- SetConsoleCtrlHandler(ControlHandler, FALSE);
+ SetConsoleCtrlHandler(control_handler, FALSE);
return ERROR_OK;
#endif
return last_signal;
}
+void server_free(void)
+{
+ tcl_service_free();
+ telnet_service_free();
+ jsp_service_free();
+
+ free(bindto_name);
+}
+
void exit_on_signal(int sig)
{
#ifndef _WIN32
{
LOG_USER("shutdown command invoked");
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_REQUESTED;
if (CMD_ARGC == 1) {
if (!strcmp(CMD_ARGV[0], "error")) {
- shutdown_openocd = 2;
+ shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE;
return ERROR_FAIL;
}
}
{
switch (CMD_ARGC) {
case 0:
- command_print(CMD_CTX, "bindto name: %s", bindto_name);
+ command_print(CMD, "bindto name: %s", bindto_name);
break;
case 1:
free(bindto_name);
{
.name = "bindto",
.handler = &handle_bindto_command,
- .mode = COMMAND_ANY,
+ .mode = COMMAND_CONFIG,
.usage = "[name]",
.help = "Specify address by name on which to listen for "
- "incoming TCP/IP connections",
+ "incoming TCP/IP connections",
},
COMMAND_REGISTRATION_DONE
};
int server_register_commands(struct command_context *cmd_ctx)
{
int retval = telnet_register_commands(cmd_ctx);
- if (ERROR_OK != retval)
+ if (retval != ERROR_OK)
return retval;
retval = tcl_register_commands(cmd_ctx);
- if (ERROR_OK != retval)
+ if (retval != ERROR_OK)
return retval;
retval = jsp_register_commands(cmd_ctx);
- if (ERROR_OK != retval)
+ if (retval != ERROR_OK)
return retval;
return register_commands(cmd_ctx, NULL, server_command_handlers);
{
switch (CMD_ARGC) {
case 0:
- command_print(CMD_CTX, "%d", *out);
+ command_print(CMD, "%d", *out);
break;
case 1:
{
{
switch (CMD_ARGC) {
case 0:
- command_print(CMD_CTX, "%s", *out);
+ command_print(CMD, "%s", *out);
break;
case 1:
{