aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android-commands.h33
-rw-r--r--android-console.c216
-rw-r--r--android-console.h4
3 files changed, 253 insertions, 0 deletions
diff --git a/android-commands.h b/android-commands.h
index a8a9075897..45b6c1d447 100644
--- a/android-commands.h
+++ b/android-commands.h
@@ -1,5 +1,30 @@
/* hand-written for now; consider .hx autogen */
+static mon_cmd_t android_redir_cmds[] = {
+ {
+ .name = "list",
+ .args_type = "",
+ .params = "",
+ .help = "list current redirections",
+ .mhandler.cmd = android_console_redir_list,
+ },
+ {
+ .name = "add",
+ .args_type = "arg:s",
+ .params = "[tcp|udp]:hostport:guestport",
+ .help = "add new redirection",
+ .mhandler.cmd = android_console_redir_add,
+ },
+ {
+ .name = "del",
+ .args_type = "arg:s",
+ .params = "[tcp|udp]:hostport",
+ .help = "remove existing redirection",
+ .mhandler.cmd = android_console_redir_del,
+ },
+ { NULL, NULL, },
+};
+
static mon_cmd_t android_cmds[] = {
{
.name = "help|h|?",
@@ -15,5 +40,13 @@ static mon_cmd_t android_cmds[] = {
.help = "kill the emulator instance",
.mhandler.cmd = android_console_kill,
},
+ {
+ .name = "redir",
+ .args_type = "item:s?",
+ .params = "",
+ .help = "manage port redirections",
+ .mhandler.cmd = android_console_redir,
+ .sub_table = android_redir_cmds,
+ },
{ NULL, NULL, },
};
diff --git a/android-console.c b/android-console.c
index 9bc2ad4dd2..42ada96730 100644
--- a/android-console.c
+++ b/android-console.c
@@ -22,9 +22,225 @@
#include "slirp/libslirp.h"
#include "qmp-commands.h"
+typedef struct {
+ int is_udp;
+ int host_port;
+ int guest_port;
+} RedirRec;
+
+GList *redir_list;
+
void android_console_kill(Monitor *mon, const QDict *qdict)
{
monitor_printf(mon, "OK: killing emulator, bye bye\n");
monitor_suspend(mon);
qmp_quit(NULL);
}
+
+#ifdef CONFIG_SLIRP
+void android_console_redir_list(Monitor *mon, const QDict *qdict)
+{
+ if (!redir_list) {
+ monitor_printf(mon, "no active redirections\n");
+ } else {
+ GList *l;
+
+ for (l = redir_list; l; l = l->next) {
+ RedirRec *r = l->data;
+
+ monitor_printf(mon, "%s:%-5d => %-5d\n", r->is_udp ? "udp" : "tcp",
+ r->host_port, r->guest_port);
+ }
+ }
+ monitor_printf(mon, "OK\n");
+}
+
+static int parse_proto(const char *s)
+{
+ if (!strcmp(s, "tcp")) {
+ return 0;
+ } else if (!strcmp(s, "udp")) {
+ return 1;
+ } else {
+ return -1;
+ }
+}
+
+static int parse_port(const char *s)
+{
+ char *end;
+ int port;
+
+ port = strtol(s, &end, 10);
+ if (*end != 0 || port < 1 || port > 65535) {
+ return 0;
+ }
+ return port;
+}
+
+void android_console_redir_add(Monitor *mon, const QDict *qdict)
+{
+ const char *arg = qdict_get_str(qdict, "arg");
+ char **tokens;
+ int is_udp, host_port, guest_port;
+ Slirp *slirp;
+ Error *err = NULL;
+ struct in_addr host_addr = { .s_addr = htonl(INADDR_LOOPBACK) };
+ struct in_addr guest_addr = { .s_addr = 0 };
+ RedirRec *redir;
+
+ slirp = net_slirp_lookup(NULL, NULL, &err);
+ if (err) {
+ monitor_printf(mon, "KO: %s\n", error_get_pretty(err));
+ error_free(err);
+ return;
+ }
+
+ /* Argument syntax: "proto:hostport:guestport" */
+ tokens = g_strsplit(arg, ":", 0);
+
+ if (g_strv_length(tokens) != 3) {
+ goto fail_syntax;
+ }
+
+ is_udp = parse_proto(tokens[0]);
+ host_port = parse_port(tokens[1]);
+ guest_port = parse_port(tokens[2]);
+
+ if (is_udp < 0 || host_port == 0 || guest_port == 0) {
+ goto fail_syntax;
+ }
+
+ g_strfreev(tokens);
+
+ if (slirp_add_hostfwd(slirp, is_udp, host_addr, host_port,
+ guest_addr, guest_port) < 0) {
+ monitor_printf(mon, "KO: can't setup redirection, "
+ "port probably used by another program on host\n");
+ return;
+ }
+
+ redir = g_new0(RedirRec, 1);
+ redir->is_udp = is_udp;
+ redir->host_port = host_port;
+ redir->guest_port = guest_port;
+ redir_list = g_list_append(redir_list, redir);
+
+ monitor_printf(mon, "OK\n");
+ return;
+
+fail_syntax:
+ monitor_printf(mon, "KO: bad redirection format, try "
+ "(tcp|udp):hostport:guestport\n");
+ g_strfreev(tokens);
+}
+
+static gint redir_cmp(gconstpointer a, gconstpointer b)
+{
+ const RedirRec *ra = a;
+ const RedirRec *rb = b;
+
+ /* For purposes of list deletion, only protocol and host port matter */
+ if (ra->is_udp != rb->is_udp) {
+ return ra->is_udp - rb->is_udp;
+ }
+ return ra->host_port - rb->host_port;
+}
+
+void android_console_redir_del(Monitor *mon, const QDict *qdict)
+{
+ const char *arg = qdict_get_str(qdict, "arg");
+ char **tokens;
+ int is_udp, host_port;
+ Slirp *slirp;
+ Error *err = NULL;
+ struct in_addr host_addr = { .s_addr = INADDR_ANY };
+ RedirRec rr;
+ GList *entry;
+
+ slirp = net_slirp_lookup(NULL, NULL, &err);
+ if (err) {
+ monitor_printf(mon, "KO: %s\n", error_get_pretty(err));
+ error_free(err);
+ return;
+ }
+
+ /* Argument syntax: "proto:hostport" */
+ tokens = g_strsplit(arg, ":", 0);
+
+ if (g_strv_length(tokens) != 2) {
+ goto fail_syntax;
+ }
+
+ is_udp = parse_proto(tokens[0]);
+ host_port = parse_port(tokens[1]);
+
+ if (is_udp < 0 || host_port == 0) {
+ goto fail_syntax;
+ }
+
+ g_strfreev(tokens);
+
+ rr.is_udp = is_udp;
+ rr.host_port = host_port;
+ entry = g_list_find_custom(redir_list, &rr, redir_cmp);
+
+ if (!entry || slirp_remove_hostfwd(slirp, is_udp, host_addr, host_port)) {
+ monitor_printf(mon, "KO: can't remove unknown redirection (%s:%d)\n",
+ is_udp ? "udp" : "tcp", host_port);
+ return;
+ }
+
+ g_free(entry->data);
+ redir_list = g_list_delete_link(redir_list, entry);
+
+ monitor_printf(mon, "OK\n");
+ return;
+
+fail_syntax:
+ monitor_printf(mon, "KO: bad redirection format, try (tcp|udp):hostport\n");
+ g_strfreev(tokens);
+}
+
+#else /* not CONFIG_SLIRP */
+void android_console_redir_list(Monitor *mon, const QDict *qdict)
+{
+ monitor_printf(mon, "KO: emulator not built with CONFIG_SLIRP\n");
+}
+
+void android_console_redir_add(Monitor *mon, const QDict *qdict)
+{
+ monitor_printf(mon, "KO: emulator not built with CONFIG_SLIRP\n");
+}
+
+void android_console_redir_remove(Monitor *mon, const QDict *qdict)
+{
+ monitor_printf(mon, "KO: emulator not built with CONFIG_SLIRP\n");
+}
+#endif
+
+void android_console_redir(Monitor *mon, const QDict *qdict)
+{
+ const char *arg = qdict_get_try_str(qdict, "arg");
+
+ if (!arg) {
+ goto fail;
+ }
+
+ monitor_printf(mon, "redir: arg %s\n", arg);
+ return;
+
+fail:
+ monitor_printf(mon, "allows you to add, list and remove and/or "
+ "PORT redirection from the host to the device\n"
+ "as an example, 'redir tcp:5000:6000' will route "
+ "any packet sent to the host's TCP port 5000\n"
+ "to TCP port 6000 of the emulated device\n"
+ "\n"
+ "available sub-commands:\n"
+ " list list current redirections\n"
+ " add add new redirection\n"
+ " del remove existing redirection\n"
+ "\n"
+ "KO: missing sub-command\n");
+}
diff --git a/android-console.h b/android-console.h
index 7aa183489c..26c82505c5 100644
--- a/android-console.h
+++ b/android-console.h
@@ -22,5 +22,9 @@
#include "qemu-common.h"
void android_console_kill(Monitor *mon, const QDict *qdict);
+void android_console_redir(Monitor *mon, const QDict *qdict);
+void android_console_redir_list(Monitor *mon, const QDict *qdict);
+void android_console_redir_add(Monitor *mon, const QDict *qdict);
+void android_console_redir_del(Monitor *mon, const QDict *qdict);
#endif