glue: Proper support for -http-proxy option.
This adds the required glue code to make -http-proxy option
work, by injecting the AndroidEmu HTTP proxy implementation
into the SLIRP stack at emulation setup time.
+ Remove -http-proxy from the list of QEMU2 options, it is
not needed because the corresponding initialization can
be performed directly in android-qemu2-glue/main.cpp
instead.
Change-Id: Ia972b7882ebf00a379ed9536e93e44551e3b0160
diff --git a/android-qemu2-glue/build/Makefile.qemu2-glue.mk b/android-qemu2-glue/build/Makefile.qemu2-glue.mk
index 649c1a0..613d2bf 100644
--- a/android-qemu2-glue/build/Makefile.qemu2-glue.mk
+++ b/android-qemu2-glue/build/Makefile.qemu2-glue.mk
@@ -24,6 +24,7 @@
emulation/VmLock.cpp \
looper-qemu.cpp \
net-android.cpp \
+ proxy/slirp_proxy.cpp \
qemu-battery-agent-impl.c \
qemu-cellular-agent-impl.c \
qemu-clipboard-agent-impl.cpp \
diff --git a/android-qemu2-glue/main.cpp b/android-qemu2-glue/main.cpp
index 0a18f06..add247d 100644
--- a/android-qemu2-glue/main.cpp
+++ b/android-qemu2-glue/main.cpp
@@ -16,6 +16,7 @@
#include "android/base/StringFormat.h"
#include "android/base/system/System.h"
+
#include "android/android.h"
#include "android/avd/hw-config.h"
#include "android/cmdline-option.h"
@@ -56,6 +57,7 @@
#include "android/ui-emu-agent.h"
#include "android-qemu2-glue/emulation/serial_line.h"
+#include "android-qemu2-glue/proxy/slirp_proxy.h"
#include "android-qemu2-glue/qemu-control-impl.h"
#ifdef TARGET_AARCH64
@@ -551,8 +553,9 @@
}
if (opts->http_proxy) {
- args[n++] = "-http-proxy";
- args[n++] = opts->http_proxy;
+ if (!qemu_android_setup_http_proxy(opts->http_proxy)) {
+ return 1;
+ }
}
if (!opts->charmap) {
diff --git a/android-qemu2-glue/proxy/slirp_proxy.cpp b/android-qemu2-glue/proxy/slirp_proxy.cpp
new file mode 100644
index 0000000..da53263
--- /dev/null
+++ b/android-qemu2-glue/proxy/slirp_proxy.cpp
@@ -0,0 +1,121 @@
+/* Copyright 2016 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android-qemu2-glue/proxy/slirp_proxy.h"
+
+#include "android/base/Log.h"
+#include "android/base/memory/LazyInstance.h"
+#include "android/proxy/proxy_common.h"
+#include "android/utils/sockets.h"
+
+#include "slirp/proxy.h"
+
+#ifdef _WIN32
+#include "android/base/sockets/Winsock.h"
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#include <unordered_map>
+#include <utility>
+
+extern "C" const char* op_http_proxy;
+
+namespace {
+
+// NOTE: The SLIRP stack only runs in the main thread, so don't
+// use a mutex to protect global variables from multiple threads.
+
+struct Globals {
+ // Implement a global map |connect_opaque| -> { |af|, |connect_func| }
+ // to be used in the android_tcp_proxy_event() function to map opaque
+ // handles to the appropriate callback and address family.
+ struct Info {
+ Info() = default;
+ Info(int af_, SlirpProxyConnectFunc* connect_func_) : af(af_), connect_func(connect_func_) {}
+ int af = 0;
+ SlirpProxyConnectFunc* connect_func = nullptr;
+ };
+ using MapType = std::unordered_map<void*, Info>;
+ MapType mMap;
+};
+
+android::base::LazyInstance<Globals> sGlobals = LAZY_INSTANCE_INIT;
+
+} // namespace
+
+using MapType = Globals::MapType;
+
+static void android_tcp_proxy_event(void* opaque, int fd, ProxyEvent event) {
+ MapType* map = &sGlobals->mMap;
+ auto it = map->find(opaque);
+ DCHECK(it != map->end());
+ if (event != PROXY_EVENT_CONNECTED) {
+ fd = -1;
+ }
+ it->second.connect_func(opaque, fd, it->second.af);
+}
+
+static bool android_proxy_try_connect(const struct sockaddr_storage *addr,
+ SlirpProxyConnectFunc *connect_func,
+ void *connect_opaque) {
+ SockAddress sockaddr = {};
+ int af = addr->ss_family;
+ switch (af) {
+ case AF_INET: {
+ auto sin = reinterpret_cast<const sockaddr_in *>(addr);
+ sock_address_init_inet(&sockaddr, ntohl(sin->sin_addr.s_addr),
+ ntohs(sin->sin_port));
+ break;
+ }
+ case AF_INET6: {
+ auto sin6 = reinterpret_cast<const sockaddr_in6 *>(addr);
+ sock_address_init_in6(&sockaddr, sin6->sin6_addr.s6_addr,
+ ntohs(sin6->sin6_port));
+ break;
+ }
+ default:
+ return false;
+ }
+
+ MapType* map = &sGlobals->mMap;
+ (*map)[connect_opaque] = Globals::Info({af, connect_func});
+
+ if (!proxy_manager_add(&sockaddr, SOCKET_STREAM, android_tcp_proxy_event,
+ connect_opaque)) {
+ return true;
+ }
+
+ // No proxy possible here, to remove from map.
+ map->erase(connect_opaque);
+ return false;
+}
+
+static void android_proxy_remove(void* connect_opaque) {
+ sGlobals->mMap.erase(connect_opaque);
+ proxy_manager_del(connect_opaque);
+}
+
+bool qemu_android_setup_http_proxy(const char* http_proxy) {
+ // Inject TCP proxy implementation into SLIRP stack.
+ // Initialization of the proxy will happen later.
+ static const SlirpProxyOps android_proxy_ops = {
+ .try_connect = android_proxy_try_connect,
+ .remove = android_proxy_remove,
+ };
+
+ op_http_proxy = http_proxy;
+
+ slirp_proxy = &android_proxy_ops;
+
+ return true;
+}
diff --git a/android-qemu2-glue/proxy/slirp_proxy.h b/android-qemu2-glue/proxy/slirp_proxy.h
new file mode 100644
index 0000000..d8994e4
--- /dev/null
+++ b/android-qemu2-glue/proxy/slirp_proxy.h
@@ -0,0 +1,21 @@
+/* Copyright 2016 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#pragma once
+
+#include "android/utils/compiler.h"
+#include <stdbool.h>
+
+ANDROID_BEGIN_HEADER
+
+bool qemu_android_setup_http_proxy(const char* http_proxy);
+
+ANDROID_END_HEADER
diff --git a/android-qemu2-glue/qemu-setup.cpp b/android-qemu2-glue/qemu-setup.cpp
index bdb0af8..34ac0ca 100644
--- a/android-qemu2-glue/qemu-setup.cpp
+++ b/android-qemu2-glue/qemu-setup.cpp
@@ -24,6 +24,7 @@
#include "android-qemu2-glue/looper-qemu.h"
#include "android-qemu2-glue/android_qemud.h"
#include "android-qemu2-glue/net-android.h"
+#include "android-qemu2-glue/proxy/slirp_proxy.h"
#include "android-qemu2-glue/qemu-control-impl.h"
extern "C" {
@@ -31,6 +32,10 @@
#include "qemu-common.h"
#include "qemu/main-loop.h"
#include "qemu/thread.h"
+
+// TODO: Remove op_http_proxy global variable.
+extern char* op_http_proxy;
+
} // extern "C"
using android::VmLock;
@@ -79,6 +84,10 @@
gQAndroidNetAgent,
};
+ if (!qemu_android_setup_http_proxy(op_http_proxy)) {
+ return false;
+ }
+
return android_emulation_setup(&consoleAgents);
}
diff --git a/qemu-options.def b/qemu-options.def
index 3822c5b..e8d6f4f 100644
--- a/qemu-options.def
+++ b/qemu-options.def
@@ -876,9 +876,6 @@
"-android-report-console <socket>"
" report console port to remote socket\n", QEMU_ARCH_ALL)
-DEF("http-proxy", HAS_ARG, QEMU_OPTION_http_proxy,
-"-http-proxy <proxy> make TCP connections through a HTTP/HTTPS proxy\n", QEMU_ARCH_ALL)
-
DEF("dns-server", HAS_ARG, QEMU_OPTION_dns_server,
"-dns-server <servers> use this DNS server(s) in the emulated system\n", QEMU_ARCH_ALL)
diff --git a/qemu-options.hx b/qemu-options.hx
index 92705ac..d543529 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4025,14 +4025,6 @@
Report console port to remote socket
ETEXI
-DEF("http-proxy", HAS_ARG, QEMU_OPTION_http_proxy,
- "-http-proxy <proxy> make TCP connections through a HTTP/HTTPS proxy\n", QEMU_ARCH_ALL)
-STEXI
-@item -http-proxy @var{proxy}
-@findex -http-proxy
-make TCP connections through a HTTP/HTTPS proxy
-ETEXI
-
DEF("dns-server", HAS_ARG, QEMU_OPTION_dns_server,
"-dns-server <servers> use this DNS server(s) in the emulated system\n", QEMU_ARCH_ALL)
STEXI
diff --git a/vl.c b/vl.c
index 1dd8897..c36e607 100755
--- a/vl.c
+++ b/vl.c
@@ -241,7 +241,6 @@
int graphic_rotate = 0;
#ifdef CONFIG_ANDROID
int lcd_density = LCD_DENSITY_MDPI;
-extern char* op_http_proxy;
extern char* android_op_ports;
extern int android_op_ports_numbers[2];
extern char* android_op_report_console;
@@ -4327,9 +4326,6 @@
android_op_dns_server = (char*)optarg;
break;
- case QEMU_OPTION_http_proxy:
- op_http_proxy = (char*)optarg;
- break;
case QEMU_OPTION_android_hw:
android_hw_file = optarg;
break;