]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[fdxhook] Added LUA too
authorFrancis Dupont <fdupont@isc.org>
Mon, 20 Jun 2016 21:02:37 +0000 (23:02 +0200)
committerFrancis Dupont <fdupont@isc.org>
Mon, 20 Jun 2016 21:02:37 +0000 (23:02 +0200)
src/hooks/external/lua/Makefile [new file with mode: 0644]
src/hooks/external/lua/NOTES [new file with mode: 0644]
src/hooks/external/lua/cshenv [new file with mode: 0644]
src/hooks/external/lua/dso.cc [new file with mode: 0644]
src/hooks/external/lua/hook.lua [new file with mode: 0644]
src/hooks/external/lua/loption.cc [new file with mode: 0644]
src/hooks/external/lua/loption.h [new file with mode: 0644]
src/hooks/external/lua/lpkt4.cc [new file with mode: 0644]
src/hooks/external/lua/lpkt4.h [new file with mode: 0644]
src/hooks/external/lua/tests.cc [new file with mode: 0644]
src/hooks/external/ocaml/NOTES

diff --git a/src/hooks/external/lua/Makefile b/src/hooks/external/lua/Makefile
new file mode 100644 (file)
index 0000000..5331483
--- /dev/null
@@ -0,0 +1,49 @@
+#KEASRC = /tmp/kea/src/lib
+
+# Kea includes and boost
+CPPFLAGS = -I../../.. -I$(KEASRC) -I/usr/local/include
+# lua 5.3
+CPPFLAGS += -I/usr/local/include/lua-5.3
+
+CXXFLAGS = -DBOOST_ERROR_CODE_HEADER_ONLY -DBOOST_SYSTEM_NO_DEPRECATED
+CXXFLAGS += -g -fPIC -dynamic
+
+# Kea dhcp library
+LIBS = -lkea-dhcp++ -lkea-hooks -lkea-exceptions
+# lua 5.3
+LIBS += -llua.5.3 -lm
+
+# Kea dependencies
+LDFLAGS = -L/usr/local/Cellar/botan/1.10.12/lib
+LDFLAGS += -L$(KEASRC)/dhcp/.libs
+LDFLAGS += -L$(KEASRC)/hooks/.libs
+LDFLAGS += -L$(KEASRC)/exceptions/.libs
+# lua 5.3
+LDFLAGS += -L/usr/local/lib
+
+SRCS = dso.cc loption.h loption.cc lpkt4.h lpkt4.cc
+
+OBJS = dso.o loption.o lpkt4.o
+
+all: kea.so tests
+
+kea.so: $(OBJS)
+       g++ -shared $(OBJS) $(LDFLAGS) $(LIBS) -o kea.so
+
+TESTLIBS = -lkea-dhcpsrv -lkea-dhcp++ -lkea-asiolink -lkea-cc
+TESTLIBS += -lkea-hooks -lkea-log -lkea-exceptions
+
+TESTLDFLAGS = -L/usr/local/Cellar/botan/1.10.12/lib
+TESTLDFLAGS += -L$(KEASRC)/dhcpsrv/.libs
+TESTLDFLAGS += -L$(KEASRC)/dhcp/.libs
+TESTLDFLAGS += -L$(KEASRC)/asiolink/.libs
+TESTLDFLAGS += -L$(KEASRC)/cc/.libs
+TESTLDFLAGS += -L$(KEASRC)/hooks/.libs
+TESTLDFLAGS += -L$(KEASRC)/log/.libs
+TESTLDFLAGS += -L$(KEASRC)/exceptions/.libs
+
+tests: tests.o
+       g++ tests.o $(TESTLDFLAGS) $(TESTLIBS) -o tests
+
+clean:
+       rm -f *.o *.so tests
diff --git a/src/hooks/external/lua/NOTES b/src/hooks/external/lua/NOTES
new file mode 100644 (file)
index 0000000..7aa22e3
--- /dev/null
@@ -0,0 +1,39 @@
+Implementation notes for lua
+
+Manifest:
+ - loption.h loption.cc: the C++ OptionPtr encapsulated into a lua full
+  userdata with a few methods ported.
+
+ - ppkt4.h ppkt4.cc: the C++ Pkt4Ptr encapsulated into a lua full userdata
+  with a few methods ported.
+
+  one can complete these lua types or/and new lua type.
+
+ - dso.cc: the kea framework and hook glue: on the kea / C side it is
+  a dynamic shared object providing the framework and hook entry points,
+  on the lua side it embeds an interpreter which imports the lua script
+  hook.lua.
+
+  loption.o, lpkt4.o and dso.o are compiled into kea.so.
+
+ - hook.lua: the lua script which implements the lua part of hook
+  hook handlers using lua option and pkt4 modules.
+
+ - tests.cc: source of test program which loads the kea.so hook-library
+  and exercise the pkt4_receive hook. It gives an independent executable.
+
+ - cshenv: C-shell script setting environment variables for a kea
+  distrib in /tmp/kea on OS X. Note I brewed a recent (vs standard)
+  version of lua (last one is 5.3.3).
+
+ - Makefile: make config file for OS X.
+
+ - NOTES: this file.
+
+I was afraid to have to recompile lua for C++ but it was not (yet?)
+necessary.
+
+The preload stuff from linit.c doesn't work.
+
+A possible bug issue: the allocator (lua_newuserdata) does NOT
+clear the memory?!
diff --git a/src/hooks/external/lua/cshenv b/src/hooks/external/lua/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/lua/dso.cc b/src/hooks/external/lua/dso.cc
new file mode 100644 (file)
index 0000000..e771e90
--- /dev/null
@@ -0,0 +1,208 @@
+// 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 <lua.hpp>
+
+#include <hooks/hooks.h>
+
+#include <hooks/external/lua/loption.h>
+#include <hooks/external/lua/lpkt4.h>
+
+#include <iostream>
+
+using namespace std;
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::hooks;
+using namespace isc::kea;
+
+namespace {
+    // Lua state
+    lua_State* L;
+};
+
+extern "C" {
+
+// Framework functions
+
+// version
+int version() {
+    return (KEA_HOOKS_VERSION);
+}
+
+// load
+int load(LibraryHandle& handle) {
+    // Get a new state
+    L = luaL_newstate();
+    if (!L) {
+        cerr << "can't get new state\n";
+        return (1);
+    }
+
+    // Check against version mismatch
+    luaL_checkversion(L);
+
+    // Add option and pkt4 as to be preloaded modules
+    static_cast<void>(luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"));
+    lua_pushcfunction(L, luaopen_option);
+    lua_setfield(L, -2, "option");
+    lua_pushcfunction(L, luaopen_pkt4);
+    lua_setfield(L, -2, "pkt4");
+    lua_pop(L, 1);
+    
+    // Load librairies
+    luaL_openlibs(L);
+
+    // Load option
+    luaL_requiref(L, LUA_OPTIONLIBNAME, luaopen_option, 1);
+    lua_pop(L, 1);
+
+    // Load pkt4
+    luaL_requiref(L, LUA_PKT4LIBNAME, luaopen_pkt4, 1);
+    lua_pop(L, 1);
+
+    // Get the script module name (default "hook.lua" file)
+    ConstElementPtr script = handle.getParameter("script");
+    string scptname = "hook.lua";
+    if (script && script->getType() == Element::string) {
+        scptname = script->stringValue();
+    } else {
+        cout << "no \"script\" parameter: using \"hook.hua\"\n";
+    }
+    int ret = luaL_loadfile(L, scptname.c_str());
+    switch (ret) {
+    case LUA_OK:
+        break;
+    case LUA_ERRSYNTAX:
+        cerr << "syntax error in \"" << scptname << "\": "
+             << lua_tostring(L, -1) << "\n";
+        return (2);
+    case LUA_ERRFILE:
+        cerr << "bad file \"" << scptname << "\": "
+             << lua_tostring(L, -1) << "\n";
+        return (2);
+    case LUA_ERRMEM:
+    case LUA_ERRGCMM:
+        cerr << "memory problem loading \"" << scptname << "\": "
+             << lua_tostring(L, -1) << "\n";
+        return (2);
+    default:
+        cerr << "unspecified error (" << ret
+             << ") loading \"" << scptname << "\": "
+             << lua_tostring(L, -1) << "\n";
+        return (2);
+    }
+
+    // Run the script
+    ret = lua_pcall(L, 0, 0, 0);
+    switch (ret) {
+    case LUA_OK:
+        break;
+    case LUA_ERRRUN:
+        cerr << "runtime error from \"" << scptname << "\": "
+             << lua_tostring(L, -1) << "\n";
+        return (3);
+    case LUA_ERRMEM:
+    case LUA_ERRGCMM:
+        cerr << "memory problem running \"" << scptname << "\": "
+             << lua_tostring(L, -1) << "\n";
+        return (3);
+    default:
+        cerr << "unspecified error (" << ret
+             << ") running \"" << scptname << "\": "
+             << lua_tostring(L, -1) << "\n";
+        return (3);
+    }
+
+    // Get pkt4_receive handler
+    ret = lua_getglobal(L, "pkt4_receive");
+    switch (ret) {
+    case LUA_TNIL:
+        cerr << "can't find \"pkt4_receive\"\n";
+        return (4);
+    case LUA_TFUNCTION:
+        break;
+    default:
+        cerr << "\"pkt4_receive\" is not a function, it is a "
+             << lua_typename(L, ret) << "\n";
+        return (4);
+    }
+    lua_pop(L, 1);
+
+    return (0);
+}
+
+// unload
+int unload() {
+    // Release the state
+    lua_close(L);
+    L = NULL;
+
+    return (0);
+}
+
+// pkt4_receive hook
+int pkt4_receive(CalloutHandle& handle) {
+    if (lua_getglobal(L, "pkt4_receive") != LUA_TFUNCTION) {
+        return (0);
+    }
+    cout << "pkt4_receive: enter\n";
+
+    Pkt4Ptr query4;
+    handle.getArgument("query4", query4);
+    if (!query4) {
+        cerr << "pkt4_receive: null query4\n";
+        return (0);
+    }
+
+    void *query = lua_newuserdata(L, sizeof(l_pkt4));
+    if (!query) {
+        cerr << "lua_newuserdata failed\n";
+        return (0);
+    }
+    memset(query, 0, sizeof(l_pkt4));
+    (static_cast<l_pkt4*>(query))->object = query4;
+    if (luaL_getmetatable(L, LUA_KEAPKT4) == LUA_TNIL) {
+        cerr << "no metatable for " << LUA_KEAPKT4 << "\n";
+    }
+    lua_pop(L, 1);
+    luaL_setmetatable(L, LUA_KEAPKT4);
+    
+    int ret = lua_pcall(L, 1, 1, 0);
+    switch (ret) {
+    case LUA_OK:
+        break;
+    case LUA_ERRRUN:
+        cerr << "runtime error in pkt4_receive: "
+             << lua_tostring(L, -1) << "\n";
+        lua_pop(L, 1);
+        return (0);
+    case LUA_ERRMEM:
+    case LUA_ERRGCMM:
+        cerr << "memory problem in pkt4_receive: "
+             << lua_tostring(L, -1) << "\n";
+        lua_pop(L, 1);
+        return (0);
+    default:
+        cerr << "unspecified error (" << ret
+             << ") in pkt4_receive: "
+             << lua_tostring(L, -1) << "\n";
+        lua_pop(L, 1);
+        return (0);
+    }
+    if (lua_type(L, -1) != LUA_TNUMBER) {
+        cerr << "pkt4_receive didn't return a number\n";
+        lua_pop(L, 1);
+        return (0);
+    }
+    ret = static_cast<int>(lua_tonumber(L, -1));
+    lua_pop(L, 1);
+
+    cout << "pkt4_receive: return " << ret << "\n";
+    return (ret);
+}
+
+}
diff --git a/src/hooks/external/lua/hook.lua b/src/hooks/external/lua/hook.lua
new file mode 100644 (file)
index 0000000..384e3e6
--- /dev/null
@@ -0,0 +1,27 @@
+-- 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 lua
+
+print("hook.lua is loading")
+
+-- require kea
+
+NEXT_STEP_CONTINUE = 0
+NEXT_STEP_SKIP = 1
+NEXT_STEP_DROP = 2
+
+-- pkt4_receive hook point
+--
+-- parameter: inout Pkt4Ptr query4 
+-- return: next step
+
+function pkt4_receive(query4)
+    print("pkt4_receive: handler is called with", tostring(query4))
+    return NEXT_STEP_CONTINUE
+end
+
+print("hook.lua loaded")
diff --git a/src/hooks/external/lua/loption.cc b/src/hooks/external/lua/loption.cc
new file mode 100644 (file)
index 0000000..d47c976
--- /dev/null
@@ -0,0 +1,150 @@
+// 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 <lua.hpp>
+
+#include <hooks/external/lua/loption.h>
+
+#include <iostream>
+
+using namespace std;
+using namespace isc::dhcp;
+using namespace isc::kea;
+
+// Constructor
+l_option::l_option() {}
+
+namespace { // anonymous namespace
+
+// factory(universe, type, data)
+int factory(lua_State* L) {
+    // Require 3 arguments
+    if (lua_gettop(L) - 1 != 3) {
+        return (luaL_error(L, "option.factory takes 3 arguments"));
+    }
+    if (lua_type(L, -3) != LUA_TNUMBER) {
+        return (luaL_error(L, "universe must be a number"));
+    }
+    if (lua_type(L, -2) != LUA_TNUMBER) {
+        return (luaL_error(L, "type must be a number"));
+    }
+    if (lua_type(L, -1) != LUA_TSTRING) {
+        return (luaL_error(L, "data must be a string"));
+    }
+    unsigned char u = static_cast<unsigned char>(lua_tonumber(L, -3));
+    unsigned short t = static_cast<unsigned short>(lua_tonumber(L, -2));
+    Option::Universe universe;
+    switch (u) {
+    case 4:
+        universe = Option::V4;
+        if (t > 255) {
+            return (luaL_error(L, "out of range type for DHCPv4: %d",
+                               static_cast<int>(t)));
+        }
+        break;
+    case 6:
+        universe = Option::V6;
+        break;
+    default:
+        return (luaL_error(L, "universe must be 4 or 6 (not %d)",
+                           static_cast<int>(u)));
+    }
+
+    size_t len = 0;
+    const char* d = lua_tolstring(L, -1, &len);
+    OptionBuffer data;
+    data.resize(len);
+    if (len) {
+        memmove(&data[0], d, len);
+    }
+
+    l_option* const self =
+        static_cast<l_option*>(lua_newuserdata(L, sizeof(l_option)));
+    memset(self, 0, sizeof(l_option));
+    self->object.reset(new Option(universe, t, data));
+    luaL_setmetatable(L, LUA_KEAOPTION);
+    return (1);
+}
+
+// __gc
+int option__gc(lua_State* L) {
+    // This is a critical code to avoid memory leaks
+    cout << "option__gc called\n";
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    self->object.reset();
+    return (0);
+}
+
+// __tostring
+int option__tostring(lua_State* L) {
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    lua_pushstring(L, self->object->toText(0).c_str());
+    return (1);
+}
+
+// getUniverse() method
+int getUniverse(lua_State* L) {
+    l_option* const self =
+        static_cast<l_option*>(luaL_checkudata(L, 1, LUA_KEAOPTION));
+    switch (self->object->getUniverse()) {
+    case Option::V4:
+        lua_pushinteger(L, 4);
+        return (1);
+    case Option::V6:
+        lua_pushinteger(L, 6);
+        return (1);
+    default:
+        return (luaL_error(L, "getUniverse"));
+    }
+}
+
+// Method table
+const luaL_Reg option_method[] = {
+    { "__gc", option__gc },
+    { "__tostring", option__tostring },
+    { "getUniverse", getUniverse },
+    { NULL, NULL }
+};
+
+// Function table
+const luaL_Reg option_function[] = {
+    { NULL, NULL }
+};
+
+// Create the module metadata
+void createmeta(lua_State* L) {
+    // create metatable
+    luaL_newmetatable(L, LUA_KEAOPTION);
+    // push metatable
+    lua_pushvalue(L, -1);
+    // metatable.__index = metatable
+    lua_setfield(L, -2, "__index");
+    // add methods
+    luaL_setfuncs(L, option_method, 0);
+    // pop new metatable
+    lua_pop(L, 1);
+}
+
+} // end of anonymous namespace
+
+namespace isc {
+namespace kea {
+
+// Initialize the module
+int luaopen_option(lua_State* L) {
+    // new module
+    luaL_newlib(L, option_function);
+    createmeta(L);
+
+    // constants
+
+    return (1);
+}
+
+} // namespace lua
+} // namespace isc
diff --git a/src/hooks/external/lua/loption.h b/src/hooks/external/lua/loption.h
new file mode 100644 (file)
index 0000000..c63fd37
--- /dev/null
@@ -0,0 +1,32 @@
+// 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 LOPTION_H
+#define LOPTION_H 1
+
+#include <dhcp/option.h>
+
+namespace isc {
+namespace kea {
+
+// Lua option class
+class l_option  {
+    l_option();
+
+public:
+    isc::dhcp::OptionPtr object;
+};
+
+#define LUA_KEAOPTION "kea-option"
+
+#define LUA_OPTIONLIBNAME "option"
+
+LUAMOD_API int luaopen_option(lua_State* L);
+
+} // namespace kea
+} // namespace isc
+
+#endif // LOPTION_H
diff --git a/src/hooks/external/lua/lpkt4.cc b/src/hooks/external/lua/lpkt4.cc
new file mode 100644 (file)
index 0000000..d6ccd05
--- /dev/null
@@ -0,0 +1,95 @@
+// 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 <lua.hpp>
+
+#include <hooks/external/lua/loption.h>
+#include <hooks/external/lua/lpkt4.h>
+
+#include <iostream>
+
+using namespace std;
+using namespace isc::dhcp;
+using namespace isc::kea;
+
+// Constructor
+l_pkt4::l_pkt4() {}
+
+namespace { // anonymous namespace
+
+// __gc
+int pkt4__gc(lua_State* L) {
+    // This is a critical code to avoid memory leaks
+    cout << "pkt4__gc called\n";
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    self->object.reset();
+    return (0);
+}
+
+// __tostring
+int pkt4__tostring(lua_State* L) {
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    lua_pushstring(L, self->object->toText().c_str());
+    return (1);
+}
+
+// addOption(const OptionPtr opt) method
+int addOption(lua_State* L) {
+    l_pkt4* const self =
+        static_cast<l_pkt4*>(luaL_checkudata(L, 1, LUA_KEAPKT4));
+    l_option* const sub =
+        static_cast<l_option*>(luaL_checkudata(L, 2, LUA_KEAOPTION));
+    self->object->addOption(sub->object);
+    return (0);
+}
+
+// Method table
+const luaL_Reg pkt4_method[] = {
+    { "__gc", pkt4__gc },
+    { "__tostring", pkt4__tostring },
+    { "addOption", addOption },
+    { NULL, NULL }
+};
+
+// Function table
+const luaL_Reg pkt4_function[] = {
+    { NULL, NULL }
+};
+
+// Create the module metadata
+void createmeta(lua_State* L) {
+    // create metatable
+    luaL_newmetatable(L, LUA_KEAPKT4);
+    // push metatable
+    lua_pushvalue(L, -1);
+    // metatable.__index = metatable
+    lua_setfield(L, -2, "__index");
+    // add methods
+    luaL_setfuncs(L, pkt4_method, 0);
+    // pop new metatable
+    lua_pop(L, 1);
+}
+
+} // end of anonymous namespace
+
+namespace isc {
+namespace kea {
+
+// Initialize the module
+int luaopen_pkt4(lua_State* L) {
+    // new module
+    luaL_newlib(L, pkt4_function);
+    createmeta(L);
+
+    // constants
+
+    return (1);
+}
+
+} // namespace lua
+} // namespace isc
diff --git a/src/hooks/external/lua/lpkt4.h b/src/hooks/external/lua/lpkt4.h
new file mode 100644 (file)
index 0000000..496038e
--- /dev/null
@@ -0,0 +1,32 @@
+// 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 LPKT4_H
+#define LPKT4_H 1
+
+#include <dhcp/pkt4.h>
+
+namespace isc {
+namespace kea {
+
+// Lua DHCPv4 packet class
+class l_pkt4  {
+    l_pkt4();
+
+public:
+    isc::dhcp::Pkt4Ptr object;
+};
+
+#define LUA_KEAPKT4 "kea-pkt4"
+
+#define LUA_PKT4LIBNAME "pkt4"
+
+LUAMOD_API int luaopen_pkt4(lua_State* L);
+
+} // namespace kea
+} // namespace isc
+
+#endif // LPKT4_H
diff --git a/src/hooks/external/lua/tests.cc b/src/hooks/external/lua/tests.cc
new file mode 100644 (file)
index 0000000..5d21d3a
--- /dev/null
@@ -0,0 +1,146 @@
+// 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\": "
+    "   { \"script\": \"hook.lua\" }"
+    " }] }";
+
+// 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);
+}
index cd595caa900be7aff7c6ea8512e7ba3c7761b2d5..1e05e93546b059a03c49d8f86472278f6c032a28 100644 (file)
@@ -42,3 +42,6 @@ problem but it means memory leaks can become hard to track.
 ocaml is statically typed so there is no type check in the runtime
 even in the C++ code. So if you bug an external declaration you
 likely bug the whole thing!
+
+To finish ocaml has a standard type named option (None | Some of)
+so I used the name opt (vs option) for the kea option type.