]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add per-thread Lua FFI load-balancing policies
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 27 Aug 2020 09:00:06 +0000 (11:00 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 1 Sep 2020 12:34:08 +0000 (14:34 +0200)
This allows Lua FFI load-balancing policies that don't need access
to the global, shared Lua state to be lock-less, avoiding lock contention.

25 files changed:
pdns/dnsdist-console.cc
pdns/dnsdist-lbpolicies.hh
pdns/dnsdist-lua-actions.cc
pdns/dnsdist-lua-bindings-dnsquestion.cc
pdns/dnsdist-lua-bindings.cc
pdns/dnsdist-lua-inspection.cc
pdns/dnsdist-lua-rules.cc
pdns/dnsdist-lua-vars.cc
pdns/dnsdist-lua.cc
pdns/dnsdist-lua.hh
pdns/dnsdist-tcp.cc
pdns/dnsdist-web.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/dnsdist-lbpolicies.cc
pdns/dnsdistdist/dnsdist-lua-bindings-dnscrypt.cc
pdns/dnsdistdist/dnsdist-lua-bindings-kvs.cc
pdns/dnsdistdist/dnsdist-lua-bindings-packetcache.cc
pdns/dnsdistdist/dnsdist-lua-bindings-protobuf.cc
pdns/dnsdistdist/dnsdist-lua-ffi.cc
pdns/dnsdistdist/docs/advanced/tuning.rst
pdns/dnsdistdist/docs/guides/serverselection.rst
pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc
regression-tests.dnsdist/test_Routing.py

index 177837f522296bfdb8e99accfce552f99382fb07..130e4cc628b9d46096f8bcd87b366e7fd66d2c9b 100644 (file)
@@ -528,7 +528,9 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "SetNegativeAndSOAAction", true, "nxd, zone, ttl, mname, rname, serial, refresh, retry, expire, minimum [, options]", "Turn a query into a NXDomain or NoData answer and sets a SOA record in the additional section" },
   { "setPayloadSizeOnSelfGeneratedAnswers", true, "payloadSize", "set the UDP payload size advertised via EDNS on self-generated responses" },
   { "setPoolServerPolicy", true, "policy, pool", "set the server selection policy for this pool to that policy" },
-  { "setPoolServerPolicyLua", true, "name, func, pool", "set the server selection policy for this pool to one named 'name' and provided by 'function'" },
+  { "setPoolServerPolicyLua", true, "name, function, pool", "set the server selection policy for this pool to one named 'name' and provided by 'function'" },
+  { "setPoolServerPolicyLuaFFI", true, "name, function, pool", "set the server selection policy for this pool to one named 'name' and provided by 'function'" },
+  { "setPoolServerPolicyLuaFFIPerThread", true, "name, code", "set server selection policy for this pool to one named 'name' and returned by the Lua FFI code passed in 'code'" },
   { "setPreserveTrailingData", true, "bool", "set whether trailing data should be preserved while adding ECS or XPF records to incoming queries" },
   { "setQueryCount", true, "bool", "set whether queries should be counted" },
   { "setQueryCountFilter", true, "func", "filter queries that would be counted, where `func` is a function with parameter `dq` which decides whether a query should and how it should be counted" },
@@ -541,6 +543,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "setServerPolicy", true, "policy", "set server selection policy to that policy" },
   { "setServerPolicyLua", true, "name, function", "set server selection policy to one named 'name' and provided by 'function'" },
   { "setServerPolicyLuaFFI", true, "name, function", "set server selection policy to one named 'name' and provided by the Lua FFI 'function'" },
+  { "setServerPolicyLuaFFIPerThread", true, "name, code", "set server selection policy to one named 'name' and returned by the Lua FFI code passed in 'code'" },
   { "setServFailWhenNoServer", true, "bool", "if set, return a ServFail when no servers are available, instead of the default behaviour of dropping the query" },
   { "setStaleCacheEntriesTTL", true, "n", "allows using cache entries expired for at most n seconds when there is no backend available to answer for a query" },
   { "setSyslogFacility", true, "facility", "set the syslog logging facility to 'facility'. Defaults to LOG_DAEMON" },
index 7ad5f25cff1f94e0236373aca0cd100199176f05..395deec2b5e9e00534c9c0445559566790818dea 100644 (file)
@@ -27,37 +27,69 @@ struct dnsdist_ffi_dnsquestion_t;
 
 struct DownstreamState;
 
-struct ServerPolicy
+struct PerThreadPoliciesState;
+
+class ServerPolicy
 {
+public:
   template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
   using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
   typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
   typedef std::function<unsigned int(dnsdist_ffi_servers_list_t* servers, dnsdist_ffi_dnsquestion_t* dq)> ffipolicyfunc_t;
 
-  ServerPolicy(const std::string& name_, policyfunc_t policy_, bool isLua_): name(name_), policy(policy_), isLua(isLua_)
+  ServerPolicy(const std::string& name_, policyfunc_t policy_, bool isLua_): d_name(name_), d_policy(policy_), d_isLua(isLua_)
   {
   }
-  ServerPolicy(const std::string& name_, ffipolicyfunc_t policy_): name(name_), ffipolicy(policy_), isLua(true), isFFI(true)
+
+  ServerPolicy(const std::string& name_, ffipolicyfunc_t policy_): d_name(name_), d_ffipolicy(policy_), d_isLua(true), d_isFFI(true)
   {
   }
+
+  /* create a per-thread FFI policy */
+  ServerPolicy(const std::string& name_, const std::string& code);
+
   ServerPolicy()
   {
   }
 
-  string name;
-  policyfunc_t policy;
-  ffipolicyfunc_t ffipolicy;
-  bool isLua{false};
-  bool isFFI{false};
+  std::shared_ptr<DownstreamState> getSelectedBackend(const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq) const;
+
+  const std::string& getName() const
+  {
+    return d_name;
+  }
 
   std::string toString() const {
-    return string("ServerPolicy") + (isLua ? " (Lua)" : "") + " \"" + name + "\"";
+    return string("ServerPolicy") + (d_isLua ? " (Lua)" : "") + " \"" + d_name + "\"";
   }
+
+private:
+  struct PerThreadState
+  {
+    LuaContext d_luaContext;
+    std::unordered_map<std::string, ffipolicyfunc_t> d_policies;
+    bool d_initialized{false};
+  };
+
+  const ffipolicyfunc_t& getPerThreadPolicy() const;
+  static thread_local PerThreadState t_perThreadState;
+
+
+public:
+  std::string d_name;
+  std::string d_perThreadPolicyCode;
+
+  policyfunc_t d_policy;
+  ffipolicyfunc_t d_ffipolicy;
+
+  bool d_isLua{false};
+  bool d_isFFI{false};
+  bool d_isPerThread{false};
 };
 
 struct ServerPool;
 
-using pools_t=map<std::string,std::shared_ptr<ServerPool>>;
+using pools_t = map<std::string, std::shared_ptr<ServerPool>>;
 std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName);
 std::shared_ptr<ServerPool> createPoolIfNotExists(pools_t& pools, const string& poolName);
 void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<ServerPolicy> policy);
@@ -75,7 +107,6 @@ std::shared_ptr<DownstreamState> whashedFromHash(const ServerPolicy::NumberedSer
 std::shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
 std::shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t hash);
 std::shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
-std::shared_ptr<DownstreamState> getSelectedBackendFromPolicy(const ServerPolicy& policy, const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq);
 
 extern double g_consistentHashBalancingFactor;
 extern double g_weightedBalancingFactor;
index ef47d25165ba4e93e7323021a3b9f8e6a9894ec3..dbbcaadfda8b0c8bda6057647accb46a9db5d53e 100644 (file)
@@ -1505,9 +1505,9 @@ void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config)
   }
 }
 
-void setupLuaActions()
+void setupLuaActions(LuaContext& luaCtx)
 {
-  g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
+  luaCtx.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
       boost::uuids::uuid uuid;
       uint64_t creationOrder;
       parseRuleParams(params, uuid, creationOrder);
@@ -1517,7 +1517,7 @@ void setupLuaActions()
       return std::make_shared<DNSDistRuleAction>(ra);
     });
 
-  g_lua.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
+  luaCtx.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
       if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
         throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
       }
@@ -1525,7 +1525,7 @@ void setupLuaActions()
       addAction(&g_rulactions, var, boost::get<std::shared_ptr<DNSAction> >(era), params);
     });
 
-  g_lua.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
+  luaCtx.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
       if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
         throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
       }
@@ -1533,7 +1533,7 @@ void setupLuaActions()
       addAction(&g_resprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
     });
 
-  g_lua.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
+  luaCtx.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
       if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
         throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
       }
@@ -1541,7 +1541,7 @@ void setupLuaActions()
       addAction(&g_cachehitresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
     });
 
-  g_lua.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
+  luaCtx.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
       if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
         throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
       }
@@ -1549,7 +1549,7 @@ void setupLuaActions()
       addAction(&g_selfansweredresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
     });
 
-  g_lua.registerFunction<void(DNSAction::*)()>("printStats", [](const DNSAction& ta) {
+  luaCtx.registerFunction<void(DNSAction::*)()>("printStats", [](const DNSAction& ta) {
       setLuaNoSideEffect();
       auto stats = ta.getStats();
       for(const auto& s : stats) {
@@ -1561,7 +1561,7 @@ void setupLuaActions()
       }
     });
 
-  g_lua.writeFunction("getAction", [](unsigned int num) {
+  luaCtx.writeFunction("getAction", [](unsigned int num) {
       setLuaNoSideEffect();
       boost::optional<std::shared_ptr<DNSAction>> ret;
       auto rulactions = g_rulactions.getCopy();
@@ -1570,39 +1570,39 @@ void setupLuaActions()
       return ret;
     });
 
-  g_lua.registerFunction("getStats", &DNSAction::getStats);
+  luaCtx.registerFunction("getStats", &DNSAction::getStats);
 
-  g_lua.writeFunction("LuaAction", [](LuaAction::func_t func) {
+  luaCtx.writeFunction("LuaAction", [](LuaAction::func_t func) {
       setLuaSideEffect();
       return std::shared_ptr<DNSAction>(new LuaAction(func));
     });
 
-  g_lua.writeFunction("LuaFFIAction", [](LuaFFIAction::func_t func) {
+  luaCtx.writeFunction("LuaFFIAction", [](LuaFFIAction::func_t func) {
       setLuaSideEffect();
       return std::shared_ptr<DNSAction>(new LuaFFIAction(func));
     });
 
-  g_lua.writeFunction("NoRecurseAction", []() {
+  luaCtx.writeFunction("NoRecurseAction", []() {
       return std::shared_ptr<DNSAction>(new NoRecurseAction);
     });
 
-  g_lua.writeFunction("MacAddrAction", [](int code) {
+  luaCtx.writeFunction("MacAddrAction", [](int code) {
       return std::shared_ptr<DNSAction>(new MacAddrAction(code));
     });
 
-  g_lua.writeFunction("PoolAction", [](const std::string& a) {
+  luaCtx.writeFunction("PoolAction", [](const std::string& a) {
       return std::shared_ptr<DNSAction>(new PoolAction(a));
     });
 
-  g_lua.writeFunction("QPSAction", [](int limit) {
+  luaCtx.writeFunction("QPSAction", [](int limit) {
       return std::shared_ptr<DNSAction>(new QPSAction(limit));
     });
 
-  g_lua.writeFunction("QPSPoolAction", [](int limit, const std::string& a) {
+  luaCtx.writeFunction("QPSPoolAction", [](int limit, const std::string& a) {
       return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a));
     });
 
-  g_lua.writeFunction("SpoofAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<std::string> b, boost::optional<responseParams_t> vars) {
+  luaCtx.writeFunction("SpoofAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<std::string> b, boost::optional<responseParams_t> vars) {
       vector<ComboAddress> addrs;
       if(auto s = boost::get<std::string>(&inp))
         addrs.push_back(ComboAddress(*s));
@@ -1621,97 +1621,97 @@ void setupLuaActions()
       return ret;
     });
 
-  g_lua.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional<responseParams_t> vars) {
+  luaCtx.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional<responseParams_t> vars) {
       auto ret = std::shared_ptr<DNSAction>(new SpoofAction(DNSName(a)));
       auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
       parseResponseConfig(vars, sa->d_responseConfig);
       return ret;
     });
 
-  g_lua.writeFunction("SpoofRawAction", [](const std::string& raw, boost::optional<responseParams_t> vars) {
+  luaCtx.writeFunction("SpoofRawAction", [](const std::string& raw, boost::optional<responseParams_t> vars) {
       auto ret = std::shared_ptr<DNSAction>(new SpoofAction(raw));
       auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
       parseResponseConfig(vars, sa->d_responseConfig);
       return ret;
     });
 
-  g_lua.writeFunction("DropAction", []() {
+  luaCtx.writeFunction("DropAction", []() {
       return std::shared_ptr<DNSAction>(new DropAction);
     });
 
-  g_lua.writeFunction("AllowAction", []() {
+  luaCtx.writeFunction("AllowAction", []() {
       return std::shared_ptr<DNSAction>(new AllowAction);
     });
 
-  g_lua.writeFunction("NoneAction", []() {
+  luaCtx.writeFunction("NoneAction", []() {
       return std::shared_ptr<DNSAction>(new NoneAction);
     });
 
-  g_lua.writeFunction("DelayAction", [](int msec) {
+  luaCtx.writeFunction("DelayAction", [](int msec) {
       return std::shared_ptr<DNSAction>(new DelayAction(msec));
     });
 
-  g_lua.writeFunction("TCAction", []() {
+  luaCtx.writeFunction("TCAction", []() {
       return std::shared_ptr<DNSAction>(new TCAction);
     });
 
-  g_lua.writeFunction("DisableValidationAction", []() {
+  luaCtx.writeFunction("DisableValidationAction", []() {
       return std::shared_ptr<DNSAction>(new DisableValidationAction);
     });
 
-  g_lua.writeFunction("LogAction", [](boost::optional<std::string> fname, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) {
+  luaCtx.writeFunction("LogAction", [](boost::optional<std::string> fname, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) {
       return std::shared_ptr<DNSAction>(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
     });
 
-  g_lua.writeFunction("LogResponseAction", [](boost::optional<std::string> fname, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) {
+  luaCtx.writeFunction("LogResponseAction", [](boost::optional<std::string> fname, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) {
       return std::shared_ptr<DNSResponseAction>(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
     });
 
-  g_lua.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
+  luaCtx.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
       auto ret = std::shared_ptr<DNSAction>(new RCodeAction(rcode));
       auto rca = std::dynamic_pointer_cast<RCodeAction>(ret);
       parseResponseConfig(vars, rca->d_responseConfig);
       return ret;
     });
 
-  g_lua.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
+  luaCtx.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
       auto ret = std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
       auto erca = std::dynamic_pointer_cast<ERCodeAction>(ret);
       parseResponseConfig(vars, erca->d_responseConfig);
       return ret;
     });
 
-  g_lua.writeFunction("SkipCacheAction", []() {
+  luaCtx.writeFunction("SkipCacheAction", []() {
       return std::shared_ptr<DNSAction>(new SkipCacheAction);
     });
 
-  g_lua.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
+  luaCtx.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
       return std::shared_ptr<DNSAction>(new TempFailureCacheTTLAction(maxTTL));
     });
 
-  g_lua.writeFunction("DropResponseAction", []() {
+  luaCtx.writeFunction("DropResponseAction", []() {
       return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
     });
 
-  g_lua.writeFunction("AllowResponseAction", []() {
+  luaCtx.writeFunction("AllowResponseAction", []() {
       return std::shared_ptr<DNSResponseAction>(new AllowResponseAction);
     });
 
-  g_lua.writeFunction("DelayResponseAction", [](int msec) {
+  luaCtx.writeFunction("DelayResponseAction", [](int msec) {
       return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
     });
 
-  g_lua.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) {
+  luaCtx.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) {
       setLuaSideEffect();
       return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func));
     });
 
-  g_lua.writeFunction("LuaFFIResponseAction", [](LuaFFIResponseAction::func_t func) {
+  luaCtx.writeFunction("LuaFFIResponseAction", [](LuaFFIResponseAction::func_t func) {
       setLuaSideEffect();
       return std::shared_ptr<DNSResponseAction>(new LuaFFIResponseAction(func));
     });
 
-  g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<std::unordered_map<std::string, std::string>> vars) {
+  luaCtx.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<std::unordered_map<std::string, std::string>> vars) {
       if (logger) {
         // avoids potentially-evaluated-expression warning with clang.
         RemoteLoggerInterface& rl = *logger.get();
@@ -1739,7 +1739,7 @@ void setupLuaActions()
 #endif
     });
 
-  g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME, boost::optional<std::unordered_map<std::string, std::string>> vars) {
+  luaCtx.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME, boost::optional<std::unordered_map<std::string, std::string>> vars) {
       if (logger) {
         // avoids potentially-evaluated-expression warning with clang.
         RemoteLoggerInterface& rl = *logger.get();
@@ -1767,7 +1767,7 @@ void setupLuaActions()
 #endif
     });
 
-  g_lua.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
+  luaCtx.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
 #ifdef HAVE_PROTOBUF
       return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
 #else
@@ -1775,7 +1775,7 @@ void setupLuaActions()
 #endif
     });
 
-  g_lua.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) {
+  luaCtx.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) {
 #ifdef HAVE_PROTOBUF
       return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
 #else
@@ -1783,30 +1783,30 @@ void setupLuaActions()
 #endif
     });
 
-  g_lua.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) {
+  luaCtx.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) {
       return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), addECS ? *addECS : false));
     });
 
-  g_lua.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
+  luaCtx.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
       return std::shared_ptr<DNSAction>(new ECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
     });
 
-  g_lua.writeFunction("ECSOverrideAction", [](bool ecsOverride) {
+  luaCtx.writeFunction("ECSOverrideAction", [](bool ecsOverride) {
       return std::shared_ptr<DNSAction>(new ECSOverrideAction(ecsOverride));
     });
 
-  g_lua.writeFunction("DisableECSAction", []() {
+  luaCtx.writeFunction("DisableECSAction", []() {
       return std::shared_ptr<DNSAction>(new DisableECSAction());
     });
 
-  g_lua.writeFunction("SetECSAction", [](const std::string v4, boost::optional<std::string> v6) {
+  luaCtx.writeFunction("SetECSAction", [](const std::string v4, boost::optional<std::string> v6) {
       if (v6) {
         return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4), Netmask(*v6)));
       }
       return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4)));
     });
 
-  g_lua.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) {
+  luaCtx.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
       return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : ""));
 #else
@@ -1814,7 +1814,7 @@ void setupLuaActions()
 #endif /* HAVE_NET_SNMP */
     });
 
-  g_lua.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) {
+  luaCtx.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
       return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : ""));
 #else
@@ -1822,20 +1822,20 @@ void setupLuaActions()
 #endif /* HAVE_NET_SNMP */
     });
 
-  g_lua.writeFunction("TagAction", [](std::string tag, std::string value) {
+  luaCtx.writeFunction("TagAction", [](std::string tag, std::string value) {
       return std::shared_ptr<DNSAction>(new TagAction(tag, value));
     });
 
-  g_lua.writeFunction("TagResponseAction", [](std::string tag, std::string value) {
+  luaCtx.writeFunction("TagResponseAction", [](std::string tag, std::string value) {
       return std::shared_ptr<DNSResponseAction>(new TagResponseAction(tag, value));
     });
 
-  g_lua.writeFunction("ContinueAction", [](std::shared_ptr<DNSAction> action) {
+  luaCtx.writeFunction("ContinueAction", [](std::shared_ptr<DNSAction> action) {
       return std::shared_ptr<DNSAction>(new ContinueAction(action));
     });
 
 #ifdef HAVE_DNS_OVER_HTTPS
-  g_lua.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) {
+  luaCtx.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) {
       auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, body, contentType ? *contentType : ""));
       auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret);
       parseResponseConfig(vars, hsa->d_responseConfig);
@@ -1843,18 +1843,18 @@ void setupLuaActions()
     });
 #endif /* HAVE_DNS_OVER_HTTPS */
 
-  g_lua.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
+  luaCtx.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
       return std::shared_ptr<DNSAction>(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag));
     });
 
-  g_lua.writeFunction("SetNegativeAndSOAAction", [](bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, boost::optional<responseParams_t> vars) {
+  luaCtx.writeFunction("SetNegativeAndSOAAction", [](bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, boost::optional<responseParams_t> vars) {
       auto ret = std::shared_ptr<DNSAction>(new SetNegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum));
       auto action = std::dynamic_pointer_cast<SetNegativeAndSOAAction>(ret);
       parseResponseConfig(vars, action->d_responseConfig);
       return ret;
     });
 
-  g_lua.writeFunction("SetProxyProtocolValuesAction", [](const std::vector<std::pair<uint8_t, std::string>>& values) {
+  luaCtx.writeFunction("SetProxyProtocolValuesAction", [](const std::vector<std::pair<uint8_t, std::string>>& values) {
       return std::shared_ptr<DNSAction>(new SetProxyProtocolValuesAction(values));
     });
 }
index 9c87d129c8f9b65c2893f8aed69493b6820810e4..eaa1ef31bc607ec6710e288de002f44c579f2426 100644 (file)
 #include "dnsdist-lua.hh"
 #include "dnsparser.hh"
 
-void setupLuaBindingsDNSQuestion()
+void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
 {
   /* DNSQuestion */
   /* PowerDNS DNSQuestion compat */
-  g_lua.registerMember<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion& dq) -> const ComboAddress { return *dq.local; }, [](DNSQuestion& dq, const ComboAddress newLocal) { (void) newLocal; });
-  g_lua.registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName { return *dq.qname; }, [](DNSQuestion& dq, const DNSName newName) { (void) newName; });
-  g_lua.registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
-  g_lua.registerMember<uint16_t (DNSQuestion::*)>("qclass", [](const DNSQuestion& dq) -> uint16_t { return dq.qclass; }, [](DNSQuestion& dq, uint16_t newClass) { (void) newClass; });
-  g_lua.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return dq.dh->rcode; }, [](DNSQuestion& dq, int newRCode) { dq.dh->rcode = newRCode; });
-  g_lua.registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress { return *dq.remote; }, [](DNSQuestion& dq, const ComboAddress newRemote) { (void) newRemote; });
+  luaCtx.registerMember<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion& dq) -> const ComboAddress { return *dq.local; }, [](DNSQuestion& dq, const ComboAddress newLocal) { (void) newLocal; });
+  luaCtx.registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName { return *dq.qname; }, [](DNSQuestion& dq, const DNSName newName) { (void) newName; });
+  luaCtx.registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
+  luaCtx.registerMember<uint16_t (DNSQuestion::*)>("qclass", [](const DNSQuestion& dq) -> uint16_t { return dq.qclass; }, [](DNSQuestion& dq, uint16_t newClass) { (void) newClass; });
+  luaCtx.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return dq.dh->rcode; }, [](DNSQuestion& dq, int newRCode) { dq.dh->rcode = newRCode; });
+  luaCtx.registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress { return *dq.remote; }, [](DNSQuestion& dq, const ComboAddress newRemote) { (void) newRemote; });
   /* DNSDist DNSQuestion */
-  g_lua.registerMember("dh", &DNSQuestion::dh);
-  g_lua.registerMember<uint16_t (DNSQuestion::*)>("len", [](const DNSQuestion& dq) -> uint16_t { return dq.len; }, [](DNSQuestion& dq, uint16_t newlen) { dq.len = newlen; });
-  g_lua.registerMember<uint8_t (DNSQuestion::*)>("opcode", [](const DNSQuestion& dq) -> uint8_t { return dq.dh->opcode; }, [](DNSQuestion& dq, uint8_t newOpcode) { (void) newOpcode; });
-  g_lua.registerMember<size_t (DNSQuestion::*)>("size", [](const DNSQuestion& dq) -> size_t { return dq.size; }, [](DNSQuestion& dq, size_t newSize) { (void) newSize; });
-  g_lua.registerMember<bool (DNSQuestion::*)>("tcp", [](const DNSQuestion& dq) -> bool { return dq.tcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
-  g_lua.registerMember<bool (DNSQuestion::*)>("skipCache", [](const DNSQuestion& dq) -> bool { return dq.skipCache; }, [](DNSQuestion& dq, bool newSkipCache) { dq.skipCache = newSkipCache; });
-  g_lua.registerMember<bool (DNSQuestion::*)>("useECS", [](const DNSQuestion& dq) -> bool { return dq.useECS; }, [](DNSQuestion& dq, bool useECS) { dq.useECS = useECS; });
-  g_lua.registerMember<bool (DNSQuestion::*)>("ecsOverride", [](const DNSQuestion& dq) -> bool { return dq.ecsOverride; }, [](DNSQuestion& dq, bool ecsOverride) { dq.ecsOverride = ecsOverride; });
-  g_lua.registerMember<uint16_t (DNSQuestion::*)>("ecsPrefixLength", [](const DNSQuestion& dq) -> uint16_t { return dq.ecsPrefixLength; }, [](DNSQuestion& dq, uint16_t newPrefixLength) { dq.ecsPrefixLength = newPrefixLength; });
-  g_lua.registerMember<boost::optional<uint32_t> (DNSQuestion::*)>("tempFailureTTL",
+  luaCtx.registerMember("dh", &DNSQuestion::dh);
+  luaCtx.registerMember<uint16_t (DNSQuestion::*)>("len", [](const DNSQuestion& dq) -> uint16_t { return dq.len; }, [](DNSQuestion& dq, uint16_t newlen) { dq.len = newlen; });
+  luaCtx.registerMember<uint8_t (DNSQuestion::*)>("opcode", [](const DNSQuestion& dq) -> uint8_t { return dq.dh->opcode; }, [](DNSQuestion& dq, uint8_t newOpcode) { (void) newOpcode; });
+  luaCtx.registerMember<size_t (DNSQuestion::*)>("size", [](const DNSQuestion& dq) -> size_t { return dq.size; }, [](DNSQuestion& dq, size_t newSize) { (void) newSize; });
+  luaCtx.registerMember<bool (DNSQuestion::*)>("tcp", [](const DNSQuestion& dq) -> bool { return dq.tcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
+  luaCtx.registerMember<bool (DNSQuestion::*)>("skipCache", [](const DNSQuestion& dq) -> bool { return dq.skipCache; }, [](DNSQuestion& dq, bool newSkipCache) { dq.skipCache = newSkipCache; });
+  luaCtx.registerMember<bool (DNSQuestion::*)>("useECS", [](const DNSQuestion& dq) -> bool { return dq.useECS; }, [](DNSQuestion& dq, bool useECS) { dq.useECS = useECS; });
+  luaCtx.registerMember<bool (DNSQuestion::*)>("ecsOverride", [](const DNSQuestion& dq) -> bool { return dq.ecsOverride; }, [](DNSQuestion& dq, bool ecsOverride) { dq.ecsOverride = ecsOverride; });
+  luaCtx.registerMember<uint16_t (DNSQuestion::*)>("ecsPrefixLength", [](const DNSQuestion& dq) -> uint16_t { return dq.ecsPrefixLength; }, [](DNSQuestion& dq, uint16_t newPrefixLength) { dq.ecsPrefixLength = newPrefixLength; });
+  luaCtx.registerMember<boost::optional<uint32_t> (DNSQuestion::*)>("tempFailureTTL",
       [](const DNSQuestion& dq) -> boost::optional<uint32_t> {
         return dq.tempFailureTTL;
       },
@@ -52,29 +52,29 @@ void setupLuaBindingsDNSQuestion()
         dq.tempFailureTTL = newValue;
       }
     );
-  g_lua.registerFunction<bool(DNSQuestion::*)()>("getDO", [](const DNSQuestion& dq) {
+  luaCtx.registerFunction<bool(DNSQuestion::*)()>("getDO", [](const DNSQuestion& dq) {
       return getEDNSZ(dq) & EDNS_HEADER_FLAG_DO;
     });
 
-  g_lua.registerFunction<std::map<uint16_t, EDNSOptionView>(DNSQuestion::*)()>("getEDNSOptions", [](DNSQuestion& dq) {
+  luaCtx.registerFunction<std::map<uint16_t, EDNSOptionView>(DNSQuestion::*)()>("getEDNSOptions", [](DNSQuestion& dq) {
       if (dq.ednsOptions == nullptr) {
         parseEDNSOptions(dq);
       }
 
       return *dq.ednsOptions;
     });
-  g_lua.registerFunction<std::string(DNSQuestion::*)(void)>("getTrailingData", [](const DNSQuestion& dq) {
+  luaCtx.registerFunction<std::string(DNSQuestion::*)(void)>("getTrailingData", [](const DNSQuestion& dq) {
       return dq.getTrailingData();
     });
-  g_lua.registerFunction<bool(DNSQuestion::*)(std::string)>("setTrailingData", [](DNSQuestion& dq, const std::string& tail) {
+  luaCtx.registerFunction<bool(DNSQuestion::*)(std::string)>("setTrailingData", [](DNSQuestion& dq, const std::string& tail) {
       return dq.setTrailingData(tail);
     });
 
-  g_lua.registerFunction<std::string(DNSQuestion::*)()>("getServerNameIndication", [](const DNSQuestion& dq) {
+  luaCtx.registerFunction<std::string(DNSQuestion::*)()>("getServerNameIndication", [](const DNSQuestion& dq) {
       return dq.sni;
     });
 
-  g_lua.registerFunction<void(DNSQuestion::*)(std::string)>("sendTrap", [](const DNSQuestion& dq, boost::optional<std::string> reason) {
+  luaCtx.registerFunction<void(DNSQuestion::*)(std::string)>("sendTrap", [](const DNSQuestion& dq, boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
       if (g_snmpAgent && g_snmpTrapsEnabled) {
         g_snmpAgent->sendDNSTrap(dq, reason ? *reason : "");
@@ -82,13 +82,13 @@ void setupLuaBindingsDNSQuestion()
 #endif /* HAVE_NET_SNMP */
     });
 
-  g_lua.registerFunction<void(DNSQuestion::*)(std::string, std::string)>("setTag", [](DNSQuestion& dq, const std::string& strLabel, const std::string& strValue) {
+  luaCtx.registerFunction<void(DNSQuestion::*)(std::string, std::string)>("setTag", [](DNSQuestion& dq, const std::string& strLabel, const std::string& strValue) {
       if(dq.qTag == nullptr) {
         dq.qTag = std::make_shared<QTag>();
       }
       dq.qTag->insert({strLabel, strValue});
     });
-  g_lua.registerFunction<void(DNSQuestion::*)(vector<pair<string, string>>)>("setTagArray", [](DNSQuestion& dq, const vector<pair<string, string>>&tags) {
+  luaCtx.registerFunction<void(DNSQuestion::*)(vector<pair<string, string>>)>("setTagArray", [](DNSQuestion& dq, const vector<pair<string, string>>&tags) {
       if (!dq.qTag) {
         dq.qTag = std::make_shared<QTag>();
       }
@@ -97,7 +97,7 @@ void setupLuaBindingsDNSQuestion()
         dq.qTag->insert({tag.first, tag.second});
       }
     });
-  g_lua.registerFunction<string(DNSQuestion::*)(std::string)>("getTag", [](const DNSQuestion& dq, const std::string& strLabel) {
+  luaCtx.registerFunction<string(DNSQuestion::*)(std::string)>("getTag", [](const DNSQuestion& dq, const std::string& strLabel) {
       if (!dq.qTag) {
         return string();
       }
@@ -109,7 +109,7 @@ void setupLuaBindingsDNSQuestion()
       }
       return it->second;
     });
-  g_lua.registerFunction<QTag(DNSQuestion::*)(void)>("getTagArray", [](const DNSQuestion& dq) {
+  luaCtx.registerFunction<QTag(DNSQuestion::*)(void)>("getTagArray", [](const DNSQuestion& dq) {
       if (!dq.qTag) {
         QTag empty;
         return empty;
@@ -118,7 +118,7 @@ void setupLuaBindingsDNSQuestion()
       return *dq.qTag;
     });
 
-  g_lua.registerFunction<void(DNSQuestion::*)(std::vector<std::pair<uint8_t, std::string>>)>("setProxyProtocolValues", [](DNSQuestion& dq, const std::vector<std::pair<uint8_t, std::string>>& values) {
+  luaCtx.registerFunction<void(DNSQuestion::*)(std::vector<std::pair<uint8_t, std::string>>)>("setProxyProtocolValues", [](DNSQuestion& dq, const std::vector<std::pair<uint8_t, std::string>>& values) {
       if (!dq.proxyProtocolValues) {
         dq.proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
       }
@@ -131,36 +131,36 @@ void setupLuaBindingsDNSQuestion()
     });
 
   /* LuaWrapper doesn't support inheritance */
-  g_lua.registerMember<const ComboAddress (DNSResponse::*)>("localaddr", [](const DNSResponse& dq) -> const ComboAddress { return *dq.local; }, [](DNSResponse& dq, const ComboAddress newLocal) { (void) newLocal; });
-  g_lua.registerMember<const DNSName (DNSResponse::*)>("qname", [](const DNSResponse& dq) -> const DNSName { return *dq.qname; }, [](DNSResponse& dq, const DNSName newName) { (void) newName; });
-  g_lua.registerMember<uint16_t (DNSResponse::*)>("qtype", [](const DNSResponse& dq) -> uint16_t { return dq.qtype; }, [](DNSResponse& dq, uint16_t newType) { (void) newType; });
-  g_lua.registerMember<uint16_t (DNSResponse::*)>("qclass", [](const DNSResponse& dq) -> uint16_t { return dq.qclass; }, [](DNSResponse& dq, uint16_t newClass) { (void) newClass; });
-  g_lua.registerMember<int (DNSResponse::*)>("rcode", [](const DNSResponse& dq) -> int { return dq.dh->rcode; }, [](DNSResponse& dq, int newRCode) { dq.dh->rcode = newRCode; });
-  g_lua.registerMember<const ComboAddress (DNSResponse::*)>("remoteaddr", [](const DNSResponse& dq) -> const ComboAddress { return *dq.remote; }, [](DNSResponse& dq, const ComboAddress newRemote) { (void) newRemote; });
-  g_lua.registerMember<dnsheader* (DNSResponse::*)>("dh", [](const DNSResponse& dr) -> dnsheader* { return dr.dh; }, [](DNSResponse& dr, dnsheader * newdh) { dr.dh = newdh; });
-  g_lua.registerMember<uint16_t (DNSResponse::*)>("len", [](const DNSResponse& dq) -> uint16_t { return dq.len; }, [](DNSResponse& dq, uint16_t newlen) { dq.len = newlen; });
-  g_lua.registerMember<uint8_t (DNSResponse::*)>("opcode", [](const DNSResponse& dq) -> uint8_t { return dq.dh->opcode; }, [](DNSResponse& dq, uint8_t newOpcode) { (void) newOpcode; });
-  g_lua.registerMember<size_t (DNSResponse::*)>("size", [](const DNSResponse& dq) -> size_t { return dq.size; }, [](DNSResponse& dq, size_t newSize) { (void) newSize; });
-  g_lua.registerMember<bool (DNSResponse::*)>("tcp", [](const DNSResponse& dq) -> bool { return dq.tcp; }, [](DNSResponse& dq, bool newTcp) { (void) newTcp; });
-  g_lua.registerMember<bool (DNSResponse::*)>("skipCache", [](const DNSResponse& dq) -> bool { return dq.skipCache; }, [](DNSResponse& dq, bool newSkipCache) { dq.skipCache = newSkipCache; });
-  g_lua.registerFunction<void(DNSResponse::*)(std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc)>("editTTLs", [](const DNSResponse& dr, std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc) {
+  luaCtx.registerMember<const ComboAddress (DNSResponse::*)>("localaddr", [](const DNSResponse& dq) -> const ComboAddress { return *dq.local; }, [](DNSResponse& dq, const ComboAddress newLocal) { (void) newLocal; });
+  luaCtx.registerMember<const DNSName (DNSResponse::*)>("qname", [](const DNSResponse& dq) -> const DNSName { return *dq.qname; }, [](DNSResponse& dq, const DNSName newName) { (void) newName; });
+  luaCtx.registerMember<uint16_t (DNSResponse::*)>("qtype", [](const DNSResponse& dq) -> uint16_t { return dq.qtype; }, [](DNSResponse& dq, uint16_t newType) { (void) newType; });
+  luaCtx.registerMember<uint16_t (DNSResponse::*)>("qclass", [](const DNSResponse& dq) -> uint16_t { return dq.qclass; }, [](DNSResponse& dq, uint16_t newClass) { (void) newClass; });
+  luaCtx.registerMember<int (DNSResponse::*)>("rcode", [](const DNSResponse& dq) -> int { return dq.dh->rcode; }, [](DNSResponse& dq, int newRCode) { dq.dh->rcode = newRCode; });
+  luaCtx.registerMember<const ComboAddress (DNSResponse::*)>("remoteaddr", [](const DNSResponse& dq) -> const ComboAddress { return *dq.remote; }, [](DNSResponse& dq, const ComboAddress newRemote) { (void) newRemote; });
+  luaCtx.registerMember<dnsheader* (DNSResponse::*)>("dh", [](const DNSResponse& dr) -> dnsheader* { return dr.dh; }, [](DNSResponse& dr, dnsheader * newdh) { dr.dh = newdh; });
+  luaCtx.registerMember<uint16_t (DNSResponse::*)>("len", [](const DNSResponse& dq) -> uint16_t { return dq.len; }, [](DNSResponse& dq, uint16_t newlen) { dq.len = newlen; });
+  luaCtx.registerMember<uint8_t (DNSResponse::*)>("opcode", [](const DNSResponse& dq) -> uint8_t { return dq.dh->opcode; }, [](DNSResponse& dq, uint8_t newOpcode) { (void) newOpcode; });
+  luaCtx.registerMember<size_t (DNSResponse::*)>("size", [](const DNSResponse& dq) -> size_t { return dq.size; }, [](DNSResponse& dq, size_t newSize) { (void) newSize; });
+  luaCtx.registerMember<bool (DNSResponse::*)>("tcp", [](const DNSResponse& dq) -> bool { return dq.tcp; }, [](DNSResponse& dq, bool newTcp) { (void) newTcp; });
+  luaCtx.registerMember<bool (DNSResponse::*)>("skipCache", [](const DNSResponse& dq) -> bool { return dq.skipCache; }, [](DNSResponse& dq, bool newSkipCache) { dq.skipCache = newSkipCache; });
+  luaCtx.registerFunction<void(DNSResponse::*)(std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc)>("editTTLs", [](const DNSResponse& dr, std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc) {
         editDNSPacketTTL((char*) dr.dh, dr.len, editFunc);
       });
-  g_lua.registerFunction<std::string(DNSResponse::*)(void)>("getTrailingData", [](const DNSResponse& dq) {
+  luaCtx.registerFunction<std::string(DNSResponse::*)(void)>("getTrailingData", [](const DNSResponse& dq) {
       return dq.getTrailingData();
     });
-  g_lua.registerFunction<bool(DNSResponse::*)(std::string)>("setTrailingData", [](DNSResponse& dq, const std::string& tail) {
+  luaCtx.registerFunction<bool(DNSResponse::*)(std::string)>("setTrailingData", [](DNSResponse& dq, const std::string& tail) {
       return dq.setTrailingData(tail);
     });
 
-  g_lua.registerFunction<void(DNSResponse::*)(std::string, std::string)>("setTag", [](DNSResponse& dr, const std::string& strLabel, const std::string& strValue) {
+  luaCtx.registerFunction<void(DNSResponse::*)(std::string, std::string)>("setTag", [](DNSResponse& dr, const std::string& strLabel, const std::string& strValue) {
       if(dr.qTag == nullptr) {
         dr.qTag = std::make_shared<QTag>();
       }
       dr.qTag->insert({strLabel, strValue});
     });
 
-  g_lua.registerFunction<void(DNSResponse::*)(vector<pair<string, string>>)>("setTagArray", [](DNSResponse& dr, const vector<pair<string, string>>&tags) {
+  luaCtx.registerFunction<void(DNSResponse::*)(vector<pair<string, string>>)>("setTagArray", [](DNSResponse& dr, const vector<pair<string, string>>&tags) {
       if (!dr.qTag) {
         dr.qTag = std::make_shared<QTag>();
       }
@@ -169,7 +169,7 @@ void setupLuaBindingsDNSQuestion()
         dr.qTag->insert({tag.first, tag.second});
       }
     });
-  g_lua.registerFunction<string(DNSResponse::*)(std::string)>("getTag", [](const DNSResponse& dr, const std::string& strLabel) {
+  luaCtx.registerFunction<string(DNSResponse::*)(std::string)>("getTag", [](const DNSResponse& dr, const std::string& strLabel) {
       if (!dr.qTag) {
         return string();
       }
@@ -181,7 +181,7 @@ void setupLuaBindingsDNSQuestion()
       }
       return it->second;
     });
-  g_lua.registerFunction<QTag(DNSResponse::*)(void)>("getTagArray", [](const DNSResponse& dr) {
+  luaCtx.registerFunction<QTag(DNSResponse::*)(void)>("getTagArray", [](const DNSResponse& dr) {
       if (!dr.qTag) {
         QTag empty;
         return empty;
@@ -190,7 +190,7 @@ void setupLuaBindingsDNSQuestion()
       return *dr.qTag;
     });
 
-  g_lua.registerFunction<void(DNSResponse::*)(std::string)>("sendTrap", [](const DNSResponse& dr, boost::optional<std::string> reason) {
+  luaCtx.registerFunction<void(DNSResponse::*)(std::string)>("sendTrap", [](const DNSResponse& dr, boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
       if (g_snmpAgent && g_snmpTrapsEnabled) {
         g_snmpAgent->sendDNSTrap(dr, reason ? *reason : "");
@@ -199,42 +199,42 @@ void setupLuaBindingsDNSQuestion()
     });
 
 #ifdef HAVE_DNS_OVER_HTTPS
-    g_lua.registerFunction<std::string(DNSQuestion::*)(void)>("getHTTPPath", [](const DNSQuestion& dq) {
+    luaCtx.registerFunction<std::string(DNSQuestion::*)(void)>("getHTTPPath", [](const DNSQuestion& dq) {
       if (dq.du == nullptr) {
         return std::string();
       }
       return dq.du->getHTTPPath();
     });
 
-    g_lua.registerFunction<std::string(DNSQuestion::*)(void)>("getHTTPQueryString", [](const DNSQuestion& dq) {
+    luaCtx.registerFunction<std::string(DNSQuestion::*)(void)>("getHTTPQueryString", [](const DNSQuestion& dq) {
       if (dq.du == nullptr) {
         return std::string();
       }
       return dq.du->getHTTPQueryString();
     });
 
-    g_lua.registerFunction<std::string(DNSQuestion::*)(void)>("getHTTPHost", [](const DNSQuestion& dq) {
+    luaCtx.registerFunction<std::string(DNSQuestion::*)(void)>("getHTTPHost", [](const DNSQuestion& dq) {
       if (dq.du == nullptr) {
         return std::string();
       }
       return dq.du->getHTTPHost();
     });
 
-    g_lua.registerFunction<std::string(DNSQuestion::*)(void)>("getHTTPScheme", [](const DNSQuestion& dq) {
+    luaCtx.registerFunction<std::string(DNSQuestion::*)(void)>("getHTTPScheme", [](const DNSQuestion& dq) {
       if (dq.du == nullptr) {
         return std::string();
       }
       return dq.du->getHTTPScheme();
     });
 
-    g_lua.registerFunction<std::unordered_map<std::string, std::string>(DNSQuestion::*)(void)>("getHTTPHeaders", [](const DNSQuestion& dq) {
+    luaCtx.registerFunction<std::unordered_map<std::string, std::string>(DNSQuestion::*)(void)>("getHTTPHeaders", [](const DNSQuestion& dq) {
       if (dq.du == nullptr) {
         return std::unordered_map<std::string, std::string>();
       }
       return dq.du->getHTTPHeaders();
     });
 
-    g_lua.registerFunction<void(DNSQuestion::*)(uint16_t statusCode, const std::string& body, const boost::optional<std::string> contentType)>("setHTTPResponse", [](DNSQuestion& dq, uint16_t statusCode, const std::string& body, const boost::optional<std::string> contentType) {
+    luaCtx.registerFunction<void(DNSQuestion::*)(uint16_t statusCode, const std::string& body, const boost::optional<std::string> contentType)>("setHTTPResponse", [](DNSQuestion& dq, uint16_t statusCode, const std::string& body, const boost::optional<std::string> contentType) {
       if (dq.du == nullptr) {
         return;
       }
@@ -242,7 +242,7 @@ void setupLuaBindingsDNSQuestion()
     });
 #endif /* HAVE_DNS_OVER_HTTPS */
 
-  g_lua.registerFunction<bool(DNSQuestion::*)(bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum)>("setNegativeAndAdditionalSOA", [](DNSQuestion& dq, bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) {
+  luaCtx.registerFunction<bool(DNSQuestion::*)(bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum)>("setNegativeAndAdditionalSOA", [](DNSQuestion& dq, bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) {
       return setNegativeAndAdditionalSOA(dq, nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum);
     });
 }
index ba4cf9eac4b2c959d7a40706fbd5a2902d63f797..62c679336bec7f7a08064d4a90c7f6846c999a9d 100644 (file)
 
 #include "dolog.hh"
 
-void setupLuaBindings(bool client)
+void setupLuaBindings(LuaContext& luaCtx, bool client)
 {
-  g_lua.writeFunction("infolog", [](const string& arg) {
+  luaCtx.writeFunction("infolog", [](const string& arg) {
       infolog("%s", arg);
     });
-  g_lua.writeFunction("errlog", [](const string& arg) {
+  luaCtx.writeFunction("errlog", [](const string& arg) {
       errlog("%s", arg);
     });
-  g_lua.writeFunction("warnlog", [](const string& arg) {
+  luaCtx.writeFunction("warnlog", [](const string& arg) {
       warnlog("%s", arg);
     });
-  g_lua.writeFunction("show", [](const string& arg) {
+  luaCtx.writeFunction("show", [](const string& arg) {
       g_outputBuffer+=arg;
       g_outputBuffer+="\n";
     });
 
   /* Exceptions */
-  g_lua.registerFunction<string(std::exception_ptr::*)()>("__tostring", [](const std::exception_ptr& eptr) {
+  luaCtx.registerFunction<string(std::exception_ptr::*)()>("__tostring", [](const std::exception_ptr& eptr) {
       try {
         if (eptr) {
           std::rethrow_exception(eptr);
@@ -57,125 +57,126 @@ void setupLuaBindings(bool client)
       return string("No exception");
     });
   /* ServerPolicy */
-  g_lua.writeFunction("newServerPolicy", [](string name, ServerPolicy::policyfunc_t policy) { return std::make_shared<ServerPolicy>(name, policy, true);});
-  g_lua.registerMember("name", &ServerPolicy::name);
-  g_lua.registerMember("policy", &ServerPolicy::policy);
-  g_lua.registerMember("ffipolicy", &ServerPolicy::ffipolicy);
-  g_lua.registerMember("isLua", &ServerPolicy::isLua);
-  g_lua.registerMember("isFFI", &ServerPolicy::isFFI);
-  g_lua.registerFunction("toString", &ServerPolicy::toString);
-
-  g_lua.writeVariable("firstAvailable", ServerPolicy{"firstAvailable", firstAvailable, false});
-  g_lua.writeVariable("roundrobin", ServerPolicy{"roundrobin", roundrobin, false});
-  g_lua.writeVariable("wrandom", ServerPolicy{"wrandom", wrandom, false});
-  g_lua.writeVariable("whashed", ServerPolicy{"whashed", whashed, false});
-  g_lua.writeVariable("chashed", ServerPolicy{"chashed", chashed, false});
-  g_lua.writeVariable("leastOutstanding", ServerPolicy{"leastOutstanding", leastOutstanding, false});
+  luaCtx.writeFunction("newServerPolicy", [](string name, ServerPolicy::policyfunc_t policy) { return std::make_shared<ServerPolicy>(name, policy, true);});
+  luaCtx.registerMember("name", &ServerPolicy::d_name);
+  luaCtx.registerMember("policy", &ServerPolicy::d_policy);
+  luaCtx.registerMember("ffipolicy", &ServerPolicy::d_ffipolicy);
+  luaCtx.registerMember("isLua", &ServerPolicy::d_isLua);
+  luaCtx.registerMember("isFFI", &ServerPolicy::d_isFFI);
+  luaCtx.registerMember("isPerThread", &ServerPolicy::d_isPerThread);
+  luaCtx.registerFunction("toString", &ServerPolicy::toString);
+
+  luaCtx.writeVariable("firstAvailable", ServerPolicy{"firstAvailable", firstAvailable, false});
+  luaCtx.writeVariable("roundrobin", ServerPolicy{"roundrobin", roundrobin, false});
+  luaCtx.writeVariable("wrandom", ServerPolicy{"wrandom", wrandom, false});
+  luaCtx.writeVariable("whashed", ServerPolicy{"whashed", whashed, false});
+  luaCtx.writeVariable("chashed", ServerPolicy{"chashed", chashed, false});
+  luaCtx.writeVariable("leastOutstanding", ServerPolicy{"leastOutstanding", leastOutstanding, false});
 
   /* ServerPool */
-  g_lua.registerFunction<void(std::shared_ptr<ServerPool>::*)(std::shared_ptr<DNSDistPacketCache>)>("setCache", [](std::shared_ptr<ServerPool> pool, std::shared_ptr<DNSDistPacketCache> cache) {
+  luaCtx.registerFunction<void(std::shared_ptr<ServerPool>::*)(std::shared_ptr<DNSDistPacketCache>)>("setCache", [](std::shared_ptr<ServerPool> pool, std::shared_ptr<DNSDistPacketCache> cache) {
       if (pool) {
         pool->packetCache = cache;
       }
     });
-  g_lua.registerFunction("getCache", &ServerPool::getCache);
-  g_lua.registerFunction<void(std::shared_ptr<ServerPool>::*)()>("unsetCache", [](std::shared_ptr<ServerPool> pool) {
+  luaCtx.registerFunction("getCache", &ServerPool::getCache);
+  luaCtx.registerFunction<void(std::shared_ptr<ServerPool>::*)()>("unsetCache", [](std::shared_ptr<ServerPool> pool) {
       if (pool) {
         pool->packetCache = nullptr;
       }
     });
-  g_lua.registerFunction("getECS", &ServerPool::getECS);
-  g_lua.registerFunction("setECS", &ServerPool::setECS);
+  luaCtx.registerFunction("getECS", &ServerPool::getECS);
+  luaCtx.registerFunction("setECS", &ServerPool::setECS);
 
   /* DownstreamState */
-  g_lua.registerFunction<void(DownstreamState::*)(int)>("setQPS", [](DownstreamState& s, int lim) { s.qps = lim ? QPSLimiter(lim, lim) : QPSLimiter(); });
-  g_lua.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](std::shared_ptr<DownstreamState> s, string pool) {
+  luaCtx.registerFunction<void(DownstreamState::*)(int)>("setQPS", [](DownstreamState& s, int lim) { s.qps = lim ? QPSLimiter(lim, lim) : QPSLimiter(); });
+  luaCtx.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](std::shared_ptr<DownstreamState> s, string pool) {
       auto localPools = g_pools.getCopy();
       addServerToPool(localPools, pool, s);
       g_pools.setState(localPools);
       s->pools.insert(pool);
     });
-  g_lua.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](std::shared_ptr<DownstreamState> s, string pool) {
+  luaCtx.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](std::shared_ptr<DownstreamState> s, string pool) {
       auto localPools = g_pools.getCopy();
       removeServerFromPool(localPools, pool, s);
       g_pools.setState(localPools);
       s->pools.erase(pool);
     });
-  g_lua.registerFunction<uint64_t(DownstreamState::*)()>("getOutstanding", [](const DownstreamState& s) { return s.outstanding.load(); });
-  g_lua.registerFunction<double(DownstreamState::*)()>("getLatency", [](const DownstreamState& s) { return s.latencyUsec; });
-  g_lua.registerFunction("isUp", &DownstreamState::isUp);
-  g_lua.registerFunction("setDown", &DownstreamState::setDown);
-  g_lua.registerFunction("setUp", &DownstreamState::setUp);
-  g_lua.registerFunction<void(DownstreamState::*)(boost::optional<bool> newStatus)>("setAuto", [](DownstreamState& s, boost::optional<bool> newStatus) {
+  luaCtx.registerFunction<uint64_t(DownstreamState::*)()>("getOutstanding", [](const DownstreamState& s) { return s.outstanding.load(); });
+  luaCtx.registerFunction<double(DownstreamState::*)()>("getLatency", [](const DownstreamState& s) { return s.latencyUsec; });
+  luaCtx.registerFunction("isUp", &DownstreamState::isUp);
+  luaCtx.registerFunction("setDown", &DownstreamState::setDown);
+  luaCtx.registerFunction("setUp", &DownstreamState::setUp);
+  luaCtx.registerFunction<void(DownstreamState::*)(boost::optional<bool> newStatus)>("setAuto", [](DownstreamState& s, boost::optional<bool> newStatus) {
       if (newStatus) {
         s.upStatus = *newStatus;
       }
       s.setAuto();
     });
-  g_lua.registerFunction<std::string(DownstreamState::*)()>("getName", [](const DownstreamState& s) { return s.getName(); });
-  g_lua.registerFunction<std::string(DownstreamState::*)()>("getNameWithAddr", [](const DownstreamState& s) { return s.getNameWithAddr(); });
-  g_lua.registerMember("upStatus", &DownstreamState::upStatus);
-  g_lua.registerMember<int (DownstreamState::*)>("weight",
+  luaCtx.registerFunction<std::string(DownstreamState::*)()>("getName", [](const DownstreamState& s) { return s.getName(); });
+  luaCtx.registerFunction<std::string(DownstreamState::*)()>("getNameWithAddr", [](const DownstreamState& s) { return s.getNameWithAddr(); });
+  luaCtx.registerMember("upStatus", &DownstreamState::upStatus);
+  luaCtx.registerMember<int (DownstreamState::*)>("weight",
     [](const DownstreamState& s) -> int {return s.weight;},
     [](DownstreamState& s, int newWeight) {s.setWeight(newWeight);}
   );
-  g_lua.registerMember("order", &DownstreamState::order);
-  g_lua.registerMember<const std::string(DownstreamState::*)>("name", [](const DownstreamState& backend) -> const std::string { return backend.getName(); }, [](DownstreamState& backend, const std::string& newName) { backend.setName(newName); });
-  g_lua.registerFunction<std::string(DownstreamState::*)()>("getID", [](const DownstreamState& s) { return boost::uuids::to_string(s.id); });
+  luaCtx.registerMember("order", &DownstreamState::order);
+  luaCtx.registerMember<const std::string(DownstreamState::*)>("name", [](const DownstreamState& backend) -> const std::string { return backend.getName(); }, [](DownstreamState& backend, const std::string& newName) { backend.setName(newName); });
+  luaCtx.registerFunction<std::string(DownstreamState::*)()>("getID", [](const DownstreamState& s) { return boost::uuids::to_string(s.id); });
 
   /* dnsheader */
-  g_lua.registerFunction<void(dnsheader::*)(bool)>("setRD", [](dnsheader& dh, bool v) {
+  luaCtx.registerFunction<void(dnsheader::*)(bool)>("setRD", [](dnsheader& dh, bool v) {
       dh.rd=v;
     });
 
-  g_lua.registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) {
+  luaCtx.registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) {
       return (bool)dh.rd;
     });
 
-  g_lua.registerFunction<void(dnsheader::*)(bool)>("setRA", [](dnsheader& dh, bool v) {
+  luaCtx.registerFunction<void(dnsheader::*)(bool)>("setRA", [](dnsheader& dh, bool v) {
       dh.ra=v;
     });
 
-  g_lua.registerFunction<bool(dnsheader::*)()>("getRA", [](dnsheader& dh) {
+  luaCtx.registerFunction<bool(dnsheader::*)()>("getRA", [](dnsheader& dh) {
       return (bool)dh.ra;
     });
 
-  g_lua.registerFunction<void(dnsheader::*)(bool)>("setAD", [](dnsheader& dh, bool v) {
+  luaCtx.registerFunction<void(dnsheader::*)(bool)>("setAD", [](dnsheader& dh, bool v) {
       dh.ad=v;
     });
 
-  g_lua.registerFunction<bool(dnsheader::*)()>("getAD", [](dnsheader& dh) {
+  luaCtx.registerFunction<bool(dnsheader::*)()>("getAD", [](dnsheader& dh) {
       return (bool)dh.ad;
     });
 
-  g_lua.registerFunction<void(dnsheader::*)(bool)>("setAA", [](dnsheader& dh, bool v) {
+  luaCtx.registerFunction<void(dnsheader::*)(bool)>("setAA", [](dnsheader& dh, bool v) {
       dh.aa=v;
     });
 
-  g_lua.registerFunction<bool(dnsheader::*)()>("getAA", [](dnsheader& dh) {
+  luaCtx.registerFunction<bool(dnsheader::*)()>("getAA", [](dnsheader& dh) {
       return (bool)dh.aa;
     });
 
-  g_lua.registerFunction<void(dnsheader::*)(bool)>("setCD", [](dnsheader& dh, bool v) {
+  luaCtx.registerFunction<void(dnsheader::*)(bool)>("setCD", [](dnsheader& dh, bool v) {
       dh.cd=v;
     });
 
-  g_lua.registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) {
+  luaCtx.registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) {
       return (bool)dh.cd;
     });
 
-  g_lua.registerFunction<void(dnsheader::*)(bool)>("setTC", [](dnsheader& dh, bool v) {
+  luaCtx.registerFunction<void(dnsheader::*)(bool)>("setTC", [](dnsheader& dh, bool v) {
       dh.tc=v;
       if(v) dh.ra = dh.rd; // you'll always need this, otherwise TC=1 gets ignored
     });
 
-  g_lua.registerFunction<void(dnsheader::*)(bool)>("setQR", [](dnsheader& dh, bool v) {
+  luaCtx.registerFunction<void(dnsheader::*)(bool)>("setQR", [](dnsheader& dh, bool v) {
       dh.qr=v;
     });
 
   /* ComboAddress */
-  g_lua.writeFunction("newCA", [](const std::string& name) { return ComboAddress(name); });
-  g_lua.writeFunction("newCAFromRaw", [](const std::string& raw, boost::optional<uint16_t> port) {
+  luaCtx.writeFunction("newCA", [](const std::string& name) { return ComboAddress(name); });
+  luaCtx.writeFunction("newCAFromRaw", [](const std::string& raw, boost::optional<uint16_t> port) {
                                         if (raw.size() == 4) {
                                           struct sockaddr_in sin4;
                                           memset(&sin4, 0, sizeof(sin4));
@@ -198,42 +199,42 @@ void setupLuaBindings(bool client)
                                         }
                                         return ComboAddress();
                                       });
-  g_lua.registerFunction<string(ComboAddress::*)()>("tostring", [](const ComboAddress& ca) { return ca.toString(); });
-  g_lua.registerFunction<string(ComboAddress::*)()>("tostringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
-  g_lua.registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); });
-  g_lua.registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
-  g_lua.registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
-  g_lua.registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); });
-  g_lua.registerFunction<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; });
-  g_lua.registerFunction<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; });
-  g_lua.registerFunction<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); });
-  g_lua.registerFunction<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); });
-  g_lua.registerFunction<bool(nmts_t::*)(const ComboAddress&)>("match", [](nmts_t& s, const ComboAddress& ca) { return s.match(ca); });
+  luaCtx.registerFunction<string(ComboAddress::*)()>("tostring", [](const ComboAddress& ca) { return ca.toString(); });
+  luaCtx.registerFunction<string(ComboAddress::*)()>("tostringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
+  luaCtx.registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); });
+  luaCtx.registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
+  luaCtx.registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
+  luaCtx.registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); });
+  luaCtx.registerFunction<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; });
+  luaCtx.registerFunction<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; });
+  luaCtx.registerFunction<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); });
+  luaCtx.registerFunction<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); });
+  luaCtx.registerFunction<bool(nmts_t::*)(const ComboAddress&)>("match", [](nmts_t& s, const ComboAddress& ca) { return s.match(ca); });
 
   /* DNSName */
-  g_lua.registerFunction("isPartOf", &DNSName::isPartOf);
-  g_lua.registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); });
-  g_lua.registerFunction<unsigned int(DNSName::*)()>("countLabels", [](const DNSName& name) { return name.countLabels(); });
-  g_lua.registerFunction<size_t(DNSName::*)()>("hash", [](const DNSName& name) { return name.hash(); });
-  g_lua.registerFunction<size_t(DNSName::*)()>("wirelength", [](const DNSName& name) { return name.wirelength(); });
-  g_lua.registerFunction<string(DNSName::*)()>("tostring", [](const DNSName&dn ) { return dn.toString(); });
-  g_lua.registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
-  g_lua.writeFunction("newDNSName", [](const std::string& name) { return DNSName(name); });
-  g_lua.writeFunction("newDNSNameFromRaw", [](const std::string& name) { return DNSName(name.c_str(), name.size(), 0, false); });
-  g_lua.writeFunction("newSuffixMatchNode", []() { return SuffixMatchNode(); });
-  g_lua.writeFunction("newDNSNameSet", []() { return DNSNameSet(); });
+  luaCtx.registerFunction("isPartOf", &DNSName::isPartOf);
+  luaCtx.registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); });
+  luaCtx.registerFunction<unsigned int(DNSName::*)()>("countLabels", [](const DNSName& name) { return name.countLabels(); });
+  luaCtx.registerFunction<size_t(DNSName::*)()>("hash", [](const DNSName& name) { return name.hash(); });
+  luaCtx.registerFunction<size_t(DNSName::*)()>("wirelength", [](const DNSName& name) { return name.wirelength(); });
+  luaCtx.registerFunction<string(DNSName::*)()>("tostring", [](const DNSName&dn ) { return dn.toString(); });
+  luaCtx.registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
+  luaCtx.writeFunction("newDNSName", [](const std::string& name) { return DNSName(name); });
+  luaCtx.writeFunction("newDNSNameFromRaw", [](const std::string& name) { return DNSName(name.c_str(), name.size(), 0, false); });
+  luaCtx.writeFunction("newSuffixMatchNode", []() { return SuffixMatchNode(); });
+  luaCtx.writeFunction("newDNSNameSet", []() { return DNSNameSet(); });
 
   /* DNSNameSet */
-  g_lua.registerFunction<string(DNSNameSet::*)()>("toString", [](const DNSNameSet&dns ) { return dns.toString(); });
-  g_lua.registerFunction<void(DNSNameSet::*)(DNSName&)>("add", [](DNSNameSet& dns, DNSName& dn) { dns.insert(dn); });
-  g_lua.registerFunction<bool(DNSNameSet::*)(DNSName&)>("check", [](DNSNameSet& dns, DNSName& dn) { return dns.find(dn) != dns.end(); });
-  g_lua.registerFunction("delete",(size_t (DNSNameSet::*)(const DNSName&)) &DNSNameSet::erase);
-  g_lua.registerFunction("size",(size_t (DNSNameSet::*)() const) &DNSNameSet::size);
-  g_lua.registerFunction("clear",(void (DNSNameSet::*)()) &DNSNameSet::clear);
-  g_lua.registerFunction("empty",(bool (DNSNameSet::*)()) &DNSNameSet::empty);
+  luaCtx.registerFunction<string(DNSNameSet::*)()>("toString", [](const DNSNameSet&dns ) { return dns.toString(); });
+  luaCtx.registerFunction<void(DNSNameSet::*)(DNSName&)>("add", [](DNSNameSet& dns, DNSName& dn) { dns.insert(dn); });
+  luaCtx.registerFunction<bool(DNSNameSet::*)(DNSName&)>("check", [](DNSNameSet& dns, DNSName& dn) { return dns.find(dn) != dns.end(); });
+  luaCtx.registerFunction("delete",(size_t (DNSNameSet::*)(const DNSName&)) &DNSNameSet::erase);
+  luaCtx.registerFunction("size",(size_t (DNSNameSet::*)() const) &DNSNameSet::size);
+  luaCtx.registerFunction("clear",(void (DNSNameSet::*)()) &DNSNameSet::clear);
+  luaCtx.registerFunction("empty",(bool (DNSNameSet::*)()) &DNSNameSet::empty);
 
   /* SuffixMatchNode */
-  g_lua.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name)>("add", [](SuffixMatchNode &smn, const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name) {
+  luaCtx.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name)>("add", [](SuffixMatchNode &smn, const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name) {
       if (name.type() == typeid(DNSName)) {
           auto n = boost::get<DNSName>(name);
           smn.add(n);
@@ -259,7 +260,7 @@ void setupLuaBindings(bool client)
           return;
       }
   });
-  g_lua.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name)>("remove", [](SuffixMatchNode &smn, const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name) {
+  luaCtx.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name)>("remove", [](SuffixMatchNode &smn, const boost::variant<DNSName, string, vector<pair<int, DNSName>>, vector<pair<int, string>>> &name) {
       if (name.type() == typeid(DNSName)) {
           auto n = boost::get<DNSName>(name);
           smn.remove(n);
@@ -288,10 +289,10 @@ void setupLuaBindings(bool client)
       }
   });
 
-  g_lua.registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
+  luaCtx.registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
 
   /* Netmask */
-  g_lua.writeFunction("newNetmask", [](boost::variant<std::string,ComboAddress> s, boost::optional<uint8_t> bits) {
+  luaCtx.writeFunction("newNetmask", [](boost::variant<std::string,ComboAddress> s, boost::optional<uint8_t> bits) {
     if (s.type() == typeid(ComboAddress)) {
       auto ca = boost::get<ComboAddress>(s);
       if (bits) {
@@ -305,92 +306,92 @@ void setupLuaBindings(bool client)
     }
     throw std::runtime_error("Invalid parameter passed to 'newNetmask()'");
   });
-  g_lua.registerFunction("empty", &Netmask::empty);
-  g_lua.registerFunction("getBits", &Netmask::getBits);
-  g_lua.registerFunction<ComboAddress(Netmask::*)()>("getNetwork", [](const Netmask& nm) { return nm.getNetwork(); } ); // const reference makes this necessary
-  g_lua.registerFunction<ComboAddress(Netmask::*)()>("getMaskedNetwork", [](const Netmask& nm) { return nm.getMaskedNetwork(); } );
-  g_lua.registerFunction("isIpv4", &Netmask::isIPv4);
-  g_lua.registerFunction("isIPv4", &Netmask::isIPv4);
-  g_lua.registerFunction("isIpv6", &Netmask::isIPv6);
-  g_lua.registerFunction("isIPv6", &Netmask::isIPv6);
-  g_lua.registerFunction("match", (bool (Netmask::*)(const string&) const)&Netmask::match);
-  g_lua.registerFunction("toString", &Netmask::toString);
-  g_lua.registerEqFunction(&Netmask::operator==);
-  g_lua.registerToStringFunction(&Netmask::toString);
+  luaCtx.registerFunction("empty", &Netmask::empty);
+  luaCtx.registerFunction("getBits", &Netmask::getBits);
+  luaCtx.registerFunction<ComboAddress(Netmask::*)()>("getNetwork", [](const Netmask& nm) { return nm.getNetwork(); } ); // const reference makes this necessary
+  luaCtx.registerFunction<ComboAddress(Netmask::*)()>("getMaskedNetwork", [](const Netmask& nm) { return nm.getMaskedNetwork(); } );
+  luaCtx.registerFunction("isIpv4", &Netmask::isIPv4);
+  luaCtx.registerFunction("isIPv4", &Netmask::isIPv4);
+  luaCtx.registerFunction("isIpv6", &Netmask::isIPv6);
+  luaCtx.registerFunction("isIPv6", &Netmask::isIPv6);
+  luaCtx.registerFunction("match", (bool (Netmask::*)(const string&) const)&Netmask::match);
+  luaCtx.registerFunction("toString", &Netmask::toString);
+  luaCtx.registerEqFunction(&Netmask::operator==);
+  luaCtx.registerToStringFunction(&Netmask::toString);
 
   /* NetmaskGroup */
-  g_lua.writeFunction("newNMG", []() { return NetmaskGroup(); });
-  g_lua.registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask)
+  luaCtx.writeFunction("newNMG", []() { return NetmaskGroup(); });
+  luaCtx.registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask)
                          {
                            nmg.addMask(mask);
                          });
-  g_lua.registerFunction<void(NetmaskGroup::*)(const std::map<ComboAddress,int>& map)>("addMasks", [](NetmaskGroup&nmg, const std::map<ComboAddress,int>& map)
+  luaCtx.registerFunction<void(NetmaskGroup::*)(const std::map<ComboAddress,int>& map)>("addMasks", [](NetmaskGroup&nmg, const std::map<ComboAddress,int>& map)
                          {
                            for (const auto& entry : map) {
                              nmg.addMask(Netmask(entry.first));
                            }
                          });
 
-  g_lua.registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
-  g_lua.registerFunction("size", &NetmaskGroup::size);
-  g_lua.registerFunction("clear", &NetmaskGroup::clear);
-  g_lua.registerFunction<string(NetmaskGroup::*)()>("toString", [](const NetmaskGroup& nmg ) { return "NetmaskGroup " + nmg.toString(); });
+  luaCtx.registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
+  luaCtx.registerFunction("size", &NetmaskGroup::size);
+  luaCtx.registerFunction("clear", &NetmaskGroup::clear);
+  luaCtx.registerFunction<string(NetmaskGroup::*)()>("toString", [](const NetmaskGroup& nmg ) { return "NetmaskGroup " + nmg.toString(); });
 
   /* QPSLimiter */
-  g_lua.writeFunction("newQPSLimiter", [](int rate, int burst) { return QPSLimiter(rate, burst); });
-  g_lua.registerFunction("check", &QPSLimiter::check);
+  luaCtx.writeFunction("newQPSLimiter", [](int rate, int burst) { return QPSLimiter(rate, burst); });
+  luaCtx.registerFunction("check", &QPSLimiter::check);
 
   /* ClientState */
-  g_lua.registerFunction<std::string(ClientState::*)()>("toString", [](const ClientState& fe) {
+  luaCtx.registerFunction<std::string(ClientState::*)()>("toString", [](const ClientState& fe) {
       setLuaNoSideEffect();
       return fe.local.toStringWithPort();
     });
-  g_lua.registerMember("muted", &ClientState::muted);
+  luaCtx.registerMember("muted", &ClientState::muted);
 #ifdef HAVE_EBPF
-  g_lua.registerFunction<void(ClientState::*)(std::shared_ptr<BPFFilter>)>("attachFilter", [](ClientState& frontend, std::shared_ptr<BPFFilter> bpf) {
+  luaCtx.registerFunction<void(ClientState::*)(std::shared_ptr<BPFFilter>)>("attachFilter", [](ClientState& frontend, std::shared_ptr<BPFFilter> bpf) {
       if (bpf) {
         frontend.attachFilter(bpf);
       }
     });
-  g_lua.registerFunction<void(ClientState::*)()>("detachFilter", [](ClientState& frontend) {
+  luaCtx.registerFunction<void(ClientState::*)()>("detachFilter", [](ClientState& frontend) {
       frontend.detachFilter();
     });
 #endif /* HAVE_EBPF */
 
   /* BPF Filter */
 #ifdef HAVE_EBPF
-  g_lua.writeFunction("newBPFFilter", [client](uint32_t maxV4, uint32_t maxV6, uint32_t maxQNames) {
+  luaCtx.writeFunction("newBPFFilter", [client](uint32_t maxV4, uint32_t maxV6, uint32_t maxQNames) {
       if (client) {
         return std::shared_ptr<BPFFilter>(nullptr);
       }
       return std::make_shared<BPFFilter>(maxV4, maxV6, maxQNames);
     });
 
-  g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca)>("block", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca) {
+  luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca)>("block", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca) {
       if (bpf) {
         return bpf->block(ca);
       }
     });
 
-  g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype)>("blockQName", [](std::shared_ptr<BPFFilter> bpf, const DNSName& qname, boost::optional<uint16_t> qtype) {
+  luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype)>("blockQName", [](std::shared_ptr<BPFFilter> bpf, const DNSName& qname, boost::optional<uint16_t> qtype) {
       if (bpf) {
         return bpf->block(qname, qtype ? *qtype : 255);
       }
     });
 
-  g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca)>("unblock", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca) {
+  luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const ComboAddress& ca)>("unblock", [](std::shared_ptr<BPFFilter> bpf, const ComboAddress& ca) {
       if (bpf) {
         return bpf->unblock(ca);
       }
     });
 
-  g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype)>("unblockQName", [](std::shared_ptr<BPFFilter> bpf, const DNSName& qname, boost::optional<uint16_t> qtype) {
+  luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype)>("unblockQName", [](std::shared_ptr<BPFFilter> bpf, const DNSName& qname, boost::optional<uint16_t> qtype) {
       if (bpf) {
         return bpf->unblock(qname, qtype ? *qtype : 255);
       }
     });
 
-  g_lua.registerFunction<std::string(std::shared_ptr<BPFFilter>::*)()>("getStats", [](const std::shared_ptr<BPFFilter> bpf) {
+  luaCtx.registerFunction<std::string(std::shared_ptr<BPFFilter>::*)()>("getStats", [](const std::shared_ptr<BPFFilter> bpf) {
       setLuaNoSideEffect();
       std::string res;
       if (bpf) {
@@ -411,7 +412,7 @@ void setupLuaBindings(bool client)
       return res;
     });
 
-  g_lua.registerFunction<void(std::shared_ptr<BPFFilter>::*)()>("attachToAllBinds", [](std::shared_ptr<BPFFilter> bpf) {
+  luaCtx.registerFunction<void(std::shared_ptr<BPFFilter>::*)()>("attachToAllBinds", [](std::shared_ptr<BPFFilter> bpf) {
       std::string res;
       if (bpf) {
         for (const auto& frontend : g_frontends) {
@@ -420,14 +421,14 @@ void setupLuaBindings(bool client)
       }
     });
 
-    g_lua.writeFunction("newDynBPFFilter", [client](std::shared_ptr<BPFFilter> bpf) {
+    luaCtx.writeFunction("newDynBPFFilter", [client](std::shared_ptr<BPFFilter> bpf) {
         if (client) {
           return std::shared_ptr<DynBPFFilter>(nullptr);
         }
         return std::make_shared<DynBPFFilter>(bpf);
       });
 
-    g_lua.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)(const ComboAddress& addr, boost::optional<int> seconds)>("block", [](std::shared_ptr<DynBPFFilter> dbpf, const ComboAddress& addr, boost::optional<int> seconds) {
+    luaCtx.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)(const ComboAddress& addr, boost::optional<int> seconds)>("block", [](std::shared_ptr<DynBPFFilter> dbpf, const ComboAddress& addr, boost::optional<int> seconds) {
         if (dbpf) {
           struct timespec until;
           clock_gettime(CLOCK_MONOTONIC, &until);
@@ -436,7 +437,7 @@ void setupLuaBindings(bool client)
         }
     });
 
-    g_lua.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)()>("purgeExpired", [](std::shared_ptr<DynBPFFilter> dbpf) {
+    luaCtx.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)()>("purgeExpired", [](std::shared_ptr<DynBPFFilter> dbpf) {
         if (dbpf) {
           struct timespec now;
           clock_gettime(CLOCK_MONOTONIC, &now);
@@ -444,7 +445,7 @@ void setupLuaBindings(bool client)
         }
     });
 
-    g_lua.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("excludeRange", [](std::shared_ptr<DynBPFFilter> dbpf, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
+    luaCtx.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("excludeRange", [](std::shared_ptr<DynBPFFilter> dbpf, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
       if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) {
         for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) {
           dbpf->excludeRange(Netmask(range.second));
@@ -455,7 +456,7 @@ void setupLuaBindings(bool client)
       }
     });
 
-    g_lua.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("includeRange", [](std::shared_ptr<DynBPFFilter> dbpf, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
+    luaCtx.registerFunction<void(std::shared_ptr<DynBPFFilter>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("includeRange", [](std::shared_ptr<DynBPFFilter> dbpf, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
       if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) {
         for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) {
           dbpf->includeRange(Netmask(range.second));
@@ -468,10 +469,10 @@ void setupLuaBindings(bool client)
 #endif /* HAVE_EBPF */
 
   /* EDNSOptionView */
-  g_lua.registerFunction<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView& option) {
+  luaCtx.registerFunction<size_t(EDNSOptionView::*)()>("count", [](const EDNSOptionView& option) {
       return option.values.size();
     });
-  g_lua.registerFunction<std::vector<string>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView& option) {
+  luaCtx.registerFunction<std::vector<string>(EDNSOptionView::*)()>("getValues", [] (const EDNSOptionView& option) {
     std::vector<string> values;
     for (const auto& value : option.values) {
       values.push_back(std::string(value.content, value.size));
@@ -479,7 +480,7 @@ void setupLuaBindings(bool client)
     return values;
   });
 
-  g_lua.writeFunction("newDOHResponseMapEntry", [](const std::string& regex, uint16_t status, const std::string& content, boost::optional<std::map<std::string, std::string>> customHeaders) {
+  luaCtx.writeFunction("newDOHResponseMapEntry", [](const std::string& regex, uint16_t status, const std::string& content, boost::optional<std::map<std::string, std::string>> customHeaders) {
     boost::optional<std::vector<std::pair<std::string, std::string>>> headers{boost::none};
     if (customHeaders) {
       headers = std::vector<std::pair<std::string, std::string>>();
index 180e6555a757a4574ad73675e9759f7e294a71c1..14028e0d47b890f3dab8b55cb93990461b1f5c6c 100644 (file)
@@ -223,9 +223,9 @@ static counts_t exceedRespByterate(unsigned int rate, int seconds)
                   });
 }
 
-void setupLuaInspection()
+void setupLuaInspection(LuaContext& luaCtx)
 {
-  g_lua.writeFunction("topClients", [](boost::optional<unsigned int> top_) {
+  luaCtx.writeFunction("topClients", [](boost::optional<unsigned int> top_) {
       setLuaNoSideEffect();
       auto top = top_.get_value_or(10);
       map<ComboAddress, unsigned int,ComboAddress::addressOnlyLessThan > counts;
@@ -259,7 +259,7 @@ void setupLuaInspection()
       g_outputBuffer += (fmt % (count) % "Rest" % rest % (total > 0 ? 100.0*rest/total : 100.0)).str();
     });
 
-  g_lua.writeFunction("getTopQueries", [](unsigned int top, boost::optional<int> labels) {
+  luaCtx.writeFunction("getTopQueries", [](unsigned int top, boost::optional<int> labels) {
       setLuaNoSideEffect();
       map<DNSName, unsigned int> counts;
       unsigned int total=0;
@@ -307,9 +307,9 @@ void setupLuaInspection()
 
     });
 
-  g_lua.executeCode(R"(function topQueries(top, labels) top = top or 10; for k,v in ipairs(getTopQueries(top,labels)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2], v[3])) end end)");
+  luaCtx.executeCode(R"(function topQueries(top, labels) top = top or 10; for k,v in ipairs(getTopQueries(top,labels)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2], v[3])) end end)");
 
-  g_lua.writeFunction("getResponseRing", []() {
+  luaCtx.writeFunction("getResponseRing", []() {
       setLuaNoSideEffect();
       size_t totalEntries = 0;
       std::vector<boost::circular_buffer<Rings::Response>> rings;
@@ -336,28 +336,28 @@ void setupLuaInspection()
       return ret;
     });
 
-  g_lua.writeFunction("getTopResponses", [](unsigned int top, unsigned int kind, boost::optional<int> labels) {
+  luaCtx.writeFunction("getTopResponses", [](unsigned int top, unsigned int kind, boost::optional<int> labels) {
       return getGenResponses(top, labels, [kind](const Rings::Response& r) { return r.dh.rcode == kind; });
     });
 
-  g_lua.executeCode(R"(function topResponses(top, kind, labels) top = top or 10; kind = kind or 0; for k,v in ipairs(getTopResponses(top, kind, labels)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
+  luaCtx.executeCode(R"(function topResponses(top, kind, labels) top = top or 10; kind = kind or 0; for k,v in ipairs(getTopResponses(top, kind, labels)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
 
 
-  g_lua.writeFunction("getSlowResponses", [](unsigned int top, unsigned int msec, boost::optional<int> labels) {
+  luaCtx.writeFunction("getSlowResponses", [](unsigned int top, unsigned int msec, boost::optional<int> labels) {
       return getGenResponses(top, labels, [msec](const Rings::Response& r) { return r.usec > msec*1000; });
     });
 
 
-  g_lua.executeCode(R"(function topSlow(top, msec, labels) top = top or 10; msec = msec or 500; for k,v in ipairs(getSlowResponses(top, msec, labels)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
+  luaCtx.executeCode(R"(function topSlow(top, msec, labels) top = top or 10; msec = msec or 500; for k,v in ipairs(getSlowResponses(top, msec, labels)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
 
-  g_lua.writeFunction("getTopBandwidth", [](unsigned int top) {
+  luaCtx.writeFunction("getTopBandwidth", [](unsigned int top) {
       setLuaNoSideEffect();
       return g_rings.getTopBandwidth(top);
     });
 
-  g_lua.executeCode(R"(function topBandwidth(top) top = top or 10; for k,v in ipairs(getTopBandwidth(top)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
+  luaCtx.executeCode(R"(function topBandwidth(top) top = top or 10; for k,v in ipairs(getTopBandwidth(top)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
 
-  g_lua.writeFunction("delta", []() {
+  luaCtx.writeFunction("delta", []() {
       setLuaNoSideEffect();
       // we hold the lua lock already!
       for(const auto& d : g_confDelta) {
@@ -370,7 +370,7 @@ void setupLuaInspection()
       }
     });
 
-  g_lua.writeFunction("grepq", [](boost::variant<string, vector<pair<int,string> > > inp, boost::optional<unsigned int> limit) {
+  luaCtx.writeFunction("grepq", [](boost::variant<string, vector<pair<int,string> > > inp, boost::optional<unsigned int> limit) {
       setLuaNoSideEffect();
       boost::optional<Netmask>  nm;
       boost::optional<DNSName> dn;
@@ -517,7 +517,7 @@ void setupLuaInspection()
       }
     });
 
-  g_lua.writeFunction("showResponseLatency", []() {
+  luaCtx.writeFunction("showResponseLatency", []() {
       setLuaNoSideEffect();
       map<double, unsigned int> histo;
       double bin=100;
@@ -575,7 +575,7 @@ void setupLuaInspection()
       }
     });
 
-  g_lua.writeFunction("showTCPStats", [] {
+  luaCtx.writeFunction("showTCPStats", [] {
       setLuaNoSideEffect();
       ostringstream ret;
       boost::format fmt("%-12d %-12d %-12d %-12d");
@@ -611,7 +611,7 @@ void setupLuaInspection()
       g_outputBuffer=ret.str();
     });
 
-  g_lua.writeFunction("showTLSErrorCounters", [] {
+  luaCtx.writeFunction("showTLSErrorCounters", [] {
       setLuaNoSideEffect();
       ostringstream ret;
       boost::format fmt("%-3d %-20.20s %-23d %-23d %-23d %-23d %-23d %-23d %-23d %-23d");
@@ -642,7 +642,7 @@ void setupLuaInspection()
       g_outputBuffer=ret.str();
     });
 
-  g_lua.writeFunction("dumpStats", [] {
+  luaCtx.writeFunction("dumpStats", [] {
       setLuaNoSideEffect();
       vector<string> leftcolumn, rightcolumn;
 
@@ -686,21 +686,21 @@ void setupLuaInspection()
       }
     });
 
-  g_lua.writeFunction("exceedServFails", [](unsigned int rate, int seconds) {
+  luaCtx.writeFunction("exceedServFails", [](unsigned int rate, int seconds) {
       setLuaNoSideEffect();
       return exceedRCode(rate, seconds, RCode::ServFail);
     });
-  g_lua.writeFunction("exceedNXDOMAINs", [](unsigned int rate, int seconds) {
+  luaCtx.writeFunction("exceedNXDOMAINs", [](unsigned int rate, int seconds) {
       setLuaNoSideEffect();
       return exceedRCode(rate, seconds, RCode::NXDomain);
     });
 
-  g_lua.writeFunction("exceedRespByterate", [](unsigned int rate, int seconds) {
+  luaCtx.writeFunction("exceedRespByterate", [](unsigned int rate, int seconds) {
       setLuaNoSideEffect();
       return exceedRespByterate(rate, seconds);
     });
 
-  g_lua.writeFunction("exceedQTypeRate", [](uint16_t type, unsigned int rate, int seconds) {
+  luaCtx.writeFunction("exceedQTypeRate", [](uint16_t type, unsigned int rate, int seconds) {
       setLuaNoSideEffect();
       return exceedQueryGen(rate, seconds, [type](counts_t& counts, const Rings::Query& q) {
          if(q.qtype==type)
@@ -708,71 +708,71 @@ void setupLuaInspection()
        });
     });
 
-  g_lua.writeFunction("exceedQRate", [](unsigned int rate, int seconds) {
+  luaCtx.writeFunction("exceedQRate", [](unsigned int rate, int seconds) {
       setLuaNoSideEffect();
       return exceedQueryGen(rate, seconds, [](counts_t& counts, const Rings::Query& q) {
           counts[q.requestor]++;
        });
     });
 
-  g_lua.writeFunction("getRespRing", getRespRing);
+  luaCtx.writeFunction("getRespRing", getRespRing);
 
   /* StatNode */
-  g_lua.registerFunction<StatNode, unsigned int()>("numChildren",
+  luaCtx.registerFunction<StatNode, unsigned int()>("numChildren",
                                                    [](StatNode& sn) -> unsigned int {
                                                      return sn.children.size();
                                                    } );
-  g_lua.registerMember("fullname", &StatNode::fullname);
-  g_lua.registerMember("labelsCount", &StatNode::labelsCount);
-  g_lua.registerMember("servfails", &StatNode::Stat::servfails);
-  g_lua.registerMember("nxdomains", &StatNode::Stat::nxdomains);
-  g_lua.registerMember("queries", &StatNode::Stat::queries);
-  g_lua.registerMember("noerrors", &StatNode::Stat::noerrors);
-  g_lua.registerMember("drops", &StatNode::Stat::drops);
-  g_lua.registerMember("bytes", &StatNode::Stat::bytes);
-
-  g_lua.writeFunction("statNodeRespRing", [](statvisitor_t visitor, boost::optional<unsigned int> seconds) {
+  luaCtx.registerMember("fullname", &StatNode::fullname);
+  luaCtx.registerMember("labelsCount", &StatNode::labelsCount);
+  luaCtx.registerMember("servfails", &StatNode::Stat::servfails);
+  luaCtx.registerMember("nxdomains", &StatNode::Stat::nxdomains);
+  luaCtx.registerMember("queries", &StatNode::Stat::queries);
+  luaCtx.registerMember("noerrors", &StatNode::Stat::noerrors);
+  luaCtx.registerMember("drops", &StatNode::Stat::drops);
+  luaCtx.registerMember("bytes", &StatNode::Stat::bytes);
+
+  luaCtx.writeFunction("statNodeRespRing", [](statvisitor_t visitor, boost::optional<unsigned int> seconds) {
       statNodeRespRing(visitor, seconds ? *seconds : 0);
     });
 
   /* DynBlockRulesGroup */
-  g_lua.writeFunction("dynBlockRulesGroup", []() { return std::make_shared<DynBlockRulesGroup>(); });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setQueryRate", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
+  luaCtx.writeFunction("dynBlockRulesGroup", []() { return std::make_shared<DynBlockRulesGroup>(); });
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setQueryRate", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
       if (group) {
         group->setQueryRate(rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setResponseByteRate", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setResponseByteRate", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
       if (group) {
         group->setResponseByteRate(rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, DynBlockRulesGroup::smtVisitor_t)>("setSuffixMatchRule", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, DynBlockRulesGroup::smtVisitor_t visitor) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, DynBlockRulesGroup::smtVisitor_t)>("setSuffixMatchRule", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, DynBlockRulesGroup::smtVisitor_t visitor) {
       if (group) {
         group->setSuffixMatchRule(seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, visitor);
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, dnsdist_ffi_stat_node_visitor_t)>("setSuffixMatchRuleFFI", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, dnsdist_ffi_stat_node_visitor_t visitor) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, dnsdist_ffi_stat_node_visitor_t)>("setSuffixMatchRuleFFI", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, dnsdist_ffi_stat_node_visitor_t visitor) {
       if (group) {
         group->setSuffixMatchRuleFFI(seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, visitor);
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setRCodeRate", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t rcode, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setRCodeRate", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t rcode, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
       if (group) {
         group->setRCodeRate(rcode, rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, double, unsigned int, const std::string&, unsigned int, size_t, boost::optional<DNSAction::Action>, boost::optional<double>)>("setRCodeRatio", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t rcode, double ratio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, size_t minimumNumberOfResponses, boost::optional<DNSAction::Action> action, boost::optional<double> warningRatio) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, double, unsigned int, const std::string&, unsigned int, size_t, boost::optional<DNSAction::Action>, boost::optional<double>)>("setRCodeRatio", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t rcode, double ratio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, size_t minimumNumberOfResponses, boost::optional<DNSAction::Action> action, boost::optional<double> warningRatio) {
       if (group) {
         group->setRCodeRatio(rcode, ratio, warningRatio ? *warningRatio : 0.0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, minimumNumberOfResponses);
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(uint16_t, unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setQTypeRate", [](std::shared_ptr<DynBlockRulesGroup>& group, uint16_t qtype, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(uint16_t, unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setQTypeRate", [](std::shared_ptr<DynBlockRulesGroup>& group, uint16_t qtype, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
       if (group) {
         group->setQTypeRate(qtype, rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("excludeRange", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("excludeRange", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
       if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) {
         for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) {
           group->excludeRange(Netmask(range.second));
@@ -782,7 +782,7 @@ void setupLuaInspection()
         group->excludeRange(Netmask(*boost::get<std::string>(&ranges)));
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("includeRange", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("includeRange", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>> ranges) {
       if (ranges.type() == typeid(std::vector<std::pair<int, std::string>>)) {
         for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&ranges)) {
           group->includeRange(Netmask(range.second));
@@ -792,7 +792,7 @@ void setupLuaInspection()
         group->includeRange(Netmask(*boost::get<std::string>(&ranges)));
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("excludeDomains", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>> domains) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(boost::variant<std::string, std::vector<std::pair<int, std::string>>>)>("excludeDomains", [](std::shared_ptr<DynBlockRulesGroup>& group, boost::variant<std::string, std::vector<std::pair<int, std::string>>> domains) {
       if (domains.type() == typeid(std::vector<std::pair<int, std::string>>)) {
         for (const auto& range : *boost::get<std::vector<std::pair<int, std::string>>>(&domains)) {
           group->excludeDomain(DNSName(range.second));
@@ -802,9 +802,9 @@ void setupLuaInspection()
         group->excludeDomain(DNSName(*boost::get<std::string>(&domains)));
       }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)()>("apply", [](std::shared_ptr<DynBlockRulesGroup>& group) {
+  luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)()>("apply", [](std::shared_ptr<DynBlockRulesGroup>& group) {
     group->apply();
   });
-  g_lua.registerFunction("setQuiet", &DynBlockRulesGroup::setQuiet);
-  g_lua.registerFunction("toString", &DynBlockRulesGroup::toString);
+  luaCtx.registerFunction("setQuiet", &DynBlockRulesGroup::setQuiet);
+  luaCtx.registerFunction("toString", &DynBlockRulesGroup::toString);
 }
index c33af0d7f166f6307de838b5f9b72f223f13d530..4307b0d1315fb56b566b46c21d2ee4a17ba9d453 100644 (file)
@@ -178,80 +178,80 @@ static void mvRule(GlobalStateHolder<vector<T> > *someRespRulActions, unsigned i
   someRespRulActions->setState(std::move(rules));
 }
 
-void setupLuaRules()
+void setupLuaRules(LuaContext& luaCtx)
 {
-  g_lua.writeFunction("makeRule", makeRule);
+  luaCtx.writeFunction("makeRule", makeRule);
 
-  g_lua.registerFunction<string(std::shared_ptr<DNSRule>::*)()>("toString", [](const std::shared_ptr<DNSRule>& rule) { return rule->toString(); });
+  luaCtx.registerFunction<string(std::shared_ptr<DNSRule>::*)()>("toString", [](const std::shared_ptr<DNSRule>& rule) { return rule->toString(); });
 
-  g_lua.writeFunction("showResponseRules", [](boost::optional<ruleparams_t> vars) {
+  luaCtx.writeFunction("showResponseRules", [](boost::optional<ruleparams_t> vars) {
       showRules(&g_resprulactions, vars);
     });
 
-  g_lua.writeFunction("rmResponseRule", [](boost::variant<unsigned int, std::string> id) {
+  luaCtx.writeFunction("rmResponseRule", [](boost::variant<unsigned int, std::string> id) {
       rmRule(&g_resprulactions, id);
     });
 
-  g_lua.writeFunction("topResponseRule", []() {
+  luaCtx.writeFunction("topResponseRule", []() {
       topRule(&g_resprulactions);
     });
 
-  g_lua.writeFunction("mvResponseRule", [](unsigned int from, unsigned int to) {
+  luaCtx.writeFunction("mvResponseRule", [](unsigned int from, unsigned int to) {
       mvRule(&g_resprulactions, from, to);
     });
 
-  g_lua.writeFunction("showCacheHitResponseRules", [](boost::optional<ruleparams_t> vars) {
+  luaCtx.writeFunction("showCacheHitResponseRules", [](boost::optional<ruleparams_t> vars) {
       showRules(&g_cachehitresprulactions, vars);
     });
 
-  g_lua.writeFunction("rmCacheHitResponseRule", [](boost::variant<unsigned int, std::string> id) {
+  luaCtx.writeFunction("rmCacheHitResponseRule", [](boost::variant<unsigned int, std::string> id) {
       rmRule(&g_cachehitresprulactions, id);
     });
 
-  g_lua.writeFunction("topCacheHitResponseRule", []() {
+  luaCtx.writeFunction("topCacheHitResponseRule", []() {
       topRule(&g_cachehitresprulactions);
     });
 
-  g_lua.writeFunction("mvCacheHitResponseRule", [](unsigned int from, unsigned int to) {
+  luaCtx.writeFunction("mvCacheHitResponseRule", [](unsigned int from, unsigned int to) {
       mvRule(&g_cachehitresprulactions, from, to);
     });
 
-  g_lua.writeFunction("showSelfAnsweredResponseRules", [](boost::optional<ruleparams_t> vars) {
+  luaCtx.writeFunction("showSelfAnsweredResponseRules", [](boost::optional<ruleparams_t> vars) {
       showRules(&g_selfansweredresprulactions, vars);
     });
 
-  g_lua.writeFunction("rmSelfAnsweredResponseRule", [](boost::variant<unsigned int, std::string> id) {
+  luaCtx.writeFunction("rmSelfAnsweredResponseRule", [](boost::variant<unsigned int, std::string> id) {
       rmRule(&g_selfansweredresprulactions, id);
     });
 
-  g_lua.writeFunction("topSelfAnsweredResponseRule", []() {
+  luaCtx.writeFunction("topSelfAnsweredResponseRule", []() {
       topRule(&g_selfansweredresprulactions);
     });
 
-  g_lua.writeFunction("mvSelfAnsweredResponseRule", [](unsigned int from, unsigned int to) {
+  luaCtx.writeFunction("mvSelfAnsweredResponseRule", [](unsigned int from, unsigned int to) {
       mvRule(&g_selfansweredresprulactions, from, to);
     });
 
-  g_lua.writeFunction("rmRule", [](boost::variant<unsigned int, std::string> id) {
+  luaCtx.writeFunction("rmRule", [](boost::variant<unsigned int, std::string> id) {
       rmRule(&g_rulactions, id);
     });
 
-  g_lua.writeFunction("topRule", []() {
+  luaCtx.writeFunction("topRule", []() {
       topRule(&g_rulactions);
     });
 
-  g_lua.writeFunction("mvRule", [](unsigned int from, unsigned int to) {
+  luaCtx.writeFunction("mvRule", [](unsigned int from, unsigned int to) {
       mvRule(&g_rulactions, from, to);
     });
 
-  g_lua.writeFunction("clearRules", []() {
+  luaCtx.writeFunction("clearRules", []() {
       setLuaSideEffect();
       g_rulactions.modify([](decltype(g_rulactions)::value_type& rulactions) {
           rulactions.clear();
         });
     });
 
-  g_lua.writeFunction("setRules", [](const std::vector<std::pair<int, std::shared_ptr<DNSDistRuleAction>>>& newruleactions) {
+  luaCtx.writeFunction("setRules", [](const std::vector<std::pair<int, std::shared_ptr<DNSDistRuleAction>>>& newruleactions) {
       setLuaSideEffect();
       g_rulactions.modify([newruleactions](decltype(g_rulactions)::value_type& gruleactions) {
           gruleactions.clear();
@@ -265,52 +265,52 @@ void setupLuaRules()
         });
     });
 
-  g_lua.writeFunction("MaxQPSIPRule", [](unsigned int qps, boost::optional<int> ipv4trunc, boost::optional<int> ipv6trunc, boost::optional<int> burst, boost::optional<unsigned int> expiration, boost::optional<unsigned int> cleanupDelay, boost::optional<unsigned int> scanFraction) {
+  luaCtx.writeFunction("MaxQPSIPRule", [](unsigned int qps, boost::optional<int> ipv4trunc, boost::optional<int> ipv6trunc, boost::optional<int> burst, boost::optional<unsigned int> expiration, boost::optional<unsigned int> cleanupDelay, boost::optional<unsigned int> scanFraction) {
       return std::shared_ptr<DNSRule>(new MaxQPSIPRule(qps, burst.get_value_or(qps), ipv4trunc.get_value_or(32), ipv6trunc.get_value_or(64), expiration.get_value_or(300), cleanupDelay.get_value_or(60), scanFraction.get_value_or(10)));
     });
 
-  g_lua.writeFunction("MaxQPSRule", [](unsigned int qps, boost::optional<int> burst) {
+  luaCtx.writeFunction("MaxQPSRule", [](unsigned int qps, boost::optional<int> burst) {
       if(!burst)
         return std::shared_ptr<DNSRule>(new MaxQPSRule(qps));
       else
         return std::shared_ptr<DNSRule>(new MaxQPSRule(qps, *burst));
     });
 
-  g_lua.writeFunction("RegexRule", [](const std::string& str) {
+  luaCtx.writeFunction("RegexRule", [](const std::string& str) {
       return std::shared_ptr<DNSRule>(new RegexRule(str));
     });
 
 #ifdef HAVE_DNS_OVER_HTTPS
-  g_lua.writeFunction("HTTPHeaderRule", [](const std::string& header, const std::string& regex) {
+  luaCtx.writeFunction("HTTPHeaderRule", [](const std::string& header, const std::string& regex) {
       return std::shared_ptr<DNSRule>(new HTTPHeaderRule(header, regex));
     });
-  g_lua.writeFunction("HTTPPathRule", [](const std::string& path) {
+  luaCtx.writeFunction("HTTPPathRule", [](const std::string& path) {
       return std::shared_ptr<DNSRule>(new HTTPPathRule(path));
     });
-  g_lua.writeFunction("HTTPPathRegexRule", [](const std::string& regex) {
+  luaCtx.writeFunction("HTTPPathRegexRule", [](const std::string& regex) {
       return std::shared_ptr<DNSRule>(new HTTPPathRegexRule(regex));
     });
 #endif
 
 #ifdef HAVE_RE2
-  g_lua.writeFunction("RE2Rule", [](const std::string& str) {
+  luaCtx.writeFunction("RE2Rule", [](const std::string& str) {
       return std::shared_ptr<DNSRule>(new RE2Rule(str));
     });
 #endif
 
-  g_lua.writeFunction("SNIRule", [](const std::string& name) {
+  luaCtx.writeFunction("SNIRule", [](const std::string& name) {
       return std::shared_ptr<DNSRule>(new SNIRule(name));
   });
 
-  g_lua.writeFunction("SuffixMatchNodeRule", [](const SuffixMatchNode& smn, boost::optional<bool> quiet) {
+  luaCtx.writeFunction("SuffixMatchNodeRule", [](const SuffixMatchNode& smn, boost::optional<bool> quiet) {
       return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false));
     });
 
-  g_lua.writeFunction("NetmaskGroupRule", [](const NetmaskGroup& nmg, boost::optional<bool> src, boost::optional<bool> quiet) {
+  luaCtx.writeFunction("NetmaskGroupRule", [](const NetmaskGroup& nmg, boost::optional<bool> src, boost::optional<bool> quiet) {
       return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false));
     });
 
-  g_lua.writeFunction("benchRule", [](std::shared_ptr<DNSRule> rule, boost::optional<int> times_, boost::optional<string> suffix_)  {
+  luaCtx.writeFunction("benchRule", [](std::shared_ptr<DNSRule> rule, boost::optional<int> times_, boost::optional<string> suffix_)  {
       setLuaNoSideEffect();
       int times = times_.get_value_or(100000);
       DNSName suffix(suffix_.get_value_or("powerdns.com"));
@@ -349,19 +349,19 @@ void setupLuaRules()
 
     });
 
-  g_lua.writeFunction("AllRule", []() {
+  luaCtx.writeFunction("AllRule", []() {
       return std::shared_ptr<DNSRule>(new AllRule());
     });
 
-  g_lua.writeFunction("ProbaRule", [](double proba) {
+  luaCtx.writeFunction("ProbaRule", [](double proba) {
       return std::shared_ptr<DNSRule>(new ProbaRule(proba));
     });
 
-  g_lua.writeFunction("QNameRule", [](const std::string& qname) {
+  luaCtx.writeFunction("QNameRule", [](const std::string& qname) {
       return std::shared_ptr<DNSRule>(new QNameRule(DNSName(qname)));
     });
 
-  g_lua.writeFunction("QTypeRule", [](boost::variant<int, std::string> str) {
+  luaCtx.writeFunction("QTypeRule", [](boost::variant<int, std::string> str) {
       uint16_t qtype;
       if(auto dir = boost::get<int>(&str)) {
         qtype = *dir;
@@ -375,123 +375,123 @@ void setupLuaRules()
       return std::shared_ptr<DNSRule>(new QTypeRule(qtype));
     });
 
-  g_lua.writeFunction("QClassRule", [](int c) {
+  luaCtx.writeFunction("QClassRule", [](int c) {
       return std::shared_ptr<DNSRule>(new QClassRule(c));
     });
 
-  g_lua.writeFunction("OpcodeRule", [](uint8_t code) {
+  luaCtx.writeFunction("OpcodeRule", [](uint8_t code) {
       return std::shared_ptr<DNSRule>(new OpcodeRule(code));
     });
 
-  g_lua.writeFunction("AndRule", [](vector<pair<int, std::shared_ptr<DNSRule> > >a) {
+  luaCtx.writeFunction("AndRule", [](vector<pair<int, std::shared_ptr<DNSRule> > >a) {
       return std::shared_ptr<DNSRule>(new AndRule(a));
     });
 
-  g_lua.writeFunction("OrRule", [](vector<pair<int, std::shared_ptr<DNSRule> > >a) {
+  luaCtx.writeFunction("OrRule", [](vector<pair<int, std::shared_ptr<DNSRule> > >a) {
       return std::shared_ptr<DNSRule>(new OrRule(a));
     });
 
-  g_lua.writeFunction("DSTPortRule", [](uint16_t port) {
+  luaCtx.writeFunction("DSTPortRule", [](uint16_t port) {
       return std::shared_ptr<DNSRule>(new DSTPortRule(port));
     });
 
-  g_lua.writeFunction("TCPRule", [](bool tcp) {
+  luaCtx.writeFunction("TCPRule", [](bool tcp) {
       return std::shared_ptr<DNSRule>(new TCPRule(tcp));
     });
 
-  g_lua.writeFunction("DNSSECRule", []() {
+  luaCtx.writeFunction("DNSSECRule", []() {
       return std::shared_ptr<DNSRule>(new DNSSECRule());
     });
 
-  g_lua.writeFunction("NotRule", [](std::shared_ptr<DNSRule>rule) {
+  luaCtx.writeFunction("NotRule", [](std::shared_ptr<DNSRule>rule) {
       return std::shared_ptr<DNSRule>(new NotRule(rule));
     });
 
-  g_lua.writeFunction("RecordsCountRule", [](uint8_t section, uint16_t minCount, uint16_t maxCount) {
+  luaCtx.writeFunction("RecordsCountRule", [](uint8_t section, uint16_t minCount, uint16_t maxCount) {
       return std::shared_ptr<DNSRule>(new RecordsCountRule(section, minCount, maxCount));
     });
 
-  g_lua.writeFunction("RecordsTypeCountRule", [](uint8_t section, uint16_t type, uint16_t minCount, uint16_t maxCount) {
+  luaCtx.writeFunction("RecordsTypeCountRule", [](uint8_t section, uint16_t type, uint16_t minCount, uint16_t maxCount) {
       return std::shared_ptr<DNSRule>(new RecordsTypeCountRule(section, type, minCount, maxCount));
     });
 
-  g_lua.writeFunction("TrailingDataRule", []() {
+  luaCtx.writeFunction("TrailingDataRule", []() {
       return std::shared_ptr<DNSRule>(new TrailingDataRule());
     });
 
-  g_lua.writeFunction("QNameLabelsCountRule", [](unsigned int minLabelsCount, unsigned int maxLabelsCount) {
+  luaCtx.writeFunction("QNameLabelsCountRule", [](unsigned int minLabelsCount, unsigned int maxLabelsCount) {
       return std::shared_ptr<DNSRule>(new QNameLabelsCountRule(minLabelsCount, maxLabelsCount));
     });
 
-  g_lua.writeFunction("QNameWireLengthRule", [](size_t min, size_t max) {
+  luaCtx.writeFunction("QNameWireLengthRule", [](size_t min, size_t max) {
       return std::shared_ptr<DNSRule>(new QNameWireLengthRule(min, max));
     });
 
-  g_lua.writeFunction("RCodeRule", [](uint8_t rcode) {
+  luaCtx.writeFunction("RCodeRule", [](uint8_t rcode) {
       return std::shared_ptr<DNSRule>(new RCodeRule(rcode));
     });
 
-  g_lua.writeFunction("ERCodeRule", [](uint8_t rcode) {
+  luaCtx.writeFunction("ERCodeRule", [](uint8_t rcode) {
       return std::shared_ptr<DNSRule>(new ERCodeRule(rcode));
     });
 
-  g_lua.writeFunction("EDNSVersionRule", [](uint8_t version) {
+  luaCtx.writeFunction("EDNSVersionRule", [](uint8_t version) {
       return std::shared_ptr<DNSRule>(new EDNSVersionRule(version));
     });
 
-  g_lua.writeFunction("EDNSOptionRule", [](uint16_t optcode) {
+  luaCtx.writeFunction("EDNSOptionRule", [](uint16_t optcode) {
       return std::shared_ptr<DNSRule>(new EDNSOptionRule(optcode));
     });
 
-  g_lua.writeFunction("showRules", [](boost::optional<ruleparams_t> vars) {
+  luaCtx.writeFunction("showRules", [](boost::optional<ruleparams_t> vars) {
       showRules(&g_rulactions, vars);
     });
 
-  g_lua.writeFunction("RDRule", []() {
+  luaCtx.writeFunction("RDRule", []() {
       return std::shared_ptr<DNSRule>(new RDRule());
     });
 
-  g_lua.writeFunction("TagRule", [](std::string tag, boost::optional<std::string> value) {
+  luaCtx.writeFunction("TagRule", [](std::string tag, boost::optional<std::string> value) {
       return std::shared_ptr<DNSRule>(new TagRule(tag, value));
     });
 
-  g_lua.writeFunction("TimedIPSetRule", []() {
+  luaCtx.writeFunction("TimedIPSetRule", []() {
       return std::shared_ptr<TimedIPSetRule>(new TimedIPSetRule());
     });
 
-  g_lua.writeFunction("PoolAvailableRule", [](std::string poolname) {
+  luaCtx.writeFunction("PoolAvailableRule", [](std::string poolname) {
     return std::shared_ptr<DNSRule>(new PoolAvailableRule(poolname));
   });
 
-  g_lua.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)()>("clear", [](std::shared_ptr<TimedIPSetRule> tisr) {
+  luaCtx.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)()>("clear", [](std::shared_ptr<TimedIPSetRule> tisr) {
       tisr->clear();
     });
 
-  g_lua.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)()>("cleanup", [](std::shared_ptr<TimedIPSetRule> tisr) {
+  luaCtx.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)()>("cleanup", [](std::shared_ptr<TimedIPSetRule> tisr) {
       tisr->cleanup();
     });
 
-  g_lua.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)(const ComboAddress& ca, int t)>("add", [](std::shared_ptr<TimedIPSetRule> tisr, const ComboAddress& ca, int t) {
+  luaCtx.registerFunction<void(std::shared_ptr<TimedIPSetRule>::*)(const ComboAddress& ca, int t)>("add", [](std::shared_ptr<TimedIPSetRule> tisr, const ComboAddress& ca, int t) {
       tisr->add(ca, time(0)+t);
     });
 
-  g_lua.registerFunction<std::shared_ptr<DNSRule>(std::shared_ptr<TimedIPSetRule>::*)()>("slice", [](std::shared_ptr<TimedIPSetRule> tisr) {
+  luaCtx.registerFunction<std::shared_ptr<DNSRule>(std::shared_ptr<TimedIPSetRule>::*)()>("slice", [](std::shared_ptr<TimedIPSetRule> tisr) {
       return std::dynamic_pointer_cast<DNSRule>(tisr);
     });
 
-  g_lua.writeFunction("QNameSetRule", [](const DNSNameSet& names) {
+  luaCtx.writeFunction("QNameSetRule", [](const DNSNameSet& names) {
       return std::shared_ptr<DNSRule>(new QNameSetRule(names));
     });
 
-  g_lua.writeFunction("KeyValueStoreLookupRule", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey) {
+  luaCtx.writeFunction("KeyValueStoreLookupRule", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey) {
       return std::shared_ptr<DNSRule>(new KeyValueStoreLookupRule(kvs, lookupKey));
     });
 
-  g_lua.writeFunction("LuaRule", [](LuaRule::func_t func) {
+  luaCtx.writeFunction("LuaRule", [](LuaRule::func_t func) {
       return std::shared_ptr<DNSRule>(new LuaRule(func));
     });
 
-  g_lua.writeFunction("LuaFFIRule", [](LuaFFIRule::func_t func) {
+  luaCtx.writeFunction("LuaFFIRule", [](LuaFFIRule::func_t func) {
       return std::shared_ptr<DNSRule>(new LuaFFIRule(func));
     });
 }
index 7058deab3d99a606df76e9448ac51fe2462c234e..9e263f7d7a7b0ba140b1fa0b0fc4c89f4ad41377 100644 (file)
@@ -25,9 +25,9 @@
 
 #undef BADSIG  // signal.h SIG_ERR
 
-void setupLuaVars()
+void setupLuaVars(LuaContext& luaCtx)
 {
-  g_lua.writeVariable("DNSAction", std::unordered_map<string,int>{
+  luaCtx.writeVariable("DNSAction", std::unordered_map<string,int>{
       {"Drop", (int)DNSAction::Action::Drop},
       {"Nxdomain", (int)DNSAction::Action::Nxdomain},
       {"Refused", (int)DNSAction::Action::Refused},
@@ -44,7 +44,7 @@ void setupLuaVars()
       {"NoRecurse", (int)DNSAction::Action::NoRecurse}
     });
 
-  g_lua.writeVariable("DNSResponseAction", std::unordered_map<string,int>{
+  luaCtx.writeVariable("DNSResponseAction", std::unordered_map<string,int>{
       {"Allow",        (int)DNSResponseAction::Action::Allow        },
       {"Delay",        (int)DNSResponseAction::Action::Delay        },
       {"Drop",         (int)DNSResponseAction::Action::Drop         },
@@ -53,14 +53,14 @@ void setupLuaVars()
       {"None",         (int)DNSResponseAction::Action::None         }
     });
 
-  g_lua.writeVariable("DNSClass", std::unordered_map<string,int>{
+  luaCtx.writeVariable("DNSClass", std::unordered_map<string,int>{
       {"IN",    QClass::IN    },
       {"CHAOS", QClass::CHAOS },
       {"NONE",  QClass::NONE  },
       {"ANY",   QClass::ANY   }
     });
 
-  g_lua.writeVariable("DNSOpcode", std::unordered_map<string,int>{
+  luaCtx.writeVariable("DNSOpcode", std::unordered_map<string,int>{
       {"Query",  Opcode::Query  },
       {"IQuery", Opcode::IQuery },
       {"Status", Opcode::Status },
@@ -68,14 +68,14 @@ void setupLuaVars()
       {"Update", Opcode::Update }
     });
 
-  g_lua.writeVariable("DNSSection", std::unordered_map<string,int>{
+  luaCtx.writeVariable("DNSSection", std::unordered_map<string,int>{
       {"Question",  0 },
       {"Answer",    1 },
       {"Authority", 2 },
       {"Additional",3 }
     });
 
-  g_lua.writeVariable("EDNSOptionCode", std::unordered_map<string,int>{
+  luaCtx.writeVariable("EDNSOptionCode", std::unordered_map<string,int>{
       {"NSID",         EDNSOptionCode::NSID },
       {"DAU",          EDNSOptionCode::DAU },
       {"DHU",          EDNSOptionCode::DHU },
@@ -89,7 +89,7 @@ void setupLuaVars()
       {"KEYTAG",       EDNSOptionCode::KEYTAG }
     });
 
-  g_lua.writeVariable("DNSRCode", std::unordered_map<string, int>{
+  luaCtx.writeVariable("DNSRCode", std::unordered_map<string, int>{
       {"NOERROR",  RCode::NoError  },
       {"FORMERR",  RCode::FormErr  },
       {"SERVFAIL", RCode::ServFail },
@@ -115,9 +115,9 @@ void setupLuaVars()
   vector<pair<string, int> > dd;
   for(const auto& n : QType::names)
     dd.push_back({n.first, n.second});
-  g_lua.writeVariable("DNSQType", dd);
+  luaCtx.writeVariable("DNSQType", dd);
 
-  g_lua.executeCode(R"LUA(
+  luaCtx.executeCode(R"LUA(
     local tables = {
       DNSQType = DNSQType,
       DNSRCode = DNSRCode
@@ -139,7 +139,7 @@ void setupLuaVars()
   );
 
 #ifdef HAVE_DNSCRYPT
-    g_lua.writeVariable("DNSCryptExchangeVersion", std::unordered_map<string,int>{
+    luaCtx.writeVariable("DNSCryptExchangeVersion", std::unordered_map<string,int>{
         { "VERSION1", DNSCryptExchangeVersion::VERSION1 },
         { "VERSION2", DNSCryptExchangeVersion::VERSION2 },
     });
index 3dacbc83f6ff742cf303c48fba6071cf4ffaaee1..b16d466c873e3815260a1406d806f6b19b1a6fc7 100644 (file)
@@ -63,7 +63,7 @@
 
 using std::thread;
 
-static vector<std::function<void(void)>>* g_launchWork = nullptr;
+static boost::optional<std::vector<std::function<void(void)>>> g_launchWork = boost::none;
 
 boost::tribool g_noLuaSideEffect;
 static bool g_included{false};
@@ -223,18 +223,18 @@ static void parseTLSConfig(TLSConfig& config, const std::string& context, boost:
 
 #endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
 
-static void setupLuaConfig(bool client, bool configCheck)
+static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 {
   typedef std::unordered_map<std::string, boost::variant<bool, std::string, vector<pair<int, std::string> >, DownstreamState::checkfunc_t > > newserver_t;
-  g_lua.writeFunction("inClientStartup", [client]() {
+  luaCtx.writeFunction("inClientStartup", [client]() {
         return client && !g_configurationDone;
   });
 
-  g_lua.writeFunction("inConfigCheck", [configCheck]() {
+  luaCtx.writeFunction("inConfigCheck", [configCheck]() {
         return !configCheck;
   });
 
-  g_lua.writeFunction("newServer",
+  luaCtx.writeFunction("newServer",
                       [client, configCheck](boost::variant<string,newserver_t> pvars, boost::optional<int> qps) {
       setLuaSideEffect();
 
@@ -500,7 +500,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       if (ret->connected) {
         ret->threadStarted.test_and_set();
 
-        if(g_launchWork) {
+        if (g_launchWork) {
           g_launchWork->push_back([ret,cpus]() {
                                     ret->tid = thread(responderThread, ret);
                                     if (!cpus.empty()) {
@@ -525,7 +525,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       return ret;
       } );
 
-  g_lua.writeFunction("rmServer",
+  luaCtx.writeFunction("rmServer",
                       [](boost::variant<std::shared_ptr<DownstreamState>, int, std::string> var)
                       {
                         setLuaSideEffect();
@@ -561,20 +561,20 @@ static void setupLuaConfig(bool client, bool configCheck)
                         server->stop();
                       } );
 
-  g_lua.writeFunction("truncateTC", [](bool tc) { setLuaSideEffect(); g_truncateTC=tc; });
-  g_lua.writeFunction("fixupCase", [](bool fu) { setLuaSideEffect(); g_fixupCase=fu; });
+  luaCtx.writeFunction("truncateTC", [](bool tc) { setLuaSideEffect(); g_truncateTC=tc; });
+  luaCtx.writeFunction("fixupCase", [](bool fu) { setLuaSideEffect(); g_fixupCase=fu; });
 
-  g_lua.writeFunction("addACL", [](const std::string& domain) {
+  luaCtx.writeFunction("addACL", [](const std::string& domain) {
       setLuaSideEffect();
       g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); });
     });
 
-  g_lua.writeFunction("rmACL", [](const std::string& netmask) {
+  luaCtx.writeFunction("rmACL", [](const std::string& netmask) {
     setLuaSideEffect();
     g_ACL.modify([netmask](NetmaskGroup& nmg) { nmg.deleteMask(netmask); });
   });
 
-  g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) {
+  luaCtx.writeFunction("setLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) {
       setLuaSideEffect();
       if(client)
        return;
@@ -615,7 +615,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) {
+  luaCtx.writeFunction("addLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) {
       setLuaSideEffect();
       if(client)
        return;
@@ -647,7 +647,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setACL", [](boost::variant<string,vector<pair<int, string>>> inp) {
+  luaCtx.writeFunction("setACL", [](boost::variant<string,vector<pair<int, string>>> inp) {
       setLuaSideEffect();
       NetmaskGroup nmg;
       if(auto str = boost::get<string>(&inp)) {
@@ -659,7 +659,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_ACL.setState(nmg);
   });
 
-  g_lua.writeFunction("showACL", []() {
+  luaCtx.writeFunction("showACL", []() {
       setLuaNoSideEffect();
       vector<string> vec;
 
@@ -670,7 +670,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 
     });
 
-  g_lua.writeFunction("shutdown", []() {
+  luaCtx.writeFunction("shutdown", []() {
 #ifdef HAVE_SYSTEMD
       sd_notify(0, "STOPPING=1");
 #endif /* HAVE_SYSTEMD */
@@ -690,7 +690,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 
   typedef std::unordered_map<std::string, boost::variant<bool, std::string> > showserversopts_t;
 
-  g_lua.writeFunction("showServers", [](boost::optional<showserversopts_t> vars) {
+  luaCtx.writeFunction("showServers", [](boost::optional<showserversopts_t> vars) {
       setLuaNoSideEffect();
       bool showUUIDs = false;
       if (vars) {
@@ -752,7 +752,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("getServers", []() {
+  luaCtx.writeFunction("getServers", []() {
       setLuaNoSideEffect();
       vector<pair<int, std::shared_ptr<DownstreamState> > > ret;
       int count=1;
@@ -762,12 +762,12 @@ static void setupLuaConfig(bool client, bool configCheck)
       return ret;
     });
 
-  g_lua.writeFunction("getPoolServers", [](string pool) {
+  luaCtx.writeFunction("getPoolServers", [](string pool) {
       const auto poolServers = getDownstreamCandidates(g_pools.getCopy(), pool);
       return *poolServers;
     });
 
-  g_lua.writeFunction("getServer", [client](boost::variant<unsigned int, std::string> i) {
+  luaCtx.writeFunction("getServer", [client](boost::variant<unsigned int, std::string> i) {
       if (client) {
         return std::make_shared<DownstreamState>(ComboAddress());
       }
@@ -788,7 +788,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       return std::shared_ptr<DownstreamState>(nullptr);
     });
 
-  g_lua.writeFunction("carbonServer", [](const std::string& address, boost::optional<string> ourName,
+  luaCtx.writeFunction("carbonServer", [](const std::string& address, boost::optional<string> ourName,
                                         boost::optional<unsigned int> interval, boost::optional<string> namespace_name,
                                          boost::optional<string> instance_name) {
       setLuaSideEffect();
@@ -803,7 +803,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_carbon.setState(ours);
   });
 
-  g_lua.writeFunction("webserver", [client,configCheck](const std::string& address, const std::string& password, const boost::optional<std::string> apiKey, const boost::optional<std::map<std::string, std::string> > customHeaders, const boost::optional<std::string> acl) {
+  luaCtx.writeFunction("webserver", [client,configCheck](const std::string& address, const std::string& password, const boost::optional<std::string> apiKey, const boost::optional<std::map<std::string, std::string> > customHeaders, const boost::optional<std::string> acl) {
       setLuaSideEffect();
       ComboAddress local;
       try {
@@ -832,10 +832,12 @@ static void setupLuaConfig(bool client, bool configCheck)
           thread t(dnsdistWebserverThread, sock, local);
          t.detach();
        };
-       if(g_launchWork)
+       if (g_launchWork) {
          g_launchWork->push_back(launch);
-       else
+        }
+       else {
          launch();
+        }
       }
       catch(std::exception& e) {
        g_outputBuffer="Unable to bind to webserver socket on " + local.toStringWithPort() + ": " + e.what();
@@ -846,7 +848,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 
   typedef std::unordered_map<std::string, boost::variant<std::string, std::map<std::string, std::string>> > webserveropts_t;
 
-  g_lua.writeFunction("setWebserverConfig", [](boost::optional<webserveropts_t> vars) {
+  luaCtx.writeFunction("setWebserverConfig", [](boost::optional<webserveropts_t> vars) {
       setLuaSideEffect();
 
       if (!vars) {
@@ -874,7 +876,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("controlSocket", [client,configCheck](const std::string& str) {
+  luaCtx.writeFunction("controlSocket", [client,configCheck](const std::string& str) {
       setLuaSideEffect();
       ComboAddress local(str, 5199);
 
@@ -899,11 +901,12 @@ static void setupLuaConfig(bool client, bool configCheck)
            thread t(controlThread, sock, local);
            t.detach();
        };
-       if(g_launchWork)
+       if (g_launchWork) {
          g_launchWork->push_back(launch);
-       else
+        }
+       else {
          launch();
-
+        }
       }
       catch(std::exception& e) {
        g_outputBuffer="Unable to bind to control socket on " + local.toStringWithPort() + ": " + e.what();
@@ -911,7 +914,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("addConsoleACL", [](const std::string& netmask) {
+  luaCtx.writeFunction("addConsoleACL", [](const std::string& netmask) {
       setLuaSideEffect();
 #ifndef HAVE_LIBSODIUM
       warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
@@ -920,7 +923,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_consoleACL.modify([netmask](NetmaskGroup& nmg) { nmg.addMask(netmask); });
     });
 
-  g_lua.writeFunction("setConsoleACL", [](boost::variant<string,vector<pair<int, string>>> inp) {
+  luaCtx.writeFunction("setConsoleACL", [](boost::variant<string,vector<pair<int, string>>> inp) {
       setLuaSideEffect();
 
 #ifndef HAVE_LIBSODIUM
@@ -937,7 +940,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_consoleACL.setState(nmg);
   });
 
-  g_lua.writeFunction("showConsoleACL", []() {
+  luaCtx.writeFunction("showConsoleACL", []() {
       setLuaNoSideEffect();
 
 #ifndef HAVE_LIBSODIUM
@@ -952,7 +955,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("clearQueryCounters", []() {
+  luaCtx.writeFunction("clearQueryCounters", []() {
       unsigned int size{0};
       {
         WriteLock wl(&g_qcount.queryLock);
@@ -964,7 +967,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_outputBuffer = (fmt % size).str();
     });
 
-  g_lua.writeFunction("getQueryCounters", [](boost::optional<unsigned int> optMax) {
+  luaCtx.writeFunction("getQueryCounters", [](boost::optional<unsigned int> optMax) {
       setLuaNoSideEffect();
       ReadLock rl(&g_qcount.queryLock);
       g_outputBuffer = "query counting is currently: ";
@@ -980,18 +983,18 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setQueryCount", [](bool enabled) { g_qcount.enabled=enabled; });
+  luaCtx.writeFunction("setQueryCount", [](bool enabled) { g_qcount.enabled=enabled; });
 
-  g_lua.writeFunction("setQueryCountFilter", [](QueryCountFilter func) {
+  luaCtx.writeFunction("setQueryCountFilter", [](QueryCountFilter func) {
       g_qcount.filter = func;
     });
 
-  g_lua.writeFunction("makeKey", []() {
+  luaCtx.writeFunction("makeKey", []() {
       setLuaNoSideEffect();
       g_outputBuffer="setKey("+newKey()+")\n";
     });
 
-  g_lua.writeFunction("setKey", [](const std::string& key) {
+  luaCtx.writeFunction("setKey", [](const std::string& key) {
       if(!g_configurationDone && ! g_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
         return;                                     // but later setKeys() trump the -k value again
       }
@@ -1009,11 +1012,11 @@ static void setupLuaConfig(bool client, bool configCheck)
        g_consoleKey=newkey;
     });
 
-  g_lua.writeFunction("clearConsoleHistory", []() {
+  luaCtx.writeFunction("clearConsoleHistory", []() {
       clearConsoleHistory();
     });
 
-  g_lua.writeFunction("testCrypto", [](boost::optional<string> optTestMsg)
+  luaCtx.writeFunction("testCrypto", [](boost::optional<string> optTestMsg)
    {
      setLuaNoSideEffect();
 #ifdef HAVE_LIBSODIUM
@@ -1055,13 +1058,13 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
    });
 
-  g_lua.writeFunction("setTCPRecvTimeout", [](int timeout) { g_tcpRecvTimeout=timeout; });
+  luaCtx.writeFunction("setTCPRecvTimeout", [](int timeout) { g_tcpRecvTimeout=timeout; });
 
-  g_lua.writeFunction("setTCPSendTimeout", [](int timeout) { g_tcpSendTimeout=timeout; });
+  luaCtx.writeFunction("setTCPSendTimeout", [](int timeout) { g_tcpSendTimeout=timeout; });
 
-  g_lua.writeFunction("setUDPTimeout", [](int timeout) { g_udpTimeout=timeout; });
+  luaCtx.writeFunction("setUDPTimeout", [](int timeout) { g_udpTimeout=timeout; });
 
-  g_lua.writeFunction("setMaxUDPOutstanding", [](uint16_t max) {
+  luaCtx.writeFunction("setMaxUDPOutstanding", [](uint16_t max) {
       if (!g_configurationDone) {
         g_maxOutstanding = max;
       } else {
@@ -1069,7 +1072,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setMaxTCPClientThreads", [](uint64_t max) {
+  luaCtx.writeFunction("setMaxTCPClientThreads", [](uint64_t max) {
       if (!g_configurationDone) {
         g_maxTCPClientThreads = max;
       } else {
@@ -1077,7 +1080,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setMaxTCPQueuedConnections", [](uint64_t max) {
+  luaCtx.writeFunction("setMaxTCPQueuedConnections", [](uint64_t max) {
       if (!g_configurationDone) {
         g_maxTCPQueuedConnections = max;
       } else {
@@ -1085,7 +1088,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setMaxTCPQueriesPerConnection", [](size_t max) {
+  luaCtx.writeFunction("setMaxTCPQueriesPerConnection", [](size_t max) {
       if (!g_configurationDone) {
         g_maxTCPQueriesPerConn = max;
       } else {
@@ -1093,7 +1096,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setMaxTCPConnectionsPerClient", [](size_t max) {
+  luaCtx.writeFunction("setMaxTCPConnectionsPerClient", [](size_t max) {
       if (!g_configurationDone) {
         g_maxTCPConnectionsPerClient = max;
       } else {
@@ -1101,7 +1104,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setMaxTCPConnectionDuration", [](size_t max) {
+  luaCtx.writeFunction("setMaxTCPConnectionDuration", [](size_t max) {
       if (!g_configurationDone) {
         g_maxTCPConnectionDuration = max;
       } else {
@@ -1109,19 +1112,19 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setCacheCleaningDelay", [](uint32_t delay) { g_cacheCleaningDelay = delay; });
+  luaCtx.writeFunction("setCacheCleaningDelay", [](uint32_t delay) { g_cacheCleaningDelay = delay; });
 
-  g_lua.writeFunction("setCacheCleaningPercentage", [](uint16_t percentage) { if (percentage < 100) g_cacheCleaningPercentage = percentage; else g_cacheCleaningPercentage = 100; });
+  luaCtx.writeFunction("setCacheCleaningPercentage", [](uint16_t percentage) { if (percentage < 100) g_cacheCleaningPercentage = percentage; else g_cacheCleaningPercentage = 100; });
 
-  g_lua.writeFunction("setECSSourcePrefixV4", [](uint16_t prefix) { g_ECSSourcePrefixV4=prefix; });
+  luaCtx.writeFunction("setECSSourcePrefixV4", [](uint16_t prefix) { g_ECSSourcePrefixV4=prefix; });
 
-  g_lua.writeFunction("setECSSourcePrefixV6", [](uint16_t prefix) { g_ECSSourcePrefixV6=prefix; });
+  luaCtx.writeFunction("setECSSourcePrefixV6", [](uint16_t prefix) { g_ECSSourcePrefixV6=prefix; });
 
-  g_lua.writeFunction("setECSOverride", [](bool override) { g_ECSOverride=override; });
+  luaCtx.writeFunction("setECSOverride", [](bool override) { g_ECSOverride=override; });
 
-  g_lua.writeFunction("setPreserveTrailingData", [](bool preserve) { g_preserveTrailingData = preserve; });
+  luaCtx.writeFunction("setPreserveTrailingData", [](bool preserve) { g_preserveTrailingData = preserve; });
 
-  g_lua.writeFunction("showDynBlocks", []() {
+  luaCtx.writeFunction("showDynBlocks", []() {
       setLuaNoSideEffect();
       auto slow = g_dynblockNMG.getCopy();
       struct timespec now;
@@ -1144,7 +1147,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 
     });
 
-  g_lua.writeFunction("clearDynBlocks", []() {
+  luaCtx.writeFunction("clearDynBlocks", []() {
       setLuaSideEffect();
       nmts_t nmg;
       g_dynblockNMG.setState(nmg);
@@ -1152,7 +1155,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_dynblockSMT.setState(smt);
     });
 
-  g_lua.writeFunction("addDynBlocks",
+  luaCtx.writeFunction("addDynBlocks",
                       [](const std::unordered_map<ComboAddress,unsigned int, ComboAddress::addressOnlyHash, ComboAddress::addressOnlyEqual>& m, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action) {
                            if (m.empty()) {
                              return;
@@ -1185,7 +1188,7 @@ static void setupLuaConfig(bool client, bool configCheck)
                           g_dynblockNMG.setState(slow);
                         });
 
-  g_lua.writeFunction("addDynBlockSMT",
+  luaCtx.writeFunction("addDynBlockSMT",
                       [](const vector<pair<unsigned int, string> >&names, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action) {
                            if (names.empty()) {
                              return;
@@ -1222,7 +1225,7 @@ static void setupLuaConfig(bool client, bool configCheck)
                           g_dynblockSMT.setState(slow);
                         });
 
-  g_lua.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
+  luaCtx.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
       if (!g_configurationDone) {
         if (action == DNSAction::Action::Drop || action == DNSAction::Action::NoOp || action == DNSAction::Action::Nxdomain || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate || action == DNSAction::Action::NoRecurse) {
           g_dynBlockAction = action;
@@ -1236,7 +1239,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, boost::variant<std::string, std::vector<std::pair<int, std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int, std::string>>> keyFiles, boost::optional<localbind_t> vars) {
+  luaCtx.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, boost::variant<std::string, std::vector<std::pair<int, std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int, std::string>>> keyFiles, boost::optional<localbind_t> vars) {
       if (g_configurationDone) {
         g_outputBuffer="addDNSCryptBind cannot be used at runtime!\n";
         return;
@@ -1304,7 +1307,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 
     });
 
-  g_lua.writeFunction("showDNSCryptBinds", []() {
+  luaCtx.writeFunction("showDNSCryptBinds", []() {
       setLuaNoSideEffect();
 #ifdef HAVE_DNSCRYPT
       ostringstream ret;
@@ -1329,7 +1332,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
     });
 
-  g_lua.writeFunction("getDNSCryptBind", [](size_t idx) {
+  luaCtx.writeFunction("getDNSCryptBind", [](size_t idx) {
       setLuaNoSideEffect();
 #ifdef HAVE_DNSCRYPT
       std::shared_ptr<DNSCryptContext> ret = nullptr;
@@ -1342,12 +1345,12 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
     });
 
-  g_lua.writeFunction("getDNSCryptBindCount", []() {
+  luaCtx.writeFunction("getDNSCryptBindCount", []() {
       setLuaNoSideEffect();
       return g_dnsCryptLocals.size();
     });
 
-  g_lua.writeFunction("generateDNSCryptProviderKeys", [client](const std::string& publicKeyFile, const std::string privateKeyFile) {
+  luaCtx.writeFunction("generateDNSCryptProviderKeys", [client](const std::string& publicKeyFile, const std::string privateKeyFile) {
       setLuaNoSideEffect();
 #ifdef HAVE_DNSCRYPT
       if (client) {
@@ -1382,7 +1385,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
     });
 
-  g_lua.writeFunction("printDNSCryptProviderFingerprint", [](const std::string& publicKeyFile) {
+  luaCtx.writeFunction("printDNSCryptProviderFingerprint", [](const std::string& publicKeyFile) {
       setLuaNoSideEffect();
 #ifdef HAVE_DNSCRYPT
       unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
@@ -1407,7 +1410,7 @@ static void setupLuaConfig(bool client, bool configCheck)
     });
 
 #ifdef HAVE_DNSCRYPT
-  g_lua.writeFunction("generateDNSCryptCertificate", [client](const std::string& providerPrivateKeyFile, const std::string& certificateFile, const std::string privateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
+  luaCtx.writeFunction("generateDNSCryptCertificate", [client](const std::string& providerPrivateKeyFile, const std::string& certificateFile, const std::string privateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
       setLuaNoSideEffect();
       if (client) {
         return;
@@ -1428,7 +1431,7 @@ static void setupLuaConfig(bool client, bool configCheck)
     });
 #endif
 
-  g_lua.writeFunction("showPools", []() {
+  luaCtx.writeFunction("showPools", []() {
       setLuaNoSideEffect();
       try {
         ostringstream ret;
@@ -1441,9 +1444,9 @@ static void setupLuaConfig(bool client, bool configCheck)
           const string& name = entry.first;
           const std::shared_ptr<ServerPool> pool = entry.second;
           string cache = pool->packetCache != nullptr ? pool->packetCache->toString() : "";
-          string policy = g_policy.getLocal()->name;
+          string policy = g_policy.getLocal()->getName();
           if (pool->policy != nullptr) {
-            policy = pool->policy->name;
+            policy = pool->policy->getName();
           }
           string servers;
 
@@ -1465,7 +1468,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }catch(std::exception& e) { g_outputBuffer=e.what(); throw; }
     });
 
-  g_lua.writeFunction("getPool", [client](const string& poolName) {
+  luaCtx.writeFunction("getPool", [client](const string& poolName) {
       if (client) {
         return std::make_shared<ServerPool>();
       }
@@ -1475,10 +1478,10 @@ static void setupLuaConfig(bool client, bool configCheck)
       return pool;
     });
 
-  g_lua.writeFunction("setVerboseHealthChecks", [](bool verbose) { g_verboseHealthChecks=verbose; });
-  g_lua.writeFunction("setStaleCacheEntriesTTL", [](uint32_t ttl) { g_staleCacheEntriesTTL = ttl; });
+  luaCtx.writeFunction("setVerboseHealthChecks", [](bool verbose) { g_verboseHealthChecks=verbose; });
+  luaCtx.writeFunction("setStaleCacheEntriesTTL", [](uint32_t ttl) { g_staleCacheEntriesTTL = ttl; });
 
-  g_lua.writeFunction("showBinds", []() {
+  luaCtx.writeFunction("showBinds", []() {
       setLuaNoSideEffect();
       try {
         ostringstream ret;
@@ -1495,7 +1498,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }catch(std::exception& e) { g_outputBuffer=e.what(); throw; }
     });
 
-  g_lua.writeFunction("getBind", [](size_t num) {
+  luaCtx.writeFunction("getBind", [](size_t num) {
       setLuaNoSideEffect();
       ClientState* ret = nullptr;
       if(num < g_frontends.size()) {
@@ -1504,12 +1507,12 @@ static void setupLuaConfig(bool client, bool configCheck)
       return ret;
       });
 
-  g_lua.writeFunction("getBindCount", []() {
+  luaCtx.writeFunction("getBindCount", []() {
       setLuaNoSideEffect();
       return g_frontends.size();
     });
 
-  g_lua.writeFunction("help", [](boost::optional<std::string> command) {
+  luaCtx.writeFunction("help", [](boost::optional<std::string> command) {
       setLuaNoSideEffect();
       g_outputBuffer = "";
       for (const auto& keyword : g_consoleKeywords) {
@@ -1526,18 +1529,18 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("showVersion", []() {
+  luaCtx.writeFunction("showVersion", []() {
       setLuaNoSideEffect();
       g_outputBuffer = "dnsdist " + std::string(VERSION) + "\n";
     });
 
-  g_lua.writeFunction("showSecurityStatus", []() {
+  luaCtx.writeFunction("showSecurityStatus", []() {
       setLuaNoSideEffect();
       g_outputBuffer = std::to_string(g_stats.securityStatus) + "\n";
     });
 
 #ifdef HAVE_EBPF
-  g_lua.writeFunction("setDefaultBPFFilter", [](std::shared_ptr<BPFFilter> bpf) {
+  luaCtx.writeFunction("setDefaultBPFFilter", [](std::shared_ptr<BPFFilter> bpf) {
       if (g_configurationDone) {
         g_outputBuffer="setDefaultBPFFilter() cannot be used at runtime!\n";
         return;
@@ -1545,13 +1548,13 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_defaultBPFFilter = bpf;
     });
 
-  g_lua.writeFunction("registerDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) {
+  luaCtx.writeFunction("registerDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) {
       if (dbpf) {
         g_dynBPFFilters.push_back(dbpf);
       }
     });
 
-  g_lua.writeFunction("unregisterDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) {
+  luaCtx.writeFunction("unregisterDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) {
       if (dbpf) {
         for (auto it = g_dynBPFFilters.begin(); it != g_dynBPFFilters.end(); it++) {
           if (*it == dbpf) {
@@ -1562,7 +1565,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("addBPFFilterDynBlocks", [](const std::unordered_map<ComboAddress,unsigned int, ComboAddress::addressOnlyHash, ComboAddress::addressOnlyEqual>& m, std::shared_ptr<DynBPFFilter> dynbpf, boost::optional<int> seconds, boost::optional<std::string> msg) {
+  luaCtx.writeFunction("addBPFFilterDynBlocks", [](const std::unordered_map<ComboAddress,unsigned int, ComboAddress::addressOnlyHash, ComboAddress::addressOnlyEqual>& m, std::shared_ptr<DynBPFFilter> dynbpf, boost::optional<int> seconds, boost::optional<std::string> msg) {
       setLuaSideEffect();
       struct timespec until, now;
       clock_gettime(CLOCK_MONOTONIC, &now);
@@ -1578,7 +1581,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 
 #endif /* HAVE_EBPF */
 
-  g_lua.writeFunction<std::unordered_map<string,uint64_t>()>("getStatisticsCounters", []() {
+  luaCtx.writeFunction<std::unordered_map<string,uint64_t>()>("getStatisticsCounters", []() {
       setLuaNoSideEffect();
       std::unordered_map<string,uint64_t> res;
       for(const auto& entry : g_stats.entries) {
@@ -1588,7 +1591,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       return res;
     });
 
-  g_lua.writeFunction("includeDirectory", [](const std::string& dirname) {
+  luaCtx.writeFunction("includeDirectory", [&luaCtx](const std::string& dirname) {
       if (g_configurationDone) {
         errlog("includeDirectory() cannot be used at runtime!");
         g_outputBuffer="includeDirectory() cannot be used at runtime!\n";
@@ -1652,13 +1655,13 @@ static void setupLuaConfig(bool client, bool configCheck)
           vinfolog("Read configuration from '%s'", *file);
         }
 
-        g_lua.executeCode(ifs);
+        luaCtx.executeCode(ifs);
       }
 
       g_included = false;
     });
 
-  g_lua.writeFunction("setAPIWritable", [](bool writable, boost::optional<std::string> apiConfigDir) {
+  luaCtx.writeFunction("setAPIWritable", [](bool writable, boost::optional<std::string> apiConfigDir) {
       setLuaSideEffect();
       g_apiReadWrite = writable;
       if (apiConfigDir) {
@@ -1672,17 +1675,17 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setServFailWhenNoServer", [](bool servfail) {
+  luaCtx.writeFunction("setServFailWhenNoServer", [](bool servfail) {
       setLuaSideEffect();
       g_servFailOnNoPolicy = servfail;
     });
 
-  g_lua.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) {
+  luaCtx.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) {
       setLuaSideEffect();
       g_roundrobinFailOnNoServer = fail;
     });
 
-  g_lua.writeFunction("setConsistentHashingBalancingFactor", [](double factor) {
+  luaCtx.writeFunction("setConsistentHashingBalancingFactor", [](double factor) {
       setLuaSideEffect();
       if (factor >= 1.0) {
         g_consistentHashBalancingFactor = factor;
@@ -1694,7 +1697,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setWeightedBalancingFactor", [](double factor) {
+  luaCtx.writeFunction("setWeightedBalancingFactor", [](double factor) {
       setLuaSideEffect();
       if (factor >= 1.0) {
         g_weightedBalancingFactor = factor;
@@ -1706,7 +1709,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       }
     });
 
-  g_lua.writeFunction("setRingBuffersSize", [](size_t capacity, boost::optional<size_t> numberOfShards) {
+  luaCtx.writeFunction("setRingBuffersSize", [](size_t capacity, boost::optional<size_t> numberOfShards) {
       setLuaSideEffect();
       if (g_configurationDone) {
         errlog("setRingBuffersSize() cannot be used at runtime!");
@@ -1716,17 +1719,17 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_rings.setCapacity(capacity, numberOfShards ? *numberOfShards : 1);
     });
 
-  g_lua.writeFunction("setRingBuffersLockRetries", [](size_t retries) {
+  luaCtx.writeFunction("setRingBuffersLockRetries", [](size_t retries) {
       setLuaSideEffect();
       g_rings.setNumberOfLockRetries(retries);
     });
 
-  g_lua.writeFunction("setWHashedPertubation", [](uint32_t pertub) {
+  luaCtx.writeFunction("setWHashedPertubation", [](uint32_t pertub) {
       setLuaSideEffect();
       g_hashperturb = pertub;
     });
 
-  g_lua.writeFunction("setTCPUseSinglePipe", [](bool flag) {
+  luaCtx.writeFunction("setTCPUseSinglePipe", [](bool flag) {
       if (g_configurationDone) {
         g_outputBuffer="setTCPUseSinglePipe() cannot be used at runtime!\n";
         return;
@@ -1735,7 +1738,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_useTCPSinglePipe = flag;
     });
 
-  g_lua.writeFunction("snmpAgent", [client,configCheck](bool enableTraps, boost::optional<std::string> masterSocket) {
+  luaCtx.writeFunction("snmpAgent", [client,configCheck](bool enableTraps, boost::optional<std::string> masterSocket) {
       if(client || configCheck)
         return;
 #ifdef HAVE_NET_SNMP
@@ -1760,72 +1763,92 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif /* HAVE_NET_SNMP */
     });
 
-  g_lua.writeFunction("sendCustomTrap", [](const std::string& str) {
+  luaCtx.writeFunction("sendCustomTrap", [](const std::string& str) {
       if (g_snmpAgent && g_snmpTrapsEnabled) {
         g_snmpAgent->sendCustomTrap(str);
       }
     });
 
-  g_lua.writeFunction("setServerPolicy", [](ServerPolicy policy) {
+  luaCtx.writeFunction("setServerPolicy", [](ServerPolicy policy) {
       setLuaSideEffect();
       g_policy.setState(policy);
     });
 
-  g_lua.writeFunction("setServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy) {
+  luaCtx.writeFunction("setServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy) {
       setLuaSideEffect();
       g_policy.setState(ServerPolicy{name, policy, true});
     });
 
-  g_lua.writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) {
+  luaCtx.writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) {
       setLuaSideEffect();
       auto pol = ServerPolicy(name, policy);
       g_policy.setState(std::move(pol));
     });
 
-  g_lua.writeFunction("showServerPolicy", []() {
+  luaCtx.writeFunction("setServerPolicyLuaFFIPerThread", [](string name, const std::string& policyCode) {
       setLuaSideEffect();
-      g_outputBuffer=g_policy.getLocal()->name+"\n";
+      auto pol = ServerPolicy(name, policyCode);
+      g_policy.setState(std::move(pol));
     });
 
-  g_lua.writeFunction("setPoolServerPolicy", [](ServerPolicy policy, string pool) {
+  luaCtx.writeFunction("showServerPolicy", []() {
+      setLuaSideEffect();
+      g_outputBuffer=g_policy.getLocal()->getName()+"\n";
+    });
+
+  luaCtx.writeFunction("setPoolServerPolicy", [](ServerPolicy policy, string pool) {
       setLuaSideEffect();
       auto localPools = g_pools.getCopy();
       setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(policy));
       g_pools.setState(localPools);
     });
 
-  g_lua.writeFunction("setPoolServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy, string pool) {
+  luaCtx.writeFunction("setPoolServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy, string pool) {
       setLuaSideEffect();
       auto localPools = g_pools.getCopy();
       setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policy, true}));
       g_pools.setState(localPools);
     });
 
-  g_lua.writeFunction("showPoolServerPolicy", [](string pool) {
+  luaCtx.writeFunction("setPoolServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy, string pool) {
+      setLuaSideEffect();
+      auto localPools = g_pools.getCopy();
+      setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policy}));
+      g_pools.setState(localPools);
+    });
+
+  luaCtx.writeFunction("setPoolServerPolicyLuaFFIPerThread", [](string name, const std::string& policyCode, string pool) {
+      setLuaSideEffect();
+      auto localPools = g_pools.getCopy();
+      setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policyCode}));
+      g_pools.setState(localPools);
+    });
+
+  luaCtx.writeFunction("showPoolServerPolicy", [](string pool) {
       setLuaSideEffect();
       auto localPools = g_pools.getCopy();
       auto poolObj = getPool(localPools, pool);
       if (poolObj->policy == nullptr) {
-        g_outputBuffer=g_policy.getLocal()->name+"\n";
+        g_outputBuffer=g_policy.getLocal()->getName()+"\n";
       } else {
-        g_outputBuffer=poolObj->policy->name+"\n";
+        g_outputBuffer=poolObj->policy->getName()+"\n";
       }
     });
 
-  g_lua.writeFunction("setTCPDownstreamCleanupInterval", [](uint16_t interval) {
+  luaCtx.writeFunction("setTCPDownstreamCleanupInterval", [](uint16_t interval) {
       setLuaSideEffect();
       g_downstreamTCPCleanupInterval = interval;
     });
 
-  g_lua.writeFunction("setConsoleConnectionsLogging", [](bool enabled) {
+  luaCtx.writeFunction("setConsoleConnectionsLogging", [](bool enabled) {
       g_logConsoleConnections = enabled;
     });
 
-  g_lua.writeFunction("setConsoleOutputMaxMsgSize", [](uint32_t size) {
+  luaCtx.writeFunction("setConsoleOutputMaxMsgSize", [](uint32_t size) {
       g_consoleOutputMsgMaxSize = size;
     });
 
-  g_lua.writeFunction("setUDPMultipleMessagesVectorSize", [](size_t vSize) {
+  luaCtx.writeFunction("setUDPMultipleMessagesVectorSize", [](size_t vSize) {
       if (g_configurationDone) {
         errlog("setUDPMultipleMessagesVectorSize() cannot be used at runtime!");
         g_outputBuffer="setUDPMultipleMessagesVectorSize() cannot be used at runtime!\n";
@@ -1840,11 +1863,11 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
     });
 
-  g_lua.writeFunction("setAddEDNSToSelfGeneratedResponses", [](bool add) {
+  luaCtx.writeFunction("setAddEDNSToSelfGeneratedResponses", [](bool add) {
       g_addEDNSToSelfGeneratedResponses = add;
   });
 
-  g_lua.writeFunction("setPayloadSizeOnSelfGeneratedAnswers", [](uint16_t payloadSize) {
+  luaCtx.writeFunction("setPayloadSizeOnSelfGeneratedAnswers", [](uint16_t payloadSize) {
       if (payloadSize < 512) {
         warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!");
         g_outputBuffer="setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!";
@@ -1858,7 +1881,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_PayloadSizeSelfGenAnswers = payloadSize;
   });
 
-  g_lua.writeFunction("setSecurityPollSuffix", [](const std::string& suffix) {
+  luaCtx.writeFunction("setSecurityPollSuffix", [](const std::string& suffix) {
       if (g_configurationDone) {
         g_outputBuffer="setSecurityPollSuffix() cannot be used at runtime!\n";
         return;
@@ -1867,7 +1890,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_secPollSuffix = suffix;
   });
 
-  g_lua.writeFunction("setSecurityPollInterval", [](time_t newInterval) {
+  luaCtx.writeFunction("setSecurityPollInterval", [](time_t newInterval) {
       if (newInterval <= 0) {
         warnlog("setSecurityPollInterval() should be > 0, skipping");
         g_outputBuffer="setSecurityPollInterval() should be > 0, skipping";
@@ -1876,7 +1899,7 @@ static void setupLuaConfig(bool client, bool configCheck)
       g_secPollInterval = newInterval;
   });
 
-  g_lua.writeFunction("setSyslogFacility", [](int facility) {
+  luaCtx.writeFunction("setSyslogFacility", [](int facility) {
     setLuaSideEffect();
     if (g_configurationDone) {
       g_outputBuffer="setSyslogFacility cannot be used at runtime!\n";
@@ -1885,7 +1908,7 @@ static void setupLuaConfig(bool client, bool configCheck)
     setSyslogFacility(facility);
   });
 
-  g_lua.writeFunction("addDOHLocal", [client](const std::string& addr, boost::optional<boost::variant<std::string, std::vector<std::pair<int,std::string>>>> certFiles, boost::optional<boost::variant<std::string, std::vector<std::pair<int,std::string>>>> keyFiles, boost::optional<boost::variant<std::string, vector<pair<int, std::string> > > > urls, boost::optional<localbind_t> vars) {
+  luaCtx.writeFunction("addDOHLocal", [client](const std::string& addr, boost::optional<boost::variant<std::string, std::vector<std::pair<int,std::string>>>> certFiles, boost::optional<boost::variant<std::string, std::vector<std::pair<int,std::string>>>> keyFiles, boost::optional<boost::variant<std::string, vector<pair<int, std::string> > > > urls, boost::optional<localbind_t> vars) {
     if (client) {
       return;
     }
@@ -1975,7 +1998,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
   });
 
-  g_lua.writeFunction("showDOHFrontends", []() {
+  luaCtx.writeFunction("showDOHFrontends", []() {
 #ifdef HAVE_DNS_OVER_HTTPS
         setLuaNoSideEffect();
         try {
@@ -1998,7 +2021,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
       });
 
-    g_lua.writeFunction("showDOHResponseCodes", []() {
+    luaCtx.writeFunction("showDOHResponseCodes", []() {
 #ifdef HAVE_DNS_OVER_HTTPS
         setLuaNoSideEffect();
         try {
@@ -2032,7 +2055,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
       });
 
-    g_lua.writeFunction("getDOHFrontend", [client](size_t index) {
+    luaCtx.writeFunction("getDOHFrontend", [client](size_t index) {
         std::shared_ptr<DOHFrontend> result = nullptr;
         if (client) {
           return result;
@@ -2058,30 +2081,30 @@ static void setupLuaConfig(bool client, bool configCheck)
         return result;
       });
 
-    g_lua.writeFunction("getDOHFrontendCount", []() {
+    luaCtx.writeFunction("getDOHFrontendCount", []() {
         setLuaNoSideEffect();
         return g_dohlocals.size();
       });
 
-    g_lua.registerFunction<void(std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<DOHFrontend> frontend) {
+    luaCtx.registerFunction<void(std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<DOHFrontend> frontend) {
         if (frontend != nullptr) {
           frontend->reloadCertificates();
         }
       });
 
-    g_lua.registerFunction<void(std::shared_ptr<DOHFrontend>::*)()>("rotateTicketsKey", [](std::shared_ptr<DOHFrontend> frontend) {
+    luaCtx.registerFunction<void(std::shared_ptr<DOHFrontend>::*)()>("rotateTicketsKey", [](std::shared_ptr<DOHFrontend> frontend) {
         if (frontend != nullptr) {
           frontend->rotateTicketsKey(time(nullptr));
         }
       });
 
-    g_lua.registerFunction<void(std::shared_ptr<DOHFrontend>::*)(const std::string&)>("loadTicketsKeys", [](std::shared_ptr<DOHFrontend> frontend, const std::string& file) {
+    luaCtx.registerFunction<void(std::shared_ptr<DOHFrontend>::*)(const std::string&)>("loadTicketsKeys", [](std::shared_ptr<DOHFrontend> frontend, const std::string& file) {
         if (frontend != nullptr) {
           frontend->loadTicketsKeys(file);
         }
       });
 
-    g_lua.registerFunction<void(std::shared_ptr<DOHFrontend>::*)(const std::map<int, std::shared_ptr<DOHResponseMapEntry>>&)>("setResponsesMap", [](std::shared_ptr<DOHFrontend> frontend, const std::map<int, std::shared_ptr<DOHResponseMapEntry>>& map) {
+    luaCtx.registerFunction<void(std::shared_ptr<DOHFrontend>::*)(const std::map<int, std::shared_ptr<DOHResponseMapEntry>>&)>("setResponsesMap", [](std::shared_ptr<DOHFrontend> frontend, const std::map<int, std::shared_ptr<DOHResponseMapEntry>>& map) {
         if (frontend != nullptr) {
           std::vector<std::shared_ptr<DOHResponseMapEntry>> newMap;
           newMap.reserve(map.size());
@@ -2094,7 +2117,7 @@ static void setupLuaConfig(bool client, bool configCheck)
         }
       });
 
-  g_lua.writeFunction("addTLSLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<localbind_t> vars) {
+  luaCtx.writeFunction("addTLSLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<localbind_t> vars) {
         if (client) {
           return;
         }
@@ -2156,7 +2179,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
       });
 
-    g_lua.writeFunction("showTLSContexts", []() {
+    luaCtx.writeFunction("showTLSContexts", []() {
 #ifdef HAVE_DNS_OVER_TLS
         setLuaNoSideEffect();
         try {
@@ -2180,7 +2203,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
       });
 
-    g_lua.writeFunction("getTLSContext", [](size_t index) {
+    luaCtx.writeFunction("getTLSContext", [](size_t index) {
         std::shared_ptr<TLSCtx> result = nullptr;
 #ifdef HAVE_DNS_OVER_TLS
         setLuaNoSideEffect();
@@ -2203,7 +2226,7 @@ static void setupLuaConfig(bool client, bool configCheck)
         return result;
       });
 
-    g_lua.writeFunction("getTLSFrontend", [](size_t index) {
+    luaCtx.writeFunction("getTLSFrontend", [](size_t index) {
         std::shared_ptr<TLSFrontend> result = nullptr;
 #ifdef HAVE_DNS_OVER_TLS
         setLuaNoSideEffect();
@@ -2226,24 +2249,24 @@ static void setupLuaConfig(bool client, bool configCheck)
         return result;
       });
 
-    g_lua.writeFunction("getTLSFrontendCount", []() {
+    luaCtx.writeFunction("getTLSFrontendCount", []() {
         setLuaNoSideEffect();
         return g_tlslocals.size();
       });
 
-    g_lua.registerFunction<void(std::shared_ptr<TLSCtx>::*)()>("rotateTicketsKey", [](std::shared_ptr<TLSCtx> ctx) {
+    luaCtx.registerFunction<void(std::shared_ptr<TLSCtx>::*)()>("rotateTicketsKey", [](std::shared_ptr<TLSCtx> ctx) {
         if (ctx != nullptr) {
           ctx->rotateTicketsKey(time(nullptr));
         }
       });
 
-    g_lua.registerFunction<void(std::shared_ptr<TLSCtx>::*)(const std::string&)>("loadTicketsKeys", [](std::shared_ptr<TLSCtx> ctx, const std::string& file) {
+    luaCtx.registerFunction<void(std::shared_ptr<TLSCtx>::*)(const std::string&)>("loadTicketsKeys", [](std::shared_ptr<TLSCtx> ctx, const std::string& file) {
         if (ctx != nullptr) {
           ctx->loadTicketsKeys(file);
         }
       });
 
-    g_lua.registerFunction<void(std::shared_ptr<TLSFrontend>::*)(boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)>("loadNewCertificatesAndKeys", [](std::shared_ptr<TLSFrontend>& frontend, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles) {
+    luaCtx.registerFunction<void(std::shared_ptr<TLSFrontend>::*)(boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)>("loadNewCertificatesAndKeys", [](std::shared_ptr<TLSFrontend>& frontend, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles) {
 #ifdef HAVE_DNS_OVER_TLS
         if (loadTLSCertificateAndKeys("loadNewCertificatesAndKeys", frontend->d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
           frontend->setupTLS();
@@ -2251,7 +2274,7 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif
       });
 
-    g_lua.writeFunction("reloadAllCertificates", []() {
+    luaCtx.writeFunction("reloadAllCertificates", []() {
         for (auto& frontend : g_frontends) {
           if (!frontend) {
             continue;
@@ -2279,10 +2302,10 @@ static void setupLuaConfig(bool client, bool configCheck)
         }
       });
 
-    g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
+    luaCtx.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
 
 #if defined(HAVE_LIBSSL) && defined(HAVE_OCSP_BASIC_SIGN)
-    g_lua.writeFunction("generateOCSPResponse", [client](const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin) {
+    luaCtx.writeFunction("generateOCSPResponse", [client](const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin) {
       if (client) {
         return;
       }
@@ -2292,24 +2315,26 @@ static void setupLuaConfig(bool client, bool configCheck)
 #endif /* HAVE_LIBSSL && HAVE_OCSP_BASIC_SIGN*/
 }
 
-vector<std::function<void(void)>> setupLua(bool client, bool configCheck, const std::string& config)
+vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config)
 {
-  g_launchWork= new vector<std::function<void(void)>>();
-
-  setupLuaActions();
-  setupLuaConfig(client, configCheck);
-  setupLuaBindings(client);
-  setupLuaBindingsDNSCrypt();
-  setupLuaBindingsDNSQuestion();
-  setupLuaBindingsKVS(client);
-  setupLuaBindingsPacketCache();
-  setupLuaBindingsProtoBuf(client, configCheck);
-  setupLuaInspection();
-  setupLuaRules();
-  setupLuaVars();
+  // this needs to exist only during the parsing of the configuration
+  // and cannot be captured by lambdas
+  g_launchWork = std::vector<std::function<void(void)>>();
+
+  setupLuaActions(luaCtx);
+  setupLuaConfig(luaCtx, client, configCheck);
+  setupLuaBindings(luaCtx, client);
+  setupLuaBindingsDNSCrypt(luaCtx);
+  setupLuaBindingsDNSQuestion(luaCtx);
+  setupLuaBindingsKVS(luaCtx, client);
+  setupLuaBindingsPacketCache(luaCtx);
+  setupLuaBindingsProtoBuf(luaCtx, client, configCheck);
+  setupLuaInspection(luaCtx);
+  setupLuaRules(luaCtx);
+  setupLuaVars(luaCtx);
 
 #ifdef LUAJIT_VERSION
-  g_lua.executeCode(getLuaFFIWrappers());
+  luaCtx.executeCode(getLuaFFIWrappers());
 #endif
 
   std::ifstream ifs(config);
@@ -2318,10 +2343,9 @@ vector<std::function<void(void)>> setupLua(bool client, bool configCheck, const
   else
     vinfolog("Read configuration from '%s'", config);
 
-  g_lua.executeCode(ifs);
+  luaCtx.executeCode(ifs);
 
   auto ret = *g_launchWork;
-  delete g_launchWork;
-  g_launchWork = nullptr;
+  g_launchWork = boost::none;
   return ret;
 }
index b25be8840fc628bc4b16f90c96075d18f0fd49ee..4818345e650b0ecbb6916e08b3c19d0da420e749 100644 (file)
@@ -94,14 +94,15 @@ void parseRuleParams(boost::optional<luaruleparams_t> params, boost::uuids::uuid
 
 typedef NetmaskTree<DynBlock> nmts_t;
 
-vector<std::function<void(void)>> setupLua(bool client, bool configCheck, const std::string& config);
-void setupLuaActions();
-void setupLuaBindings(bool client);
-void setupLuaBindingsDNSCrypt();
-void setupLuaBindingsDNSQuestion();
-void setupLuaBindingsKVS(bool client);
-void setupLuaBindingsPacketCache();
-void setupLuaBindingsProtoBuf(bool client, bool configCheck);
-void setupLuaRules();
-void setupLuaInspection();
-void setupLuaVars();
+vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config);
+void setupLuaActions(LuaContext& luaCtx);
+void setupLuaBindings(LuaContext& luaCtx, bool client);
+void setupLuaBindingsDNSCrypt(LuaContext& luaCtx);
+void setupLuaBindingsDNSQuestion(LuaContext& luaCtx);
+void setupLuaBindingsKVS(LuaContext& luaCtx, bool client);
+void setupLuaBindingsPacketCache(LuaContext& luaCtx);
+void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck);
+void setupLuaRules(LuaContext& luaCtx);
+void setupLuaInspection(LuaContext& luaCtx);
+void setupLuaVars(LuaContext& luaCtx);
+void setupLuaLoadBalancingContext(LuaContext& luaCtx);
index 854c996e342ef466d2faf56883fd7f755ddf43b7..71c669202f6d21ffe237008d9b5020220b4e59e2 100644 (file)
@@ -1405,10 +1405,10 @@ void tcpClientThread(int pipefd)
 /* spawn as many of these as required, they call Accept on a socket on which they will accept queries, and
    they will hand off to worker threads & spawn more of them if required
 */
-void tcpAcceptorThread(void* p)
+void tcpAcceptorThread(ClientState* cs)
 {
   setThreadName("dnsdist/tcpAcce");
-  ClientState* cs = (ClientState*) p;
+
   bool tcpClientCountIncremented = false;
   ComboAddress remote;
   remote.sin4.sin_family = cs->local.sin4.sin_family;
index 0c0389848d85f1a5c4089f556b00661e1740f39c..00da6abe1f89aff2ad5f48f3fb89cf3760b87d5b 100644 (file)
@@ -381,7 +381,7 @@ static void connectionThread(int sock, ComboAddress remote)
           { "packetcache-misses", 0},
           { "over-capacity-drops", 0 },
           { "too-old-drops", 0 },
-          { "server-policy", g_policy.getLocal()->name}
+          { "server-policy", g_policy.getLocal()->getName()}
         };
 
         for(const auto& e : g_stats.entries) {
@@ -1083,7 +1083,7 @@ static void connectionThread(int sock, ComboAddress remote)
         { "ecs-source-prefix-v6", (double)  g_ECSSourcePrefixV6 },
         { "fixup-case", g_fixupCase },
         { "max-outstanding", (double) g_maxOutstanding },
-        { "server-policy", g_policy.getLocal()->name },
+        { "server-policy", g_policy.getLocal()->getName() },
         { "stale-cache-entries-ttl", (double) g_staleCacheEntriesTTL },
         { "tcp-recv-timeout", (double) g_tcpRecvTimeout },
         { "tcp-send-timeout", (double) g_tcpSendTimeout },
index 4e62293526fc39ed09d1948fd926d1a84a05cd48..ac24be4c58718bc8f7040930161c108aa382f934 100644 (file)
@@ -1199,7 +1199,7 @@ ProcessQueryResult processQuery(DNSQuestion& dq, ClientState& cs, LocalHolders&
       policy = *(serverPool->policy);
     }
     const auto servers = serverPool->getServers();
-    selectedBackend = getSelectedBackendFromPolicy(policy, *servers, dq);
+    selectedBackend = policy.getSelectedBackend(*servers, dq);
 
     uint16_t cachedResponseSize = dq.size;
     uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL;
@@ -2168,7 +2168,7 @@ try
 
   g_policy.setState(leastOutstandingPol);
   if(g_cmdLine.beClient || !g_cmdLine.command.empty()) {
-    setupLua(true, false, g_cmdLine.config);
+    setupLua(g_lua, true, false, g_cmdLine.config);
     if (clientAddress != ComboAddress())
       g_serverControl = clientAddress;
     doClient(g_serverControl, g_cmdLine.command);
@@ -2189,22 +2189,22 @@ try
   g_consoleACL.setState(consoleACL);
 
   if (g_cmdLine.checkConfig) {
-    setupLua(false, true, g_cmdLine.config);
+    setupLua(g_lua, false, true, g_cmdLine.config);
     // No exception was thrown
     infolog("Configuration '%s' OK!", g_cmdLine.config);
     _exit(EXIT_SUCCESS);
   }
 
-  auto todo=setupLua(false, false, g_cmdLine.config);
+  auto todo = setupLua(g_lua, false, false, g_cmdLine.config);
 
   auto localPools = g_pools.getCopy();
   {
     bool precompute = false;
-    if (g_policy.getLocal()->name == "chashed") {
+    if (g_policy.getLocal()->getName() == "chashed") {
       precompute = true;
     } else {
       for (const auto& entry: localPools) {
-        if (entry.second->policy != nullptr && entry.second->policy->name == "chashed") {
+        if (entry.second->policy != nullptr && entry.second->policy->getName() == "chashed") {
           precompute = true;
           break ;
         }
index 9c6dcd16c077eff94e07c1738ba6ca58f0e16fd8..55c0868647b1cf02fe4db9c04d3fb584ca2d6f79 100644 (file)
@@ -1107,7 +1107,7 @@ struct dnsheader;
 
 vector<std::function<void(void)>> setupLua(bool client, const std::string& config);
 
-void tcpAcceptorThread(void* p);
+void tcpAcceptorThread(ClientState* p);
 #ifdef HAVE_DNS_OVER_HTTPS
 void dohThread(ClientState* cs);
 #endif /* HAVE_DNS_OVER_HTTPS */
index b0ca67ad4245007a82776c7e56936db21831415e..828af5ec5d1480f1e2bce57fbfce4036b0d4686e 100644 (file)
@@ -219,17 +219,23 @@ testrunner_SOURCES = \
        test-iputils_hh.cc \
        test-mplexer.cc \
        test-proxy_protocol_cc.cc \
+       bpf-filter.cc bpf-filter.hh \
        cachecleaner.hh \
        circular_buffer.hh \
        dnsdist.hh \
        dnsdist-backend.cc \
        dnsdist-cache.cc dnsdist-cache.hh \
        dnsdist-dynblocks.cc dnsdist-dynblocks.hh \
+       dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
        dnsdist-ecs.cc dnsdist-ecs.hh \
        dnsdist-kvs.cc dnsdist-kvs.hh \
        dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
+       dnsdist-lua-bindings.cc \
+       dnsdist-lua-bindings-dnsquestion.cc \
+       dnsdist-lua-bindings-kvs.cc \
        dnsdist-lua-ffi.cc dnsdist-lua-ffi.hh \
        dnsdist-lua-ffi-interface.h dnsdist-lua-ffi-interface.inc \
+       dnsdist-lua-vars.cc \
        dnsdist-rings.hh \
        dnsdist-xpf.cc dnsdist-xpf.hh \
        dnscrypt.cc dnscrypt.hh \
index b4268364f7d6864c2051123c152e9e73a7838de0..1d75ca0600a88d88d5921c9253e4b47dac212970 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "dnsdist.hh"
 #include "dnsdist-lbpolicies.hh"
+#include "dnsdist-lua.hh"
 #include "dnsdist-lua-ffi.hh"
 #include "dolog.hh"
 
@@ -251,9 +252,9 @@ void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<Serve
 {
   std::shared_ptr<ServerPool> pool = createPoolIfNotExists(pools, poolName);
   if (!poolName.empty()) {
-    vinfolog("Setting pool %s server selection policy to %s", poolName, policy->name);
+    vinfolog("Setting pool %s server selection policy to %s", poolName, policy->getName());
   } else {
-    vinfolog("Setting default pool server selection policy to %s", policy->name);
+    vinfolog("Setting default pool server selection policy to %s", policy->getName());
   }
   pool->policy = policy;
 }
@@ -294,28 +295,61 @@ std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poo
   return it->second;
 }
 
-std::shared_ptr<DownstreamState> getSelectedBackendFromPolicy(const ServerPolicy& policy, const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq)
+ServerPolicy::ServerPolicy(const std::string& name_, const std::string& code): d_name(name_), d_perThreadPolicyCode(code), d_isLua(true), d_isFFI(true), d_isPerThread(true)
+{
+  LuaContext tmpContext;
+  setupLuaLoadBalancingContext(tmpContext);
+  auto ret = tmpContext.executeCode<ServerPolicy::ffipolicyfunc_t>(code);
+}
+
+thread_local ServerPolicy::PerThreadState ServerPolicy::t_perThreadState;
+
+const ServerPolicy::ffipolicyfunc_t& ServerPolicy::getPerThreadPolicy() const
+{
+  auto& state = t_perThreadState;
+  if (!state.d_initialized) {
+    setupLuaLoadBalancingContext(state.d_luaContext);
+    state.d_initialized = true;
+  }
+
+  const auto& it = state.d_policies.find(d_name);
+  if (it != state.d_policies.end()) {
+    return it->second;
+  }
+
+  auto newPolicy = state.d_luaContext.executeCode<ServerPolicy::ffipolicyfunc_t>(d_perThreadPolicyCode);
+  state.d_policies[d_name] = std::move(newPolicy);
+  return state.d_policies.at(d_name);
+}
+
+std::shared_ptr<DownstreamState> ServerPolicy::getSelectedBackend(const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq) const
 {
   std::shared_ptr<DownstreamState> selectedBackend{nullptr};
 
-  if (policy.isLua) {
-    if (!policy.isFFI) {
+  if (d_isLua) {
+    if (!d_isFFI) {
       std::lock_guard<std::mutex> lock(g_luamutex);
-      selectedBackend = policy.policy(servers, &dq);
+      selectedBackend = d_policy(servers, &dq);
     }
     else {
       dnsdist_ffi_dnsquestion_t dnsq(&dq);
       dnsdist_ffi_servers_list_t serversList(servers);
       unsigned int selected = 0;
-      {
+
+      if (!d_isPerThread) {
         std::lock_guard<std::mutex> lock(g_luamutex);
-        selected = policy.ffipolicy(&serversList, &dnsq);
+        selected = d_ffipolicy(&serversList, &dnsq);
+      }
+      else {
+        const auto& policy = getPerThreadPolicy();
+        selected = policy(&serversList, &dnsq);
       }
+
       selectedBackend = servers.at(selected).second;
     }
   }
   else {
-    selectedBackend = policy.policy(servers, &dq);
+    selectedBackend = d_policy(servers, &dq);
   }
 
   return selectedBackend;
index 6a25dcf852994690e9ae5beff18b8922b81ac912..ff2a13ee1562f834eced2bd1ad61c8400826e0df 100644 (file)
 
 #include "dolog.hh"
 
-void setupLuaBindingsDNSCrypt()
+void setupLuaBindingsDNSCrypt(LuaContext& luaCtx)
 {
 #ifdef HAVE_DNSCRYPT
     /* DNSCryptContext bindings */
-    g_lua.registerFunction<std::string(DNSCryptContext::*)()>("getProviderName", [](const DNSCryptContext& ctx) { return ctx.getProviderName().toStringNoDot(); });
-    g_lua.registerFunction("markActive", &DNSCryptContext::markActive);
-    g_lua.registerFunction("markInactive", &DNSCryptContext::markInactive);
-    g_lua.registerFunction("removeInactiveCertificate", &DNSCryptContext::removeInactiveCertificate);
-    g_lua.registerFunction<void(std::shared_ptr<DNSCryptContext>::*)(const std::string& certFile, const std::string& keyFile, boost::optional<bool> active)>("loadNewCertificate", [](std::shared_ptr<DNSCryptContext> ctx, const std::string& certFile, const std::string& keyFile, boost::optional<bool> active) {
+    luaCtx.registerFunction<std::string(DNSCryptContext::*)()>("getProviderName", [](const DNSCryptContext& ctx) { return ctx.getProviderName().toStringNoDot(); });
+    luaCtx.registerFunction("markActive", &DNSCryptContext::markActive);
+    luaCtx.registerFunction("markInactive", &DNSCryptContext::markInactive);
+    luaCtx.registerFunction("removeInactiveCertificate", &DNSCryptContext::removeInactiveCertificate);
+    luaCtx.registerFunction<void(std::shared_ptr<DNSCryptContext>::*)(const std::string& certFile, const std::string& keyFile, boost::optional<bool> active)>("loadNewCertificate", [](std::shared_ptr<DNSCryptContext> ctx, const std::string& certFile, const std::string& keyFile, boost::optional<bool> active) {
 
       if (ctx == nullptr) {
         throw std::runtime_error("DNSCryptContext::loadNewCertificate() called on a nil value");
@@ -42,7 +42,7 @@ void setupLuaBindingsDNSCrypt()
 
       ctx->loadNewCertificate(certFile, keyFile, active ? *active : true);
     });
-    g_lua.registerFunction<void(std::shared_ptr<DNSCryptContext>::*)(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, boost::optional<bool> active)>("addNewCertificate", [](std::shared_ptr<DNSCryptContext> ctx, const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, boost::optional<bool> active) {
+    luaCtx.registerFunction<void(std::shared_ptr<DNSCryptContext>::*)(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, boost::optional<bool> active)>("addNewCertificate", [](std::shared_ptr<DNSCryptContext> ctx, const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, boost::optional<bool> active) {
 
       if (ctx == nullptr) {
         throw std::runtime_error("DNSCryptContext::addNewCertificate() called on a nil value");
@@ -50,7 +50,7 @@ void setupLuaBindingsDNSCrypt()
 
       ctx->addNewCertificate(newCert, newKey, active ? *active : true);
     });
-    g_lua.registerFunction<std::map<int, std::shared_ptr<DNSCryptCertificatePair>>(std::shared_ptr<DNSCryptContext>::*)()>("getCertificatePairs", [](std::shared_ptr<DNSCryptContext> ctx) {
+    luaCtx.registerFunction<std::map<int, std::shared_ptr<DNSCryptCertificatePair>>(std::shared_ptr<DNSCryptContext>::*)()>("getCertificatePairs", [](std::shared_ptr<DNSCryptContext> ctx) {
       std::map<int, std::shared_ptr<DNSCryptCertificatePair>> result;
 
       if (ctx != nullptr) {
@@ -63,7 +63,7 @@ void setupLuaBindingsDNSCrypt()
       return result;
     });
 
-    g_lua.registerFunction<std::shared_ptr<DNSCryptCertificatePair>(std::shared_ptr<DNSCryptContext>::*)(size_t idx)>("getCertificatePair", [](std::shared_ptr<DNSCryptContext> ctx, size_t idx) {
+    luaCtx.registerFunction<std::shared_ptr<DNSCryptCertificatePair>(std::shared_ptr<DNSCryptContext>::*)(size_t idx)>("getCertificatePair", [](std::shared_ptr<DNSCryptContext> ctx, size_t idx) {
 
       if (ctx == nullptr) {
         throw std::runtime_error("DNSCryptContext::getCertificatePair() called on a nil value");
@@ -78,7 +78,7 @@ void setupLuaBindingsDNSCrypt()
       return result;
     });
 
-    g_lua.registerFunction<const DNSCryptCert(std::shared_ptr<DNSCryptContext>::*)(size_t idx)>("getCertificate", [](std::shared_ptr<DNSCryptContext> ctx, size_t idx) {
+    luaCtx.registerFunction<const DNSCryptCert(std::shared_ptr<DNSCryptContext>::*)(size_t idx)>("getCertificate", [](std::shared_ptr<DNSCryptContext> ctx, size_t idx) {
 
       if (ctx == nullptr) {
         throw std::runtime_error("DNSCryptContext::getCertificate() called on a nil value");
@@ -92,7 +92,7 @@ void setupLuaBindingsDNSCrypt()
       throw std::runtime_error("This DNSCrypt context has no certificate at index " + std::to_string(idx));
     });
 
-    g_lua.registerFunction<std::string(std::shared_ptr<DNSCryptContext>::*)()>("printCertificates", [](const std::shared_ptr<DNSCryptContext> ctx) {
+    luaCtx.registerFunction<std::string(std::shared_ptr<DNSCryptContext>::*)()>("printCertificates", [](const std::shared_ptr<DNSCryptContext> ctx) {
       ostringstream ret;
 
       if (ctx != nullptr) {
@@ -111,7 +111,7 @@ void setupLuaBindingsDNSCrypt()
       return ret.str();
     });
 
-    g_lua.registerFunction<void(DNSCryptContext::*)(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version)>("generateAndLoadInMemoryCertificate", [](DNSCryptContext& ctx, const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
+    luaCtx.registerFunction<void(DNSCryptContext::*)(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version)>("generateAndLoadInMemoryCertificate", [](DNSCryptContext& ctx, const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
         DNSCryptPrivateKey privateKey;
         DNSCryptCert cert;
 
@@ -127,13 +127,13 @@ void setupLuaBindingsDNSCrypt()
     });
 
     /* DNSCryptCertificatePair */
-    g_lua.registerFunction<const DNSCryptCert(std::shared_ptr<DNSCryptCertificatePair>::*)()>("getCertificate", [](const std::shared_ptr<DNSCryptCertificatePair> pair) {
+    luaCtx.registerFunction<const DNSCryptCert(std::shared_ptr<DNSCryptCertificatePair>::*)()>("getCertificate", [](const std::shared_ptr<DNSCryptCertificatePair> pair) {
       if (pair == nullptr) {
         throw std::runtime_error("DNSCryptCertificatePair::getCertificate() called on a nil value");
       }
       return pair->cert;
     });
-    g_lua.registerFunction<bool(std::shared_ptr<DNSCryptCertificatePair>::*)()>("isActive", [](const std::shared_ptr<DNSCryptCertificatePair> pair) {
+    luaCtx.registerFunction<bool(std::shared_ptr<DNSCryptCertificatePair>::*)()>("isActive", [](const std::shared_ptr<DNSCryptCertificatePair> pair) {
       if (pair == nullptr) {
         throw std::runtime_error("DNSCryptCertificatePair::isActive() called on a nil value");
       }
@@ -141,14 +141,14 @@ void setupLuaBindingsDNSCrypt()
     });
 
     /* DNSCryptCert */
-    g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getMagic", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.magic), sizeof(cert.magic)); });
-    g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getEsVersion", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.esVersion), sizeof(cert.esVersion)); });
-    g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getProtocolMinorVersion", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.protocolMinorVersion), sizeof(cert.protocolMinorVersion)); });
-    g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getSignature", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signature), sizeof(cert.signature)); });
-    g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getResolverPublicKey", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signedData.resolverPK), sizeof(cert.signedData.resolverPK)); });
-    g_lua.registerFunction<std::string(DNSCryptCert::*)()>("getClientMagic", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signedData.clientMagic), sizeof(cert.signedData.clientMagic)); });
-    g_lua.registerFunction<uint32_t(DNSCryptCert::*)()>("getSerial", [](const DNSCryptCert& cert) { return cert.getSerial(); });
-    g_lua.registerFunction<uint32_t(DNSCryptCert::*)()>("getTSStart", [](const DNSCryptCert& cert) { return ntohl(cert.getTSStart()); });
-    g_lua.registerFunction<uint32_t(DNSCryptCert::*)()>("getTSEnd", [](const DNSCryptCert& cert) { return ntohl(cert.getTSEnd()); });
+    luaCtx.registerFunction<std::string(DNSCryptCert::*)()>("getMagic", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.magic), sizeof(cert.magic)); });
+    luaCtx.registerFunction<std::string(DNSCryptCert::*)()>("getEsVersion", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.esVersion), sizeof(cert.esVersion)); });
+    luaCtx.registerFunction<std::string(DNSCryptCert::*)()>("getProtocolMinorVersion", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.protocolMinorVersion), sizeof(cert.protocolMinorVersion)); });
+    luaCtx.registerFunction<std::string(DNSCryptCert::*)()>("getSignature", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signature), sizeof(cert.signature)); });
+    luaCtx.registerFunction<std::string(DNSCryptCert::*)()>("getResolverPublicKey", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signedData.resolverPK), sizeof(cert.signedData.resolverPK)); });
+    luaCtx.registerFunction<std::string(DNSCryptCert::*)()>("getClientMagic", [](const DNSCryptCert& cert) { return std::string(reinterpret_cast<const char*>(cert.signedData.clientMagic), sizeof(cert.signedData.clientMagic)); });
+    luaCtx.registerFunction<uint32_t(DNSCryptCert::*)()>("getSerial", [](const DNSCryptCert& cert) { return cert.getSerial(); });
+    luaCtx.registerFunction<uint32_t(DNSCryptCert::*)()>("getTSStart", [](const DNSCryptCert& cert) { return ntohl(cert.getTSStart()); });
+    luaCtx.registerFunction<uint32_t(DNSCryptCert::*)()>("getTSEnd", [](const DNSCryptCert& cert) { return ntohl(cert.getTSEnd()); });
 #endif
 }
index 3bc185056ed0809afc5fb6210c9c2168b50361ca..bf26914bc7e4f3a83a75ab595152447c49573bd2 100644 (file)
 #include "dnsdist-kvs.hh"
 #include "dnsdist-lua.hh"
 
-void setupLuaBindingsKVS(bool client)
+void setupLuaBindingsKVS(LuaContext& luaCtx, bool client)
 {
   /* Key Value Store objects */
-  g_lua.writeFunction("KeyValueLookupKeySourceIP", [](boost::optional<uint8_t> v4Mask, boost::optional<uint8_t> v6Mask) {
+  luaCtx.writeFunction("KeyValueLookupKeySourceIP", [](boost::optional<uint8_t> v4Mask, boost::optional<uint8_t> v6Mask) {
     return std::shared_ptr<KeyValueLookupKey>(new KeyValueLookupKeySourceIP(v4Mask.get_value_or(32), v6Mask.get_value_or(128)));
   });
-  g_lua.writeFunction("KeyValueLookupKeyQName", [](boost::optional<bool> wireFormat) {
+  luaCtx.writeFunction("KeyValueLookupKeyQName", [](boost::optional<bool> wireFormat) {
     return std::shared_ptr<KeyValueLookupKey>(new KeyValueLookupKeyQName(wireFormat ? *wireFormat : true));
   });
-  g_lua.writeFunction("KeyValueLookupKeySuffix", [](boost::optional<size_t> minLabels, boost::optional<bool> wireFormat) {
+  luaCtx.writeFunction("KeyValueLookupKeySuffix", [](boost::optional<size_t> minLabels, boost::optional<bool> wireFormat) {
     return std::shared_ptr<KeyValueLookupKey>(new KeyValueLookupKeySuffix(minLabels ? *minLabels : 0, wireFormat ? *wireFormat : true));
   });
-  g_lua.writeFunction("KeyValueLookupKeyTag", [](const std::string& tag) {
+  luaCtx.writeFunction("KeyValueLookupKeyTag", [](const std::string& tag) {
     return std::shared_ptr<KeyValueLookupKey>(new KeyValueLookupKeyTag(tag));
   });
 
 #ifdef HAVE_LMDB
-  g_lua.writeFunction("newLMDBKVStore", [client](const std::string& fname, const std::string& dbName) {
+  luaCtx.writeFunction("newLMDBKVStore", [client](const std::string& fname, const std::string& dbName) {
     if (client) {
       return std::shared_ptr<KeyValueStore>(nullptr);
     }
@@ -49,7 +49,7 @@ void setupLuaBindingsKVS(bool client)
 #endif /* HAVE_LMDB */
 
 #ifdef HAVE_CDB
-  g_lua.writeFunction("newCDBKVStore", [client](const std::string& fname, time_t refreshDelay) {
+  luaCtx.writeFunction("newCDBKVStore", [client](const std::string& fname, time_t refreshDelay) {
     if (client) {
       return std::shared_ptr<KeyValueStore>(nullptr);
     }
@@ -57,7 +57,7 @@ void setupLuaBindingsKVS(bool client)
   });
 #endif /* HAVE_CDB */
 
-  g_lua.registerFunction<std::string(std::shared_ptr<KeyValueStore>::*)(const boost::variant<ComboAddress, DNSName, std::string>, boost::optional<bool> wireFormat)>("lookup", [](std::shared_ptr<KeyValueStore>& kvs, const boost::variant<ComboAddress, DNSName, std::string> keyVar, boost::optional<bool> wireFormat) {
+  luaCtx.registerFunction<std::string(std::shared_ptr<KeyValueStore>::*)(const boost::variant<ComboAddress, DNSName, std::string>, boost::optional<bool> wireFormat)>("lookup", [](std::shared_ptr<KeyValueStore>& kvs, const boost::variant<ComboAddress, DNSName, std::string> keyVar, boost::optional<bool> wireFormat) {
     std::string result;
     if (!kvs) {
       return result;
@@ -89,7 +89,7 @@ void setupLuaBindingsKVS(bool client)
     return result;
   });
 
-  g_lua.registerFunction<std::string(std::shared_ptr<KeyValueStore>::*)(const DNSName&, boost::optional<size_t> minLabels, boost::optional<bool> wireFormat)>("lookupSuffix", [](std::shared_ptr<KeyValueStore>& kvs, const DNSName& dn, boost::optional<size_t> minLabels, boost::optional<bool> wireFormat) {
+  luaCtx.registerFunction<std::string(std::shared_ptr<KeyValueStore>::*)(const DNSName&, boost::optional<size_t> minLabels, boost::optional<bool> wireFormat)>("lookupSuffix", [](std::shared_ptr<KeyValueStore>& kvs, const DNSName& dn, boost::optional<size_t> minLabels, boost::optional<bool> wireFormat) {
     std::string result;
     if (!kvs) {
       return result;
@@ -105,7 +105,7 @@ void setupLuaBindingsKVS(bool client)
     return result;
   });
 
-  g_lua.registerFunction<bool(std::shared_ptr<KeyValueStore>::*)()>("reload", [](std::shared_ptr<KeyValueStore>& kvs) {
+  luaCtx.registerFunction<bool(std::shared_ptr<KeyValueStore>::*)()>("reload", [](std::shared_ptr<KeyValueStore>& kvs) {
     if (!kvs) {
       return false;
     }
index b6d687a759611ef6e5eb82c4f0a59e3d5e44407d..c3aed7465fbb4f5c0334f0940c305bfcda162478 100644 (file)
 #include "dnsdist.hh"
 #include "dnsdist-lua.hh"
 
-void setupLuaBindingsPacketCache()
+void setupLuaBindingsPacketCache(LuaContext& luaCtx)
 {
   /* PacketCache */
-  g_lua.writeFunction("newPacketCache", [](size_t maxEntries, boost::optional<std::unordered_map<std::string, boost::variant<bool, size_t>>> vars) {
+  luaCtx.writeFunction("newPacketCache", [](size_t maxEntries, boost::optional<std::unordered_map<std::string, boost::variant<bool, size_t>>> vars) {
 
       bool keepStaleData = false;
       size_t maxTTL = 86400;
@@ -92,31 +92,31 @@ void setupLuaBindingsPacketCache()
 
       return res;
     });
-  g_lua.registerFunction<std::string(std::shared_ptr<DNSDistPacketCache>::*)()>("toString", [](const std::shared_ptr<DNSDistPacketCache>& cache) {
+  luaCtx.registerFunction<std::string(std::shared_ptr<DNSDistPacketCache>::*)()>("toString", [](const std::shared_ptr<DNSDistPacketCache>& cache) {
       if (cache) {
         return cache->toString();
       }
       return std::string();
     });
-  g_lua.registerFunction<bool(std::shared_ptr<DNSDistPacketCache>::*)()>("isFull", [](const std::shared_ptr<DNSDistPacketCache>& cache) {
+  luaCtx.registerFunction<bool(std::shared_ptr<DNSDistPacketCache>::*)()>("isFull", [](const std::shared_ptr<DNSDistPacketCache>& cache) {
       if (cache) {
         return cache->isFull();
       }
       return false;
     });
-  g_lua.registerFunction<size_t(std::shared_ptr<DNSDistPacketCache>::*)(size_t)>("purgeExpired", [](std::shared_ptr<DNSDistPacketCache>& cache, size_t upTo) {
+  luaCtx.registerFunction<size_t(std::shared_ptr<DNSDistPacketCache>::*)(size_t)>("purgeExpired", [](std::shared_ptr<DNSDistPacketCache>& cache, size_t upTo) {
       if (cache) {
         return cache->purgeExpired(upTo);
       }
       return static_cast<size_t>(0);
     });
-  g_lua.registerFunction<size_t(std::shared_ptr<DNSDistPacketCache>::*)(size_t)>("expunge", [](std::shared_ptr<DNSDistPacketCache>& cache, size_t upTo) {
+  luaCtx.registerFunction<size_t(std::shared_ptr<DNSDistPacketCache>::*)(size_t)>("expunge", [](std::shared_ptr<DNSDistPacketCache>& cache, size_t upTo) {
       if (cache) {
         return cache->expunge(upTo);
       }
       return static_cast<size_t>(0);
     });
-  g_lua.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)(const boost::variant<DNSName, string>& dname, boost::optional<uint16_t> qtype, boost::optional<bool> suffixMatch)>("expungeByName", [](
+  luaCtx.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)(const boost::variant<DNSName, string>& dname, boost::optional<uint16_t> qtype, boost::optional<bool> suffixMatch)>("expungeByName", [](
               std::shared_ptr<DNSDistPacketCache>& cache,
               const boost::variant<DNSName, string>& dname,
               boost::optional<uint16_t> qtype,
@@ -132,7 +132,7 @@ void setupLuaBindingsPacketCache()
                   g_outputBuffer="Expunged " + std::to_string(cache->expungeByName(qname, qtype ? *qtype : QType(QType::ANY).getCode(), suffixMatch ? *suffixMatch : false)) + " records\n";
                 }
     });
-  g_lua.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)()>("printStats", [](const std::shared_ptr<DNSDistPacketCache>& cache) {
+  luaCtx.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)()>("printStats", [](const std::shared_ptr<DNSDistPacketCache>& cache) {
       if (cache) {
         g_outputBuffer="Entries: " + std::to_string(cache->getEntriesCount()) + "/" + std::to_string(cache->getMaxEntries()) + "\n";
         g_outputBuffer+="Hits: " + std::to_string(cache->getHits()) + "\n";
@@ -144,7 +144,7 @@ void setupLuaBindingsPacketCache()
         g_outputBuffer+="TTL Too Shorts: " + std::to_string(cache->getTTLTooShorts()) + "\n";
       }
     });
-  g_lua.registerFunction<std::unordered_map<std::string, uint64_t>(std::shared_ptr<DNSDistPacketCache>::*)()>("getStats", [](const std::shared_ptr<DNSDistPacketCache>& cache) {
+  luaCtx.registerFunction<std::unordered_map<std::string, uint64_t>(std::shared_ptr<DNSDistPacketCache>::*)()>("getStats", [](const std::shared_ptr<DNSDistPacketCache>& cache) {
       std::unordered_map<std::string, uint64_t> stats;
       if (cache) {
         stats["entries"] = cache->getEntriesCount();
@@ -159,7 +159,7 @@ void setupLuaBindingsPacketCache()
       }
       return stats;
     });
-  g_lua.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)(const std::string& fname)>("dump", [](const std::shared_ptr<DNSDistPacketCache>& cache, const std::string& fname) {
+  luaCtx.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)(const std::string& fname)>("dump", [](const std::shared_ptr<DNSDistPacketCache>& cache, const std::string& fname) {
       if (cache) {
 
         int fd = open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
index 1f96d7168ae55437866721c695bf662ad9f12754..c8aade0affe053fa268074b5b2939215fb78b18c 100644 (file)
@@ -49,88 +49,88 @@ static void parseFSTRMOptions(const boost::optional<std::unordered_map<std::stri
 }
 #endif /* HAVE_FSTRM */
 
-void setupLuaBindingsProtoBuf(bool client, bool configCheck)
+void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck)
 {
 #ifdef HAVE_LIBCRYPTO
-  g_lua.registerFunction<ComboAddress(ComboAddress::*)(const std::string& key)>("ipencrypt", [](const ComboAddress& ca, const std::string& key) {
+  luaCtx.registerFunction<ComboAddress(ComboAddress::*)(const std::string& key)>("ipencrypt", [](const ComboAddress& ca, const std::string& key) {
       return encryptCA(ca, key);
     });
-  g_lua.registerFunction<ComboAddress(ComboAddress::*)(const std::string& key)>("ipdecrypt", [](const ComboAddress& ca, const std::string& key) {
+  luaCtx.registerFunction<ComboAddress(ComboAddress::*)(const std::string& key)>("ipdecrypt", [](const ComboAddress& ca, const std::string& key) {
       return decryptCA(ca, key);
     });
 
-  g_lua.writeFunction("makeIPCipherKey", [](const std::string& password) {
+  luaCtx.writeFunction("makeIPCipherKey", [](const std::string& password) {
       return makeIPCipherKey(password);
     });
 #endif /* HAVE_LIBCRYPTO */
 
   /* ProtobufMessage */
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(std::string)>("setTag", [](DNSDistProtoBufMessage& message, const std::string& strValue) {
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(std::string)>("setTag", [](DNSDistProtoBufMessage& message, const std::string& strValue) {
       message.addTag(strValue);
     });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(vector<pair<int, string>>)>("setTagArray", [](DNSDistProtoBufMessage& message, const vector<pair<int, string>>&tags) {
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(vector<pair<int, string>>)>("setTagArray", [](DNSDistProtoBufMessage& message, const vector<pair<int, string>>&tags) {
       for (const auto& tag : tags) {
         message.addTag(tag.second);
       }
     });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(boost::optional <time_t> sec, boost::optional <uint32_t> uSec)>("setProtobufResponseType",
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(boost::optional <time_t> sec, boost::optional <uint32_t> uSec)>("setProtobufResponseType",
                                         [](DNSDistProtoBufMessage& message, boost::optional <time_t> sec, boost::optional <uint32_t> uSec) {
       message.setType(DNSProtoBufMessage::Response);
       message.setQueryTime(sec?*sec:0, uSec?*uSec:0);
     });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string& strQueryName, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob)>("addResponseRR", [](DNSDistProtoBufMessage& message,
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string& strQueryName, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob)>("addResponseRR", [](DNSDistProtoBufMessage& message,
                                                             const std::string& strQueryName, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& strBlob) {
       message.addRR(DNSName(strQueryName), uType, uClass, uTTL, strBlob);
     });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const Netmask&)>("setEDNSSubnet", [](DNSDistProtoBufMessage& message, const Netmask& subnet) { message.setEDNSSubnet(subnet); });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const DNSName&, uint16_t, uint16_t)>("setQuestion", [](DNSDistProtoBufMessage& message, const DNSName& qname, uint16_t qtype, uint16_t qclass) { message.setQuestion(qname, qtype, qclass); });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(size_t)>("setBytes", [](DNSDistProtoBufMessage& message, size_t bytes) { message.setBytes(bytes); });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setTime(sec, usec); });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setQueryTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setQueryTime(sec, usec); });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(uint8_t)>("setResponseCode", [](DNSDistProtoBufMessage& message, uint8_t rcode) { message.setResponseCode(rcode); });
-  g_lua.registerFunction<std::string(DNSDistProtoBufMessage::*)()>("toDebugString", [](const DNSDistProtoBufMessage& message) { return message.toDebugString(); });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&, boost::optional<uint16_t>)>("setRequestor", [](DNSDistProtoBufMessage& message, const ComboAddress& addr, boost::optional<uint16_t> port) {
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const Netmask&)>("setEDNSSubnet", [](DNSDistProtoBufMessage& message, const Netmask& subnet) { message.setEDNSSubnet(subnet); });
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const DNSName&, uint16_t, uint16_t)>("setQuestion", [](DNSDistProtoBufMessage& message, const DNSName& qname, uint16_t qtype, uint16_t qclass) { message.setQuestion(qname, qtype, qclass); });
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(size_t)>("setBytes", [](DNSDistProtoBufMessage& message, size_t bytes) { message.setBytes(bytes); });
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setTime(sec, usec); });
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(time_t, uint32_t)>("setQueryTime", [](DNSDistProtoBufMessage& message, time_t sec, uint32_t usec) { message.setQueryTime(sec, usec); });
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(uint8_t)>("setResponseCode", [](DNSDistProtoBufMessage& message, uint8_t rcode) { message.setResponseCode(rcode); });
+  luaCtx.registerFunction<std::string(DNSDistProtoBufMessage::*)()>("toDebugString", [](const DNSDistProtoBufMessage& message) { return message.toDebugString(); });
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&, boost::optional<uint16_t>)>("setRequestor", [](DNSDistProtoBufMessage& message, const ComboAddress& addr, boost::optional<uint16_t> port) {
       message.setRequestor(addr);
       if (port) {
         message.setRequestorPort(*port);
       }
     });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&, boost::optional<uint16_t>)>("setRequestorFromString", [](DNSDistProtoBufMessage& message, const std::string& str, boost::optional<uint16_t> port) {
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&, boost::optional<uint16_t>)>("setRequestorFromString", [](DNSDistProtoBufMessage& message, const std::string& str, boost::optional<uint16_t> port) {
       message.setRequestor(str);
       if (port) {
         message.setRequestorPort(*port);
       }
     });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&, boost::optional<uint16_t>)>("setResponder", [](DNSDistProtoBufMessage& message, const ComboAddress& addr, boost::optional<uint16_t> port) {
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const ComboAddress&, boost::optional<uint16_t>)>("setResponder", [](DNSDistProtoBufMessage& message, const ComboAddress& addr, boost::optional<uint16_t> port) {
       message.setResponder(addr);
       if (port) {
         message.setResponderPort(*port);
       }
     });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&, boost::optional<uint16_t>)>("setResponderFromString", [](DNSDistProtoBufMessage& message, const std::string& str, boost::optional<uint16_t> port) {
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&, boost::optional<uint16_t>)>("setResponderFromString", [](DNSDistProtoBufMessage& message, const std::string& str, boost::optional<uint16_t> port) {
       message.setResponder(str);
       if (port) {
         message.setResponderPort(*port);
       }
     });
-  g_lua.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&)>("setServerIdentity", [](DNSDistProtoBufMessage& message, const std::string& str) {
+  luaCtx.registerFunction<void(DNSDistProtoBufMessage::*)(const std::string&)>("setServerIdentity", [](DNSDistProtoBufMessage& message, const std::string& str) {
       message.setServerIdentity(str);
     });
 
-  g_lua.registerFunction<std::string(DnstapMessage::*)()>("toDebugString", [](const DnstapMessage& message) { return message.toDebugString(); });
-  g_lua.registerFunction<void(DnstapMessage::*)(const std::string&)>("setExtra", [](DnstapMessage& message, const std::string& str) {
+  luaCtx.registerFunction<std::string(DnstapMessage::*)()>("toDebugString", [](const DnstapMessage& message) { return message.toDebugString(); });
+  luaCtx.registerFunction<void(DnstapMessage::*)(const std::string&)>("setExtra", [](DnstapMessage& message, const std::string& str) {
       message.setExtra(str);
     });
 
   /* RemoteLogger */
-  g_lua.writeFunction("newRemoteLogger", [client,configCheck](const std::string& remote, boost::optional<uint16_t> timeout, boost::optional<uint64_t> maxQueuedEntries, boost::optional<uint8_t> reconnectWaitTime) {
+  luaCtx.writeFunction("newRemoteLogger", [client,configCheck](const std::string& remote, boost::optional<uint16_t> timeout, boost::optional<uint64_t> maxQueuedEntries, boost::optional<uint8_t> reconnectWaitTime) {
       if (client || configCheck) {
         return std::shared_ptr<RemoteLoggerInterface>(nullptr);
       }
       return std::shared_ptr<RemoteLoggerInterface>(new RemoteLogger(ComboAddress(remote), timeout ? *timeout : 2, maxQueuedEntries ? (*maxQueuedEntries*100) : 10000, reconnectWaitTime ? *reconnectWaitTime : 1, client));
     });
 
-  g_lua.writeFunction("newFrameStreamUnixLogger", [client,configCheck](const std::string& address, boost::optional<std::unordered_map<std::string, unsigned int>> params) {
+  luaCtx.writeFunction("newFrameStreamUnixLogger", [client,configCheck](const std::string& address, boost::optional<std::unordered_map<std::string, unsigned int>> params) {
 #ifdef HAVE_FSTRM
       if (client || configCheck) {
         return std::shared_ptr<RemoteLoggerInterface>(nullptr);
@@ -144,7 +144,7 @@ void setupLuaBindingsProtoBuf(bool client, bool configCheck)
 #endif /* HAVE_FSTRM */
     });
 
-  g_lua.writeFunction("newFrameStreamTcpLogger", [client,configCheck](const std::string& address, boost::optional<std::unordered_map<std::string, unsigned int>> params) {
+  luaCtx.writeFunction("newFrameStreamTcpLogger", [client,configCheck](const std::string& address, boost::optional<std::unordered_map<std::string, unsigned int>> params) {
 #if defined(HAVE_FSTRM) && defined(HAVE_FSTRM_TCP_WRITER_INIT)
       if (client || configCheck) {
         return std::shared_ptr<RemoteLoggerInterface>(nullptr);
@@ -158,7 +158,7 @@ void setupLuaBindingsProtoBuf(bool client, bool configCheck)
 #endif /* HAVE_FSTRM */
     });
 
-  g_lua.registerFunction<std::string(std::shared_ptr<RemoteLoggerInterface>::*)()>("toString", [](const std::shared_ptr<RemoteLoggerInterface>& logger) {
+  luaCtx.registerFunction<std::string(std::shared_ptr<RemoteLoggerInterface>::*)()>("toString", [](const std::shared_ptr<RemoteLoggerInterface>& logger) {
       if (logger) {
         return logger->toString();
       }
index a40a4ab196ad5dd1fd9b842b55c34cfa2c63ec08..1cc6cf2cbcfd83b86e08e722a889c47679ffbf48 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include "dnsdist-lua-ffi.hh"
+#include "dnsdist-lua.hh"
 #include "dnsdist-ecs.hh"
 
 uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq)
@@ -504,3 +505,15 @@ const std::string& getLuaFFIWrappers()
 )FFICodeContent";
   return code;
 }
+
+void setupLuaLoadBalancingContext(LuaContext& luaCtx)
+{
+  setupLuaBindings(luaCtx, true);
+  setupLuaBindingsDNSQuestion(luaCtx);
+  setupLuaBindingsKVS(luaCtx, true);
+  setupLuaVars(luaCtx);
+
+#ifdef LUAJIT_VERSION
+  luaCtx.executeCode(getLuaFFIWrappers());
+#endif
+}
index 46f846c68ca31f044b9d0df1e6470314d98a64b4..d50becb7f7320649906489248b47050040fd5023 100644 (file)
@@ -31,7 +31,7 @@ Large installations are advised to increase the default value at the cost of a s
 Most of the query processing is done in C++ for maximum performance, but some operations are executed in Lua for maximum flexibility:
 
  * Rules added by :func:`addLuaAction`
- * Server selection policies defined via :func:`setServerPolicyLua`, :func:`setServerPolicyLuaFFI` or :func:`newServerPolicy`
+ * Server selection policies defined via :func:`setServerPolicyLua`, :func:`setServerPolicyLuaFFI`, :func:`setServerPolicyLuaFFIPerThread` or :func:`newServerPolicy`
 
 While Lua is fast, its use should be restricted to the strict necessary in order to achieve maximum performance, it might be worth considering using LuaJIT instead of Lua.
 When Lua inspection is needed, the best course of action is to restrict the queries sent to Lua inspection by using :func:`addLuaAction` with a selector.
index 7e8ad323c244826a291ac6b217a4a530674a47f5..66aa68ac0375fef55d92d8ad88f34b4829f1a702 100644 (file)
@@ -112,6 +112,24 @@ Or::
 
   setServerPolicyLua("splitsetup", splitSetup)
 
+For performance reasons, 1.6.0 introduced per-thread Lua FFI policies that are run in a lock-free per-thread Lua context instead of the global one.
+This reduces contention between threads at the cost of preventing sharing data between threads for these policies. Since the policy needs to be recompiled
+in the context of each thread instead of the global one, Lua code that returns a function should be passed to the function as a string instead of directly
+passing the name of a function:
+
+.. code-block:: lua
+
+  setServerPolicyLuaFFIPerThread("luaffiroundrobin", [[
+    local ffi = require("ffi")
+    local C = ffi.C
+
+    local counter = 0
+    return function(servers_list, dq)
+      counter = counter + 1
+      return (counter % tonumber(C.dnsdist_ffi_servers_list_get_count(servers_list)))
+    end
+  ]])
+
 ServerPolicy Objects
 --------------------
 
@@ -143,6 +161,12 @@ ServerPolicy Objects
 
     Whether this policy is a native (C++) policy or a Lua-based one.
 
+  .. attribute:: ServerPolicy.isPerThread
+
+    .. versionadded: 1.6.0
+
+    Whether a FFI Lua-based policy is executed in a lock-free per-thread context instead of running in the global Lua context.
+
   .. attribute:: ServerPolicy.name
 
     The name of the policy.
@@ -197,6 +221,16 @@ Functions
   :param string name: name for this policy
   :param string function: name of the FFI function
 
+.. function:: setServerPolicyLuaFFIPerThread(name, code)
+
+  .. versionadded:: 1.6.0
+
+  Set server selection policy to one named ``name`` and the Lua FFI function returned by the Lua code passed in ``code``.
+  The resulting policy will be executed in a lock-free per-thread context, instead of running in the global Lua context.
+
+  :param string name: name for this policy
+  :param string code: Lua FFI code returning the function to execute as a server selection policy
+
 .. function:: setServFailWhenNoServer(value)
 
   If set, return a ServFail when no servers are available, instead of the default behaviour of dropping the query.
index 6c85b6243b0c806f39f585b833f6a9684b47cbc9..4e21675deff70d47a70c880468544a1a74b8ca15 100644 (file)
@@ -27,6 +27,9 @@ GlobalStateHolder<NetmaskTree<DynBlock>> g_dynblockNMG;
 GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
 #endif /* BENCH_POLICIES */
 
+GlobalStateHolder<pools_t> g_pools;
+std::vector<std::unique_ptr<ClientState>> g_frontends;
+
 /* add stub implementations, we don't want to include the corresponding object files
    and their dependencies */
 
@@ -76,6 +79,12 @@ bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dq, const std::string& rea
   return false;
 }
 
+void setLuaNoSideEffect()
+{
+}
+
+string g_outputBuffer;
+
 static DNSQuestion getDQ(const DNSName* providedName = nullptr)
 {
   static const DNSName qname("powerdns.com.");
@@ -122,7 +131,7 @@ static void benchPolicy(const ServerPolicy& pol)
   for (size_t idx = 0; idx < 1000; idx++) {
   for (const auto& name : names) {
     auto dq = getDQ(&name);
-    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    auto server = pol.getSelectedBackend(servers, dq);
   }
   }
   cerr<<pol.name<<" took "<<std::to_string(sw.udiff())<<" us for "<<names.size()<<endl;
@@ -149,24 +158,24 @@ BOOST_AUTO_TEST_CASE(test_firstAvailable) {
   servers.push_back({ 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")) });
 
   /* servers start as 'down' */
-  auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+  auto server = pol.getSelectedBackend(servers, dq);
   BOOST_CHECK(server == nullptr);
 
   /* mark the server as 'up' */
   servers.at(0).second->setUp();
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_CHECK(server != nullptr);
 
   /* add a second server, we should still get the first one */
   servers.push_back({ 2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")) });
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_REQUIRE(server != nullptr);
   BOOST_CHECK(server == servers.at(0).second);
 
   /* mark the first server as 'down', second as 'up' */
   servers.at(0).second->setDown();
   servers.at(1).second->setUp();
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_REQUIRE(server != nullptr);
   BOOST_CHECK(server == servers.at(1).second);
 
@@ -181,38 +190,38 @@ BOOST_AUTO_TEST_CASE(test_roundRobin) {
 
   /* selecting a server on an empty server list */
   g_roundrobinFailOnNoServer = false;
-  auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+  auto server = pol.getSelectedBackend(servers, dq);
   BOOST_CHECK(server == nullptr);
 
   servers.push_back({ 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")) });
 
   /* servers start as 'down' but the RR policy returns a server unless g_roundrobinFailOnNoServer is set */
   g_roundrobinFailOnNoServer = true;
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_CHECK(server == nullptr);
   g_roundrobinFailOnNoServer = false;
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_CHECK(server != nullptr);
 
   /* mark the server as 'up' */
   servers.at(0).second->setUp();
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_CHECK(server != nullptr);
 
   /* add a second server, we should get the first one then the second one */
   servers.push_back({ 2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")) });
   servers.at(1).second->setUp();
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_REQUIRE(server != nullptr);
   BOOST_CHECK(server == servers.at(0).second);
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_REQUIRE(server != nullptr);
   BOOST_CHECK(server == servers.at(1).second);
 
   /* mark the first server as 'down', second as 'up' */
   servers.at(0).second->setDown();
   servers.at(1).second->setUp();
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_REQUIRE(server != nullptr);
   BOOST_CHECK(server == servers.at(1).second);
 
@@ -224,7 +233,7 @@ BOOST_AUTO_TEST_CASE(test_roundRobin) {
   }
 
   for (size_t idx = 0; idx < 1000; idx++) {
-    server = getSelectedBackendFromPolicy(pol, servers, dq);
+    server = pol.getSelectedBackend(servers, dq);
     BOOST_REQUIRE(serversMap.count(server) == 1);
     ++serversMap[server];
   }
@@ -246,24 +255,24 @@ BOOST_AUTO_TEST_CASE(test_leastOutstanding) {
   servers.push_back({ 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")) });
 
   /* servers start as 'down' */
-  auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+  auto server = pol.getSelectedBackend(servers, dq);
   BOOST_CHECK(server == nullptr);
 
   /* mark the server as 'up' */
   servers.at(0).second->setUp();
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_CHECK(server != nullptr);
 
   /* add a second server, we should still get the first one */
   servers.push_back({ 2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")) });
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_REQUIRE(server != nullptr);
   BOOST_CHECK(server == servers.at(0).second);
 
   /* mark the first server as 'down', second as 'up' */
   servers.at(0).second->setDown();
   servers.at(1).second->setUp();
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_REQUIRE(server != nullptr);
   BOOST_CHECK(server == servers.at(1).second);
 
@@ -271,7 +280,7 @@ BOOST_AUTO_TEST_CASE(test_leastOutstanding) {
   servers.at(0).second->setUp();
   servers.at(0).second->outstanding = 42;
   servers.at(1).second->setUp();
-  server = getSelectedBackendFromPolicy(pol, servers, dq);
+  server = pol.getSelectedBackend(servers, dq);
   BOOST_REQUIRE(server != nullptr);
   BOOST_CHECK(server == servers.at(1).second);
 
@@ -293,7 +302,7 @@ BOOST_AUTO_TEST_CASE(test_wrandom) {
   benchPolicy(pol);
 
   for (size_t idx = 0; idx < 1000; idx++) {
-    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    auto server = pol.getSelectedBackend(servers, dq);
     BOOST_REQUIRE(serversMap.count(server) == 1);
     ++serversMap[server];
   }
@@ -321,7 +330,7 @@ BOOST_AUTO_TEST_CASE(test_wrandom) {
   servers.at(servers.size()-1).second->weight = 100;
 
   for (size_t idx = 0; idx < 1000; idx++) {
-    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    auto server = pol.getSelectedBackend(servers, dq);
     BOOST_REQUIRE(serversMap.count(server) == 1);
     ++serversMap[server];
   }
@@ -360,7 +369,7 @@ BOOST_AUTO_TEST_CASE(test_whashed) {
 
   for (const auto& name : names) {
     auto dq = getDQ(&name);
-    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    auto server = pol.getSelectedBackend(servers, dq);
     BOOST_REQUIRE(serversMap.count(server) == 1);
     ++serversMap[server];
   }
@@ -383,9 +392,9 @@ BOOST_AUTO_TEST_CASE(test_whashed) {
   /* request 1000 times the same name, we should go to the same server every time */
   {
     auto dq = getDQ(&names.at(0));
-    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    auto server = pol.getSelectedBackend(servers, dq);
     for (size_t idx = 0; idx < 1000; idx++) {
-      BOOST_CHECK(getSelectedBackendFromPolicy(pol, servers, dq) == server);
+      BOOST_CHECK(pol.getSelectedBackend(servers, dq) == server);
     }
   }
 
@@ -399,7 +408,7 @@ BOOST_AUTO_TEST_CASE(test_whashed) {
 
   for (const auto& name : names) {
     auto dq = getDQ(&name);
-    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    auto server = pol.getSelectedBackend(servers, dq);
     BOOST_REQUIRE(serversMap.count(server) == 1);
     ++serversMap[server];
   }
@@ -445,7 +454,7 @@ BOOST_AUTO_TEST_CASE(test_chashed) {
 
   for (const auto& name : names) {
     auto dq = getDQ(&name);
-    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    auto server = pol.getSelectedBackend(servers, dq);
     BOOST_REQUIRE(serversMap.count(server) == 1);
     ++serversMap[server];
   }
@@ -468,9 +477,9 @@ BOOST_AUTO_TEST_CASE(test_chashed) {
   /* request 1000 times the same name, we should go to the same server every time */
   {
     auto dq = getDQ(&names.at(0));
-    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    auto server = pol.getSelectedBackend(servers, dq);
     for (size_t idx = 0; idx < 1000; idx++) {
-      BOOST_CHECK(getSelectedBackendFromPolicy(pol, servers, dq) == server);
+      BOOST_CHECK(pol.getSelectedBackend(servers, dq) == server);
     }
   }
 
@@ -484,7 +493,7 @@ BOOST_AUTO_TEST_CASE(test_chashed) {
 
   for (const auto& name : names) {
     auto dq = getDQ(&name);
-    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    auto server = pol.getSelectedBackend(servers, dq);
     BOOST_REQUIRE(serversMap.count(server) == 1);
     ++serversMap[server];
   }
@@ -540,7 +549,7 @@ BOOST_AUTO_TEST_CASE(test_lua) {
 
     for (const auto& name : names) {
       auto dq = getDQ(&name);
-      auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+      auto server = pol.getSelectedBackend(servers, dq);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
@@ -600,7 +609,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_rr) {
 
     for (const auto& name : names) {
       auto dq = getDQ(&name);
-      auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+      auto server = pol.getSelectedBackend(servers, dq);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
@@ -657,7 +666,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_hashed) {
 
     for (const auto& name : names) {
       auto dq = getDQ(&name);
-      auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+      auto server = pol.getSelectedBackend(servers, dq);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
@@ -712,7 +721,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed) {
 
     for (const auto& name : names) {
       auto dq = getDQ(&name);
-      auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+      auto server = pol.getSelectedBackend(servers, dq);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
@@ -774,7 +783,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed) {
 
     for (const auto& name : names) {
       auto dq = getDQ(&name);
-      auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+      auto server = pol.getSelectedBackend(servers, dq);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
index 70deba8f3c43e2d377165749baccf730a6a65802..8aabad85fa3c32d79b462a6f95700b976ac3023a 100644 (file)
@@ -253,6 +253,82 @@ class TestRoutingRoundRobinLBAllDown(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEquals(receivedResponse, None)
 
+class TestRoutingLuaFFIPerThreadRoundRobinLB(DNSDistTest):
+
+    _testServer2Port = 5351
+    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_template = """
+    setServerPolicyLuaFFIPerThread("luaffiroundrobin", [[
+      local ffi = require("ffi")
+      local C = ffi.C
+
+      local counter = 0
+      return function(servers_list, dq)
+        counter = counter + 1
+        return (counter %% tonumber(C.dnsdist_ffi_servers_list_get_count(servers_list)))
+      end
+    ]])
+
+    s1 = newServer{address="127.0.0.1:%s"}
+    s1:setUp()
+    s2 = newServer{address="127.0.0.1:%s"}
+    s2:setUp()
+    """
+
+    @classmethod
+    def startResponders(cls):
+        print("Launching responders..")
+        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder.setDaemon(True)
+        cls._UDPResponder.start()
+        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2.setDaemon(True)
+        cls._UDPResponder2.start()
+
+        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder.setDaemon(True)
+        cls._TCPResponder.start()
+
+        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2.setDaemon(True)
+        cls._TCPResponder2.start()
+
+    def testRR(self):
+        """
+        Routing: Round Robin
+
+        Send 10 A queries to "rr.routing.tests.powerdns.com.",
+        check that dnsdist routes half of it to each backend.
+        """
+        numberOfQueries = 10
+        name = 'rr.routing.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '192.0.2.1')
+        response.answer.append(rrset)
+
+        # the round robin counter is shared for UDP and TCP,
+        # so we need to do UDP then TCP to have a clean count
+        for _ in range(numberOfQueries):
+            (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+            receivedQuery.id = query.id
+            self.assertEquals(query, receivedQuery)
+            self.assertEquals(response, receivedResponse)
+
+        for _ in range(numberOfQueries):
+            (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+            receivedQuery.id = query.id
+            self.assertEquals(query, receivedQuery)
+            self.assertEquals(response, receivedResponse)
+
+        for key in self._responsesCounter:
+            value = self._responsesCounter[key]
+            self.assertEquals(value, numberOfQueries / 2)
+
 class TestRoutingOrder(DNSDistTest):
 
     _testServer2Port = 5351