]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[fdxhook] Added (unfinished) v8 support
authorFrancis Dupont <fdupont@isc.org>
Mon, 27 Jun 2016 05:39:01 +0000 (07:39 +0200)
committerFrancis Dupont <fdupont@isc.org>
Mon, 27 Jun 2016 05:39:01 +0000 (07:39 +0200)
13 files changed:
src/hooks/external/lua/Makefile
src/hooks/external/ocaml/Makefile
src/hooks/external/python/Makefile
src/hooks/external/v8/cshenv [new file with mode: 0644]
src/hooks/external/v8/dso.cc [new file with mode: 0644]
src/hooks/external/v8/globals.cc [new file with mode: 0644]
src/hooks/external/v8/globals.h [new file with mode: 0644]
src/hooks/external/v8/hook.js [new file with mode: 0644]
src/hooks/external/v8/tests.cc [new file with mode: 0644]
src/hooks/external/v8/voption.cc [new file with mode: 0644]
src/hooks/external/v8/voption.h [new file with mode: 0644]
src/hooks/external/v8/vpkt4.cc [new file with mode: 0644]
src/hooks/external/v8/vpkt4.h [new file with mode: 0644]

index 5331483155860d3d2a82eaa61ef6ab775ae88415..ecd16189ab3a4e6463c1eccc0c6e9df4f663c4bf 100644 (file)
@@ -6,7 +6,7 @@ CPPFLAGS = -I../../.. -I$(KEASRC) -I/usr/local/include
 CPPFLAGS += -I/usr/local/include/lua-5.3
 
 CXXFLAGS = -DBOOST_ERROR_CODE_HEADER_ONLY -DBOOST_SYSTEM_NO_DEPRECATED
-CXXFLAGS += -g -fPIC -dynamic
+CXXFLAGS += -g -fPIC -dynamic -Wall -Wextra
 
 # Kea dhcp library
 LIBS = -lkea-dhcp++ -lkea-hooks -lkea-exceptions
index 0fc971b9798aa6ea178494c79617d179f964724f..84b382c0f064ceb5dc90cbe7994f093623f4e410 100644 (file)
@@ -4,7 +4,7 @@
 CCOPT = -ccopt -I../../.. -ccopt -I$(KEASRC) -ccopt -I/usr/local/include
 CCOPT += -ccopt -DBOOST_ERROR_CODE_HEADER_ONLY
 CCOPT += -ccopt -DBOOST_SYSTEM_NO_DEPRECATED
-CCOPT += -ccopt -g -ccopt -fPIC -ccopt -dynamic
+CCOPT += -ccopt -g -ccopt -fPIC -ccopt -dynamic -ccopt -Wall -ccopt -Wextra
 
 OCAMLCC = ocamlc -cc g++ -ccopt -x -ccopt c++
 BOCAMLCC = ocamlc -cc g++ -ccopt -x -ccopt c++ -ccopt -DOCAML_CODE_BYTECODE
index a1b033a9337c54def80231a32924801d238af177..f2687fc02984924edee2337b0c8a8586b16af567 100644 (file)
@@ -6,7 +6,7 @@ CPPFLAGS = -I../../.. -I$(KEASRC) -I/usr/local/include
 CPPFLAGS += -I/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/include/python3.5m
 
 CXXFLAGS = -DBOOST_ERROR_CODE_HEADER_ONLY -DBOOST_SYSTEM_NO_DEPRECATED
-CXXFLAGS += -g -fPIC -dynamic -DNDEBUG -fwrapv
+CXXFLAGS += -g -fPIC -dynamic -DNDEBUG -fwrapv -Wall -Wextra
 
 # Kea dhcp library
 LIBS = -lkea-dhcp++ -lkea-hooks -lkea-exceptions
diff --git a/src/hooks/external/v8/cshenv b/src/hooks/external/v8/cshenv
new file mode 100644 (file)
index 0000000..b186eb1
--- /dev/null
@@ -0,0 +1,5 @@
+setenv KEATOP /tmp/kea
+
+setenv KEASRC $KEATOP/src/lib
+
+setenv DYLD_LIBRARY_PATH $KEASRC/dhcpsrv/.libs:$KEASRC/eval/.libs:$KEASRC/dhcp_ddns/.libs:$KEASRC/stats/.libs:$KEASRC/hooks/.libs:$KEASRC/config/.libs:$KEASRC/dhcp/.libs:$KEASRC/asiolink/.libs:$KEASRC/dns/.libs:$KEASRC/cc/.libs:$KEASRC/cryptolink/.libs:$KEASRC/log/.libs:$KEASRC/util/threads/.libs:$KEASRC/util/.libs:$KEASRC/exceptions/.libs
diff --git a/src/hooks/external/v8/dso.cc b/src/hooks/external/v8/dso.cc
new file mode 100644 (file)
index 0000000..ab2ea6d
--- /dev/null
@@ -0,0 +1,289 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <libplatform/libplatform.h>
+#include <v8.h>
+
+#include <exceptions/exceptions.h>
+#include <hooks/hooks.h>
+
+#include <hooks/external/v8/globals.h>
+#include <hooks/external/v8/voption.h>
+#include <hooks/external/v8/vpkt4.h>
+
+#include <iostream>
+#include <sstream>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+using namespace std;
+using namespace v8;
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::hooks;
+using namespace isc::v8;
+
+namespace {
+    // Platform
+    Platform* platform_ = NULL;
+
+    // Isolate
+    Isolate* isolate_ = NULL;
+
+    // Pkt4 receive handler
+    Global<Function> pkt4_rcv_hndl;
+
+    // Allocator
+    class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
+    public:
+        virtual void* Allocate(size_t length) {
+            void* data = AllocateUninitialized(length);
+            return data == NULL ? data : memset(data, 0, length);
+        }
+
+        virtual void* AllocateUninitialized(size_t length) {
+            return malloc(length);
+        }
+
+        virtual void Free(void* data, size_t) {
+            free(data);
+        }
+    };
+
+    // Fatal Error Handler
+    void fatal_error_handler(const char* location, const char* message) {
+        ostringstream oss;
+        oss << "V8 crashed because " << message << " at " << location;
+        isc_throw(isc::Unexpected, oss.str().c_str());
+    }
+};
+
+extern "C" {
+
+// Framework functions
+
+// version
+int version() {
+    return (KEA_HOOKS_VERSION);
+}
+
+// load
+int load(LibraryHandle& handle) {
+    // Set the program name (default "kea")
+    ConstElementPtr program = handle.getParameter("program");
+    string progname = "kea";
+    if (program && program->getType() == Element::string) {
+        progname = program->stringValue();
+    } else {
+        cout << "no \"program\" parameter: using \"kea\"\n";
+    }
+
+    // Get the script module name (default "hook.js")
+    ConstElementPtr script_param = handle.getParameter("script");
+    string script_name = "hook.js";
+    if (script_param && script_param->getType() == Element::string) {
+        script_name = script_param->stringValue();
+    } else {
+        cout << "no \"script\" parameter: using \"hook.js\"\n";
+    }
+
+    // Read the script
+    int fd = open(script_name.c_str(), O_RDONLY);
+    if (fd < 0) {
+        cerr << "open(" << script_name << ") failed: "
+             << strerror(errno) << "\n";
+        return (1);
+    }
+    struct stat st;
+    if (fstat(fd, &st) < 0) {
+        cerr << "stat(" << script_name << ") failed: "
+             << strerror(errno) << "\n";
+        close(fd);
+        return (2);
+    }
+    size_t sz = static_cast<size_t>(st.st_size);
+    char* content = new char[static_cast<size_t>(st.st_size)];
+    if (read(fd, content, sz) < 0) {
+        cerr << "read(" << script_name << ") failed: "
+             << strerror(errno) << "\n";
+        close(fd);
+        return (3);
+    }
+    close(fd);
+
+    // Initialize the v8 interpreter
+#if (V8_MAJOR_VERSION < 5) || \
+    ((V8_MAJOR_VERSION == 5) && (V8_MINOR_VERSION < 3))
+    V8::InitializeICU();
+#else
+    V8::InitializeICUDefaultLocation(progname.c_str());
+#endif
+    V8::InitializeExternalStartupData(progname.c_str());
+    platform_ = platform::CreateDefaultPlatform();
+    V8::InitializePlatform(platform_);
+    V8::Initialize();
+    ArrayBufferAllocator array_buffer_allocator;
+    Isolate::CreateParams create_params;
+    create_params.array_buffer_allocator = &array_buffer_allocator;
+    isolate_ = Isolate::New(create_params);
+    isolate_->SetFatalErrorHandler(&fatal_error_handler);
+
+    // Open a scope for the script
+    Isolate::Scope isolate_scope(isolate_);
+
+    // Create a stack-allocated handle scope.
+    HandleScope handle_scope(isolate_);
+
+    // Catch errors
+    TryCatch try_catch(isolate_);
+
+    // For global objects
+    Local<ObjectTemplate> globals = ObjectTemplate::New(isolate_);
+    init_globals(isolate_, globals);
+
+    // Create a new context
+    Local<Context> context = Context::New(isolate_, NULL, globals);
+
+    // Enter the context for compiling and running the script
+    Context::Scope context_scope(context);
+
+    // Initialize option and pkt4
+    init_option_template(isolate_);
+    init_pkt4_template(isolate_);
+
+    // Import script file content
+    Local<String> source =
+        String::NewFromUtf8(isolate_, content,
+                            NewStringType::kNormal).ToLocalChecked();
+
+    // Compile the script
+    Local<Script> script;
+    if (!Script::Compile(context, source).ToLocal(&script)) {
+        String::Utf8Value error(try_catch.Exception());
+        cerr << "Compile(" << script_name << ") failed: "
+             << *error << "\n";
+        return (4);
+    }
+
+    // Run the script to get the result.
+    Local<Value> result;
+    if (!script->Run(context).ToLocal(&result)) {
+        String::Utf8Value error(try_catch.Exception());
+        cerr << "Run(" << script_name << ") failed: " << *error << "\n";
+        return (5);
+    }
+
+    // Get the pkt4_receive function
+    Local<String> pkt4_rcv_name =
+        String::NewFromUtf8(isolate_, "pkt4_receive",
+                            NewStringType::kNormal).ToLocalChecked();
+    Local<Object> global = context->Global();
+    Local<Value> pkt4_rcv_val;
+    if (!global->Get(context, pkt4_rcv_name).ToLocal(&pkt4_rcv_val)) {
+        String::Utf8Value error(try_catch.Exception());
+        cerr << "global->Get(pkt4_receive) failed: " << *error << "\n";
+        return (6);
+    }
+    if (!pkt4_rcv_val->IsFunction()) {
+        cerr << "\"pkt4_receive\" is not a function\n";
+        return (7);
+    }
+    Local<Function> pkt4_rcv_fun = Local<Function>::Cast(pkt4_rcv_val);
+    pkt4_rcv_hndl.Reset(isolate_, pkt4_rcv_fun);
+
+    return (0);
+}
+
+// unload
+int unload() {
+    // Clear pkt4_receive handler
+    pkt4_rcv_hndl.Reset();
+
+    // Destroy v8 interpreter
+    if (platform_) {
+        if (isolate_) {
+            isolate_->Dispose();
+        }
+        isolate_ = NULL;
+        V8::Dispose();
+        V8::ShutdownPlatform();
+        delete platform_;
+    }
+    platform_ = NULL;
+
+    return (0);
+}
+
+// pkt4_receive hook
+int pkt4_receive(CalloutHandle& handle) {
+    if (pkt4_rcv_hndl.IsEmpty()) {
+        return (0);
+    }
+    cout << "pkt4_receive: enter\n";
+
+    Pkt4Ptr query4;
+    handle.getArgument("query4", query4);
+    if (!query4) {
+        cerr << "pkt4_receive: null query4\n";
+        return (0);
+    }
+
+    // Create a stack-allocated handle scope.
+    HandleScope handle_scope(isolate_);
+
+    // Catch errors
+    TryCatch try_catch(isolate_);
+
+    // Get a new context
+    Local<Context> context = Context::New(isolate_);
+
+    // Enter the context for running the handler
+    Context::Scope context_scope(context);
+
+    // Create pkt4 object
+    Local<ObjectTemplate> templ =
+        Local<ObjectTemplate>::New(isolate_, pkt4_template);
+    Local<Object> query;
+    if (!templ->NewInstance(context).ToLocal(&query)) {
+        String::Utf8Value error(try_catch.Exception());
+        cerr << "NewInstance failed: " << *error << "\n";
+        return (0);
+    }
+    v8_pkt4* ccpobj(new v8_pkt4());
+    ccpobj->object = query4;
+    Local<External> ptr = External::New(isolate_, ccpobj);
+    query->SetInternalField(0, ptr);
+
+    // Call the handler
+    const int argc = 1;
+    Local<Value> argv[argc] = { query };
+    Local<Function> handler = Local<Function>::New(isolate_, pkt4_rcv_hndl);
+    Local<Value> result;
+    if (!handler->Call(context, context->Global(),
+                       argc, argv).ToLocal(&result)) {
+      cerr << "call failed\n";
+        String::Utf8Value error(try_catch.Exception());
+        cerr << "pkt4_receive handler failed: " << *error << "\n";
+        return (0);
+    }
+    if (!result->IsInt32()) {
+        cerr << "pkt4_receive handler didn't return an int32\n";
+        return (0);
+    }
+
+    int32_t ret = 0xbadbad;
+    ret = result->Int32Value(context).FromJust();
+    if (ret == 0xbadbad) {
+        String::Utf8Value error(try_catch.Exception());
+        cerr << "ToInt32 failed: " << *error << "\n";
+        return (0);
+    }
+
+    cout << "pkt4_receive: return " << ret << "\n";
+    return (static_cast<int>(ret));
+}
+
+}
diff --git a/src/hooks/external/v8/globals.cc b/src/hooks/external/v8/globals.cc
new file mode 100644 (file)
index 0000000..cef15f0
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <libplatform/libplatform.h>
+#include <v8.h>
+
+#include <hooks/external/v8/globals.h>
+
+#include <iostream>
+
+using namespace std;
+using namespace v8;
+using namespace isc::v8;
+
+namespace { // anonymous namespace
+
+// Convert a C++ string to a v8 String
+Local<String> StringToObject(Isolate* isolate, const string& cpps) {
+    EscapableHandleScope handle_scope(isolate);
+
+    Local<String> v8s =
+        String::NewFromUtf8(isolate, cpps.c_str(),
+                            NewStringType::kNormal).ToLocalChecked();
+    return (handle_scope.Escape(v8s));
+}
+
+// Convert a v8 String to a C++ UTF8 string
+string ObjectToString(Local<String> value) {
+    int len = value->Utf8Length();
+    char* str = new char[len + 1];
+    value->WriteUtf8(str);
+    string result(str);
+    delete [] str;
+    return (result);
+}
+
+// Print
+void Print(const FunctionCallbackInfo<Value>& args) {
+    Isolate* isolate = args.GetIsolate();
+    for (int i = 0; i < args.Length(); ++i) {
+        HandleScope handle_scope(isolate);
+
+        if (i != 0) {
+            cout << " ";
+        }
+
+        // toString() can raise errors
+        TryCatch try_catch(isolate);
+
+        Local<Value> arg = args[i];
+        Local<String> str;
+
+        // Defer symbols
+        if (arg->IsSymbol()) {
+            arg = Local<Symbol>::Cast(arg)->Name();
+        }
+
+        // Get v8 string
+        if (!arg->ToString(isolate->GetCurrentContext()).ToLocal(&str)) {
+            try_catch.ReThrow();
+            return;
+        }
+
+        cout << ObjectToString(str);
+    }
+    cout << "\n";
+}
+
+} // end of anonymous namespace
+
+namespace isc {
+namespace v8 {
+
+void init_globals(Isolate* isolate, Local<ObjectTemplate> global) {
+    global->Set(StringToObject(isolate, "print"),
+                FunctionTemplate::New(isolate, Print));
+}
+
+} // end of namespace v8
+} // end of namespace isc
diff --git a/src/hooks/external/v8/globals.h b/src/hooks/external/v8/globals.h
new file mode 100644 (file)
index 0000000..12e1d28
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef GLOBALS_V8_H
+#define GLOBALS_V8_H 1
+
+namespace isc {
+namespace v8 {
+
+void init_globals(::v8::Isolate* isolate,
+                  ::v8::Local< ::v8::ObjectTemplate> global);
+
+} // end of namespace v8
+} // end of namespace isc
+
+#endif // GLOBALS_V8_H
diff --git a/src/hooks/external/v8/hook.js b/src/hooks/external/v8/hook.js
new file mode 100644 (file)
index 0000000..f8430e9
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Support for kea hook in javascript v8
+
+print("hook.js is loading");
+
+const NEXT_STEP_CONTINUE = 0;
+const NEXT_STEP_SKIP = 1;
+const NEXT_STEP_DROP = 2;
+
+function pkt4_receive(query4) {
+    // pkt4_receive hook point.
+    //
+    // parameter: inout Pkt4Ptr query4
+    // return: next step
+    print("pkt4_receive: handler is called with", query4);
+    return NEXT_STEP_CONTINUE;
+};
+
+print("hook.js loaded");
diff --git a/src/hooks/external/v8/tests.cc b/src/hooks/external/v8/tests.cc
new file mode 100644 (file)
index 0000000..c3772f2
--- /dev/null
@@ -0,0 +1,147 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <cc/data.h>
+#include <dhcp/pkt4.h>
+#include <dhcpsrv/parsers/dhcp_parsers.h>
+#include <dhcpsrv/callout_handle_store.h>
+#include <hooks/hooks_manager.h>
+#include <log/logger_support.h>
+
+#include <boost/foreach.hpp>
+
+#include <iostream>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::hooks;
+using namespace isc::log;
+
+// config fragment for hooks-libraries
+const string config =
+    "{ \"hooks-libraries\": ["
+    " { \"library\": \"kea.so\", "
+    "   \"parameters\": "
+    "   { \"program\": \"kea\", "
+    "     \"script\": \"hook.js\" }"
+    " }] }";
+
+// main routine
+int main() {
+    // must be first
+    int hi_pkt4_receive = HooksManager::registerHook("pkt4_receive");
+    cout << "pkt4_receive is hook#" << hi_pkt4_receive << "\n";
+
+    initLogger();
+
+    // check if there is a library already loaded
+    vector<string> hooks_libraries = HooksManager::getLibraryNames();
+    if (!hooks_libraries.empty()) {
+        cerr << "hooks_libraries is not empty\n";
+    }
+
+    // parse config into json
+    ElementPtr json = Element::fromJSON(config);
+    if (!json) {
+        cerr << "fatal: fromJSON failed\n";
+        exit(-1);
+    }
+    cout << "config parsed\n";
+
+    // call the hooks-libraries parser
+    boost::shared_ptr<HooksLibrariesParser> parser;
+    try {
+        const map<string, ConstElementPtr>& cmap = json->mapValue();
+        if (cmap.empty()) {
+            cerr << "fatal: config map is empty\n";
+            exit(-1);
+        }
+        if (cmap.size() > 1) {
+            cerr << "config map has more than one element\n";
+        }
+        if (cmap.count("hooks-libraries") == 0) {
+            cerr << "fatal: no \"hooks-libraries\" in config\n";
+            exit(-1);
+        }
+        const ConstElementPtr& hl_value = cmap.find("hooks-libraries")->second;
+        if (!hl_value) {
+            cerr << "fatal: empty \"hooks-libraries\" value\n";
+            exit(-1);
+        }
+        parser.reset(new HooksLibrariesParser("hooks-libraries"));
+        parser->build(hl_value);
+        parser->commit();
+        cout << "config committed\n";
+    } catch (const Exception& ex) {
+        cerr << "fatal: config parsing failed: " << ex.what() << "\n";
+        exit(-1);
+    }
+    
+    // check if the library was loaded
+    HookLibsCollection libraries;
+    bool changed = false;
+    parser->getLibraries(libraries, changed);
+    if (!changed) {
+        cerr << "commit didn't change libraries\n";
+    }
+    if (libraries.empty()) {
+        cerr << "fatal: no libraries\n";
+        exit(-1);
+    }
+    if (libraries.size() > 1) {
+        cerr << "more than one library\n";
+    }
+    cout << "library is \"" + libraries[0].first + "\"\n";
+    if (libraries[0].first != "kea.so") {
+        cerr << "fatal: library is not \"kea.so\"\n";
+        exit(-1);
+    }
+    ConstElementPtr params = libraries[0].second;
+    if (!params) {
+        cerr << "no parameters\n";
+    } else {
+        cout << "got " << params->size() << " parameters\n";
+    }
+
+    // note we can't know this way if it was successfully loaded
+
+    // get the callout
+    if (!HooksManager::calloutsPresent(hi_pkt4_receive)) {
+        cerr << "fatal: no callout present for pkt4_receive\n";
+        exit(-1);
+    }
+
+    // from pkt4_unittests.cc
+    Pkt4Ptr pkt(new Pkt4(DHCPDISCOVER, 0x12345678));
+    const uint8_t macAddr[] = {0, 1, 2, 3, 4, 5};
+    vector<uint8_t> vectorMacAddr(macAddr, macAddr + sizeof(macAddr));
+    pkt->setHWAddr(6, 6, vectorMacAddr);
+    pkt->setHops(13);
+    // Transaction-id is already set.
+    pkt->setSecs(42);
+    pkt->setFlags(BOOTP_BROADCAST);
+    pkt->setCiaddr(IOAddress("192.0.2.1"));
+    pkt->setYiaddr(IOAddress("1.2.3.4"));
+    pkt->setSiaddr(IOAddress("192.0.2.255"));
+    pkt->setGiaddr(IOAddress("255.255.255.255"));
+    // Chaddr already set with setHWAddr().
+
+    // from dhcp4_srv.cc
+    CalloutHandlePtr co_handle = getCalloutHandle(pkt);
+    co_handle->deleteAllArguments();
+    co_handle->setArgument("query4", pkt);
+    cout << "calling pkt4_receive callout\n";
+    HooksManager::callCallouts(hi_pkt4_receive, *co_handle);
+    cout << "pkt4_receive callout status " << co_handle->getStatus() << "\n";
+    co_handle->getArgument("query4", pkt);
+
+    // TODO...
+
+    exit(0);
+}
diff --git a/src/hooks/external/v8/voption.cc b/src/hooks/external/v8/voption.cc
new file mode 100644 (file)
index 0000000..67ac27a
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <libplatform/libplatform.h>
+#include <v8.h>
+
+#include <hooks/external/v8/voption.h>
+
+#include <iostream>
+
+using namespace std;
+using namespace v8;
+using namespace isc::dhcp;
+using namespace isc::v8;
+
+// Contructor
+v8_option::v8_option() {}
+
+namespace { // anonymous namespace
+
+// finalize (how to call it?)
+void
+option_finalize(Local<Object> obj) {
+    // This is a critical code to avoid memory leaks
+    cout << "option_finalize called\n";
+    Local<External> field = Local<External>::Cast(obj->GetInternalField(0));
+    v8_option* const self = static_cast<v8_option*>(field->Value());
+    self->object.reset();
+    delete self;
+}
+
+} // end of anonymous namespace
+
+namespace isc {
+namespace v8 {
+
+Global<ObjectTemplate> option_template;
+
+void init_option_template(Isolate* isolate) {
+    // Create a stack-allocated handle scope.
+    HandleScope handle_scope(isolate);
+
+    // Get an object template
+    Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
+
+    // Get one field
+    templ->SetInternalFieldCount(1);
+
+    ///// TODO set methods
+
+    // Store it
+    option_template.Reset(isolate, templ);
+}
+
+} // end of namespace v8
+} // end of namespace isc
diff --git a/src/hooks/external/v8/voption.h b/src/hooks/external/v8/voption.h
new file mode 100644 (file)
index 0000000..ddc8ba0
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef OPTION_V8_H
+#define OPTION_V8_H 1
+
+#include <dhcp/option.h>
+
+namespace isc {
+namespace v8 {
+
+// Ocaml option class
+class v8_option {
+    v8_option();
+
+public:
+    isc::dhcp::OptionPtr object;
+};
+
+extern ::v8::Global< ::v8::ObjectTemplate> option_template;
+
+void init_option_template(::v8::Isolate* isolate);
+
+} // end of namespace v8
+} // end of namespace isc
+
+#endif // OPTION_V8_H
diff --git a/src/hooks/external/v8/vpkt4.cc b/src/hooks/external/v8/vpkt4.cc
new file mode 100644 (file)
index 0000000..3445790
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <libplatform/libplatform.h>
+#include <v8.h>
+
+#include <hooks/external/v8/voption.h>
+#include <hooks/external/v8/vpkt4.h>
+
+#include <iostream>
+
+using namespace std;
+using namespace v8;
+using namespace isc::dhcp;
+using namespace isc::v8;
+
+// Contructor
+v8_pkt4::v8_pkt4() {}
+
+namespace { // anonymous namespace
+
+// finalize (how to call it?)
+void
+pkt4_finalize(Local<Object> obj) {
+    // This is a critical code to avoid memory leaks
+    cout << "pkt4_finalize called\n";
+    Local<External> field = Local<External>::Cast(obj->GetInternalField(0));
+    v8_pkt4* const self = static_cast<v8_pkt4*>(field->Value());
+    self->object.reset();
+    delete self;
+}
+
+// toString
+void
+pkt4_tostring(const FunctionCallbackInfo<Value>& info) {
+    HandleScope handle_scope(info.GetIsolate());
+
+    Local<External> field =
+        Local<External>::Cast(info.Holder()->GetInternalField(0));
+    v8_pkt4* const self = static_cast<v8_pkt4*>(field->Value());
+    info.GetReturnValue().Set(
+        String::NewFromUtf8(info.GetIsolate(),
+                            self->object->toText().c_str(),
+                            NewStringType::kNormal).ToLocalChecked());
+}
+
+} // end of anonymous namespace
+
+namespace isc {
+namespace v8 {
+
+Global<ObjectTemplate> pkt4_template;
+
+void init_pkt4_template(Isolate* isolate) {
+    // Create a stack-allocated handle scope.
+    HandleScope handle_scope(isolate);
+
+    // Get an object template
+    Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
+
+    // Get one field
+    templ->SetInternalFieldCount(1);
+
+    // Set Methods
+    Local<Function> tostring;
+    if (!Function::New(isolate->GetCurrentContext(),
+                       pkt4_tostring).ToLocal(&tostring)) {
+        cerr << "can't create pkt4_tostring\n";
+    }
+    templ->Set(isolate, "toString", tostring);
+
+    // Store it
+    pkt4_template.Reset(isolate, templ);
+}
+
+} // end of namespace v8
+} // end of namespace isc
diff --git a/src/hooks/external/v8/vpkt4.h b/src/hooks/external/v8/vpkt4.h
new file mode 100644 (file)
index 0000000..381938a
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef PKT4_V8_H
+#define PKT4_V8_H 1
+
+#include <dhcp/pkt4.h>
+
+namespace isc {
+namespace v8 {
+
+// Ocaml pkt4 class
+class v8_pkt4 {
+public:
+    v8_pkt4();
+
+    isc::dhcp::Pkt4Ptr object;
+};
+
+extern ::v8::Global< ::v8::ObjectTemplate> pkt4_template;
+
+void init_pkt4_template(::v8::Isolate* isolate);
+
+} // end of namespace v8
+} // end of namespace isc
+
+#endif // PKT4_V8_H