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
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
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
--- /dev/null
+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
--- /dev/null
+// 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));
+}
+
+}
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+// 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");
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+// 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