aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-12-10 19:37:25 +0100
committerSamuel Ortiz <sameo@linux.intel.com>2010-12-10 19:38:29 +0100
commite9e61c9e22afbc0098fff53c3d90b4a98d51267f (patch)
tree37a76ee8f8e5c9b8f973063040b36212e07b7dfc
parentc90d24988ec2b00379310c12ba10f307f4f5b108 (diff)
downloadpacrunner-e9e61c9e22afbc0098fff53c3d90b4a98d51267f.tar.gz
v8: Initial plugin implementation
-rw-r--r--Makefile.am8
-rw-r--r--configure.ac10
-rw-r--r--plugins/v8.cc316
3 files changed, 334 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index aaa9b06..65a1e49 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -33,6 +33,12 @@ builtin_cflags += @MOZJS_CFLAGS@
builtin_libadd += @MOZJS_LIBS@
endif
+if V8
+builtin_modules += v8
+builtin_sources += plugins/v8.cc
+builtin_libadd += @V8_LIBS@
+endif
+
sbin_PROGRAMS = src/pacrunner
src_pacrunner_SOURCES = $(gdbus_sources) $(builtin_sources) \
@@ -95,6 +101,8 @@ AM_CFLAGS = @GLIB_CFLAGS@ @DBUS_CFLAGS@ @CAPNG_CFLAGS@ \
-DPACRUNNER_PLUGIN_BUILTIN \
-DPLUGINDIR=\""$(plugindir)"\"
+AM_CXXFLAGS = $(AM_CFLAGS)
+
INCLUDES = -I$(builddir)/src -I$(srcdir)/src -I$(srcdir)/gdbus
test_scripts = test/find-proxy-for-url test/create-proxy-config
diff --git a/configure.ac b/configure.ac
index 37993fa..53da781 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,6 +23,7 @@ COMPILER_FLAGS
AC_LANG_C
AC_PROG_CC
+AC_PROG_CXX
AC_PROG_CC_PIE
AC_PROG_INSTALL
@@ -66,6 +67,15 @@ if (test "${enable_mozjs}" = "yes"); then
fi
AM_CONDITIONAL(MOZJS, test "${enable_mozjs}" = "yes")
+AC_ARG_ENABLE(v8, AC_HELP_STRING([--enable-v8],
+ [enable V8 Javascript plugin support]))
+if (test "${enable_v8}" = "yes"); then
+ AC_CHECK_LIB(v8, _ZN2v82V810InitializeEv,
+ [enable_threads=yes V8_LIBS="-lv8 -lpthread" AC_SUBST(V8_LIBS)],
+ [AC_MSG_ERROR(Chrome v8 is required)], -lpthread)
+fi
+AM_CONDITIONAL(V8, test "${enable_v8}" = "yes")
+
AC_ARG_ENABLE(threads,
AC_HELP_STRING([--enable-threads], [enable threading support]),
[enable_threads=${enableval}], [enable_threads="no"])
diff --git a/plugins/v8.cc b/plugins/v8.cc
new file mode 100644
index 0000000..e0d9987
--- /dev/null
+++ b/plugins/v8.cc
@@ -0,0 +1,316 @@
+/*
+ *
+ * PACrunner - Proxy configuration daemon
+ *
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <linux/if_arp.h>
+
+#include <v8.h>
+#include "javascript.h"
+
+extern "C" {
+#include "pacrunner.h"
+#include "js.h"
+};
+
+struct pacrunner_proxy *current_proxy = NULL;
+v8::Persistent<v8::Context> jsctx;
+v8::Persistent<v8::Function> jsfn;
+guint gc_source = 0;
+
+static gboolean v8_gc(gpointer user_data)
+{
+ v8::Locker lck;
+ return !v8::V8::IdleNotification();
+}
+
+static int getaddr(const char *node, char *host, size_t hostlen)
+{
+ struct sockaddr_in addr;
+ struct ifreq ifr;
+ int sk, err;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -EIO;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, node, sizeof(ifr.ifr_name));
+
+ err = ioctl(sk, SIOCGIFADDR, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return -EIO;
+
+ memcpy(&addr, &ifr.ifr_addr, sizeof(addr));
+ snprintf(host, hostlen, "%s", inet_ntoa(addr.sin_addr));
+
+ return 0;
+}
+
+static int resolve(const char *node, char *host, size_t hostlen)
+{
+ struct addrinfo *info;
+ int err;
+
+ if (getaddrinfo(node, NULL, NULL, &info) < 0)
+ return -EIO;
+
+ err = getnameinfo(info->ai_addr, info->ai_addrlen,
+ host, hostlen, NULL, 0, NI_NUMERICHOST);
+
+ freeaddrinfo(info);
+
+ if (err < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static v8::Handle<v8::Value> myipaddress(const v8::Arguments& args)
+{
+ const char *interface;
+ char address[NI_MAXHOST];
+
+ DBG("");
+
+ if (current_proxy == NULL)
+ return v8::ThrowException(v8::String::New("No current proxy"));
+
+ interface = pacrunner_proxy_get_interface(current_proxy);
+ if (interface == NULL)
+ return v8::ThrowException(v8::String::New("Error fetching interface"));
+
+ if (getaddr(interface, address, sizeof(address)) < 0)
+ return v8::ThrowException(v8::String::New("Error fetching IP address"));
+
+ DBG("address %s", address);
+
+ return v8::String::New(address);
+}
+
+static v8::Handle<v8::Value> dnsresolve(const v8::Arguments& args)
+{
+ char address[NI_MAXHOST];
+ v8::String::Utf8Value host(args[0]);
+
+ if (args.Length() != 1)
+ return v8::ThrowException(v8::String::New("Bad parameters"));
+
+
+ DBG("host %s", *host);
+
+ if (resolve(*host, address, sizeof(address)) < 0)
+ return v8::ThrowException(v8::String::New("Failed to resolve"));
+
+ DBG("address %s", address);
+
+ return v8::String::New(address);
+}
+
+static void create_object(void)
+{
+ if (!current_proxy)
+ return;
+
+ const char *pac = pacrunner_proxy_get_script(current_proxy);
+ if (!pac) {
+ printf("no script\n");
+ return;
+ }
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+
+ global->Set(v8::String::New("myIpAddress"),
+ v8::FunctionTemplate::New(myipaddress));
+ global->Set(v8::String::New("dnsResolve"),
+ v8::FunctionTemplate::New(dnsresolve));
+
+ jsctx = v8::Context::New(NULL, global);
+ v8::Context::Scope context_scope(jsctx);
+
+ v8::TryCatch exc;
+ v8::Handle<v8::Script> script_scr;
+ v8::Handle<v8::Value> result;
+
+ script_scr = v8::Script::Compile(v8::String::New(JAVASCRIPT_ROUTINES));
+ if (script_scr.IsEmpty()) {
+ v8::String::Utf8Value err(exc.Exception());
+ DBG("Javascript failed to compile: %s", *err);
+ jsctx.Dispose();
+ return;
+ }
+ result = script_scr->Run();
+ if (exc.HasCaught()) {
+ v8::String::Utf8Value err(exc.Exception());
+ DBG("Javascript library failed: %s", *err);
+ jsctx.Dispose();
+ return;
+ }
+
+ script_scr = v8::Script::Compile(v8::String::New(pac));
+ if (script_scr.IsEmpty()) {
+ v8::String::Utf8Value err(exc.Exception());
+ DBG("PAC script failed to compile: %s", *err);
+ jsctx.Dispose();
+ return;
+ }
+ result = script_scr->Run();
+ if (exc.HasCaught()) {
+ v8::String::Utf8Value err(exc.Exception());
+ DBG("PAC script failed: %s", *err);
+ jsctx.Dispose();
+ return;
+ }
+
+ v8::Handle<v8::String> fn_name = v8::String::New("FindProxyForURL");
+ v8::Handle<v8::Value> fn_val = jsctx->Global()->Get(fn_name);
+
+ if (!fn_val->IsFunction()) {
+ DBG("FindProxyForUrl is not a function");
+ jsctx.Dispose();
+ return;
+ }
+
+ jsfn = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(fn_val));
+ return;
+}
+
+static void destroy_object(void)
+{
+ if (!jsfn.IsEmpty()) {
+ jsfn.Dispose();
+ jsfn.Clear();
+ }
+ if (!jsctx.IsEmpty()) {
+ jsctx.Dispose();
+ jsctx.Clear();
+ }
+}
+
+int v8_set_proxy(struct pacrunner_proxy *proxy)
+{
+ v8::Locker lck;
+
+ DBG("proxy %p", proxy);
+
+ if (current_proxy != NULL)
+ destroy_object();
+
+ current_proxy = proxy;
+
+ if (current_proxy != NULL)
+ create_object();
+
+ if (!gc_source)
+ gc_source = g_idle_add(v8_gc, NULL);
+
+ return 0;
+}
+
+
+char *v8_execute(const char *url, const char *host)
+{
+ v8::Locker lck;
+
+ DBG("url %s host %s", url, host);
+
+ if (jsctx.IsEmpty() || jsfn.IsEmpty())
+ return NULL;
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(jsctx);
+
+ v8::Handle<v8::Value> args[2] = {
+ v8::String::New(url),
+ v8::String::New(host)
+ };
+
+ v8::Handle<v8::Value> result;
+ v8::TryCatch exc;
+
+ result = jsfn->Call(jsctx->Global(), 2, args);
+ if (exc.HasCaught()) {
+ v8::Handle<v8::Message> msg = exc.Message();
+ int line = msg->GetLineNumber();
+ v8::String::Utf8Value err(msg->Get());
+ DBG("Failed to run FindProxyForUrl(): at line %d: %s",
+ line, *err);
+ return NULL;
+ }
+
+ if (!result->IsString()) {
+ DBG("FindProxyForUrl() failed to return a string");
+ return NULL;
+ }
+
+ /* Hrm, how to fix this leak? */
+ char *retval = g_strdup(*v8::String::Utf8Value(result->ToString()));
+
+ if (!gc_source)
+ gc_source = g_idle_add(v8_gc, NULL);
+
+ return retval;
+}
+
+static struct pacrunner_js_driver v8_driver = {
+ "v8",
+ 0,
+ v8_set_proxy,
+ v8_execute,
+};
+
+static int v8_init(void)
+{
+ DBG("");
+
+ return pacrunner_js_driver_register(&v8_driver);
+}
+
+static void v8_exit(void)
+{
+ DBG("");
+
+ pacrunner_js_driver_unregister(&v8_driver);
+
+ v8_set_proxy(NULL);
+
+ if (gc_source) {
+ g_source_remove(gc_source);
+ gc_source = 0;
+ }
+ while (!v8::V8::IdleNotification())
+ ;
+}
+
+PACRUNNER_PLUGIN_DEFINE(v8, v8_init, v8_exit)