]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Squashed commit of the following:
authorRuss Combs <rucombs@cisco.com>
Tue, 11 Aug 2015 20:35:27 +0000 (16:35 -0400)
committerRuss Combs <rucombs@cisco.com>
Tue, 11 Aug 2015 20:39:16 +0000 (16:39 -0400)
commit c5d47e48d14a6c447ff1e4a513341833dc6f29bf
Author: Joel Cornett <joel.cornett@gmail.com>
Date:   Mon Aug 10 12:28:51 2015 -0400

    added documentation to extending
    updated lua_iface
    added convenience functions for accessing RawBuffer data
    added reference tracking to interfaces
    exposed/added more methods to interfaces
    deleted RawData interface
    added lua_ref
    refactored Lua::Arg -> Lua::Args

51 files changed:
doc/extending.txt
piglet/tests/instance/codec.lua
piglet/tests/instance/inspector.lua
piglet/tests/instance/ips_option.lua
piglet/tests/instance/logger.lua
piglet/tests/interface/buffer.lua
piglet/tests/interface/cursor.lua
piglet/tests/interface/enc_state.lua
piglet/tests/interface/event.lua
piglet/tests/interface/packet.lua
piglet/tests/interface/raw_data.lua [deleted file]
src/lua/CMakeLists.txt
src/lua/Makefile.am
src/lua/lua_arg.h
src/lua/lua_iface.cc [deleted file]
src/lua/lua_iface.h
src/lua/lua_ref.cc [new file with mode: 0644]
src/lua/lua_ref.h [moved from src/piglet_plugins/pp_raw_data_iface.h with 74% similarity]
src/lua/lua_stack.h
src/lua/lua_table.h
src/managers/script_manager.cc
src/piglet/piglet_manager.cc
src/piglet/piglet_manager.h
src/piglet/piglet_runner.cc
src/piglet/piglet_utils.h
src/piglet_plugins/CMakeLists.txt
src/piglet_plugins/Makefile.am
src/piglet_plugins/dev_notes.txt
src/piglet_plugins/pp_buffer_iface.cc
src/piglet_plugins/pp_codec.cc
src/piglet_plugins/pp_codec_data_iface.cc
src/piglet_plugins/pp_codec_iface.cc
src/piglet_plugins/pp_cursor_iface.cc
src/piglet_plugins/pp_daq_pkthdr_iface.cc
src/piglet_plugins/pp_decode_data_iface.cc
src/piglet_plugins/pp_enc_state_iface.cc
src/piglet_plugins/pp_event_iface.cc
src/piglet_plugins/pp_flow_iface.cc
src/piglet_plugins/pp_inspector_iface.cc
src/piglet_plugins/pp_ips_option_iface.cc
src/piglet_plugins/pp_logger_iface.cc
src/piglet_plugins/pp_packet_iface.cc
src/piglet_plugins/pp_raw_buffer_iface.cc
src/piglet_plugins/pp_raw_buffer_iface.h
src/piglet_plugins/pp_raw_data_iface.cc [deleted file]
src/piglet_plugins/pp_stream_splitter_iface.cc
src/piglet_plugins/pp_test.cc
src/test/CMakeLists.txt
src/test/Makefile.am
src/test/lua_stack_test.cc [new file with mode: 0644]
src/test/lua_test_common.h [new file with mode: 0644]

index fac4165d1daf034fafeab586d5ffe16fbb0126fe..0f6f2cc75efd4e97daec4ce60d5eed3a75f70ec2 100644 (file)
@@ -276,6 +276,10 @@ Action plugins specify a builtin action in the API which is used to
 determine verdict.  (Conversely, builtin actions don't have an associated
 plugin function.)
 
+=== Developers Guide
+
+Run doc/dev_guide.sh to generate /tmp/dev_guide.html, an annotated guide to
+the source tree.
 
 === Piglet Test Harness
 
@@ -289,27 +293,23 @@ Here is a minimal example of a piglet test script for the IPv4 Codec plugin:
     plugin =
     {
         type = "piglet",
-        version = 1
-    }
-
-    piglet =
-    {
-        name = "my_test_for_ipv4_codec",
-        type = "codec",
-        target = "ipv4",
+        name = "codec::ipv4",
+        use_defaults = true,
         test = function()
-            local raw_data = RawData.new(1024)
+            local daq_header = DAQHeader.new()
+            local raw_buffer = RawBuffer.new("some data")
             local codec_data = CodecData.new()
             local decode_data = DecodeData.new()
 
-            codec("decode", raw_data, codec_data, decode_data)
-            return true
+            return Codec.decode(
+                daq_header,
+                raw_buffer,
+                codec_data,
+                decode_data
+            )
         end
     }
 
-More example tests can be found in the piglet_scripts directory. Refer to these
-examples for furthur usage of Lua wrappers to snort data structures (such as Packet).
-
 To run snort in piglet mode, first build snort with the BUILD_PIGLET option turned on
 (pass the flag -DBUILD_PIGLET:BOOL=ON in cmake).
 
@@ -322,9 +322,281 @@ Then, run the following command:
 The test runner will generate a check-like output, indicating the
 the results of each test script.
 
+=== Piglet Lua API
 
-=== Developers Guide
+This section documents the API that piglet exposes to Lua.
+Refer to the piglet directory in the source tree for examples of usage.
 
-Run doc/dev_guide.sh to generate /tmp/dev_guide.html, an annotated guide to
-the source tree.
+Note: Because of the differences between the Lua and C\++ data model and type
+system, not all parameters map directly to the parameters of the underlying
+C\++ member functions. Every effort has been made to keep the mappings consist,
+but there are still some differences. They are documented below.
+
+==== Plugin Instances
+
+For each test, piglet instantiates plugin specified in the ++name++ field of the
+++plugin++ table. The virtual methods of the instance are exposed in a table
+unique to each plugin type. The name of the table is the CamelCase name of the
+plugin type.
+
+For example, codec plugins have a virtual method called ++decode++. This method
+is called like this:
+
+    Codec.decode(...)
+
+*Codec*
+
+* ++Codec.get_data_link_type() -> { int, int, ... }++
+* ++Codec.get_protocol_ids() -> { int, int, ... }++
+* ++Codec.decode(DAQHeader, CodecData, DecodeData) -> bool++
+* ++Codec.log(RawBuffer, uint[lyr_len])++
+* ++Codec.encode(RawBuffer, EncState, Buffer) -> bool++
+* ++Codec.update(uint[flags_hi], uint[flags_lo], RawBuffer, uint[lyr_len] -> int++
+* ++Codec.format(bool[reverse], RawBuffer, DecodeData)++
+
+Differences:
+
+* In ++Codec.update()++, the ++(uint64_t) flags++ parameter has been split into
+++flags_hi++ and ++flags_lo++
+
+*Inspector*
+
+* ++Inspector.configure()++
+* ++Inspector.tinit()++
+* ++Inspector.tterm()++
+* ++Inspector.likes(Packet)++
+* ++Inspector.eval(Packet)++
+* ++Inspector.clear(Packet)++
+* ++Inspector.get_buf_from_key(string[key], Packet, RawBuffer) -> bool++
+* ++Inspector.get_buf_from_id(uint[id], Packet, RawBuffer) -> bool++
+* ++Inspector.get_buf_from_type(uint[type], Packet, RawBuffer) -> bool++
+* ++Inspector.get_splitter(bool[to_server]) -> StreamSplitter++
+
+Differences:
+* In ++Inspector.configure()++, the ++SnortConfig*++ parameter is passed implicitly.
+* the overloaded ++get_buf()++ member function has been split into three separate methods.
+
+*IpsOption*
+
+* ++IpsOption.hash() -> int++
+* ++IpsOption.is_relative() -> bool++
+* ++IpsOption.fp_research() -> bool++
+* ++IpsOption.get_cursor_type() -> int++
+* ++IpsOption.eval(Cursor, Packet) -> int++
+* ++IpsOption.action(Packet)++
+
+*IpsAction*
+
+* ++IpsAction.exec(Packet)++
+
+*Logger*
+
+* ++Logger.open()++
+* ++Logger.close()++
+* ++Logger.reset()++
+* ++Logger.alert(Packet, string[message], Event)++
+* ++Logger.log(Packet, string[message], Event)++
+
+*SearchEngine*
+
+Currently, SearchEngine does not expose any methods.
+
+*SoRule*
+
+Currently, SoRule does not expose any methods.
+
+===== Interface Objects
+
+Many of the plugins take C\++ classes and structs as arguments. These objects
+are exposed to the Lua API as Lua userdata. Exposed objects are instantiated
+by calling the ++new++ method from each object's method table.
+
+For example, the DecodeData object can be instantiated and exposed to Lua
+like this:
+
+    local decode_data = DecodeData.new(...)
+
+Each object also exposes useful methods for getting and setting member variables,
+and calling the C\++ methods contained in the the object. These methods can
+be accessed using the ++:++ accessor syntax:
+
+    decode_data:set({ sp = 80, dp = 3500 })
+
+Since this is just syntactic sugar for passing the object as the first parameter
+of the function ++DecodeData.set++, an equivalent form is:
+
+    decode_data.set(decode_data, { sp = 80, dp = 3500 })
+
+or even:
+
+    DecodeData.set(decode_data, { sp = 80, dp = 3500 })
+
+*Buffer*
+
+* ++Buffer.new(string[data]) -> Buffer++
+* ++Buffer.new(uint[length]) -> Buffer++
+* ++Buffer.new(RawBuffer) -> Buffer++
+* ++Buffer:allocate(uint[length]) -> bool++
+* ++Buffer:clear()++
+
+*CodecData*
+
+* ++CodecData.new() -> Cursor++
+* ++CodecData.new(uint[next_prot_id]) -> Cursor++
+* ++CodecData.new(fields) -> Cursor++
+
+* ++CodecData:get() -> fields++
+* ++CodecData:set(fields)++
+
+++fields++ is a table with the following contents:
+
+* ++next_prot_id++
+* ++lyr_len++
+* ++invalid_bytes++
+* ++proto_bits++
+* ++codec_flags++
+* ++ip_layer_cnt++
+* ++ip6_extension_count++
+* ++curr_ip6_extension++
+* ++ip6_csum_proto++
+
+*Cursor*
+
+* ++Cursor.new() -> Cursor++
+* ++Cursor.new(Packet) -> Cursor++
+* ++Cursor.new(string[data]) -> Cursor++
+* ++Cursor.new(RawBuffer) -> Cursor++
+* ++Cursor:reset()++
+* ++Cursor:reset(Packet)++
+* ++Cursor:reset(string[data])++
+* ++Cursor:reset(RawBuffer)++
+
+*DAQHeader*
+
+* ++DAQHeader.new() -> DAQHeader++
+* ++DAQHeader.new(fields) -> DAQHeader++
+* ++DAQHeader:get() -> fields++
+* ++DAQHeader:set(fields)++
+
+++fields++ is a table with the following contents:
+
+* ++caplen++
+* ++pktlen++
+* ++ingress_index++
+* ++egress_index++
+* ++ingress_group++
+* ++egress_group++
+* ++flags++
+* ++opaque++
+
+*DecodeData*
 
+* ++DecodeData.new() -> DecodeData++
+* ++DecodeData.new(fields) -> DecodeData++
+* ++DecodeData:reset()++
+* ++DecodeData:get() -> fields++
+* ++DecodeData:set(fields)++
+* ++DecodeData:set_ipv4_hdr(RawBuffer, uint[offset])++
+
+++fields++ is a table with the following contents:
+
+* ++sp++
+* ++dp++
+* ++decode_flags++
+* ++type++
+
+*EncState*
+
+* ++EncState.new() -> EncState++
+* ++EncState.new(uint[flags_lo]) -> EncState++
+* ++EncState.new(uint[flags_lo], uint[flags_hi]) -> EncState++
+* ++EncState.new(uint[flags_lo], uint[flags_hi], uint[next_proto]) -> EncState++
+* ++EncState.new(uint[flags_lo], uint[flags_hi], uint[next_proto], uint[ttl]) -> EncState++
+* ++EncState.new(uint[flags_lo], uint[flags_hi], uint[next_proto], uint[ttl], uint[dsize]) -> EncState++
+
+*Event*
+
+* ++Event.new() -> Event++
+* ++Event.new(fields) -> Event++
+* ++Event:get() -> fields++
+* ++Event:set(fields)++
+
+++fields++ is a table with the following contents:
+
+* ++event_id++
+* ++event_reference++
+* ++sig_info++
+** ++generator++
+** ++id++
+** ++rev++
+** ++class_id++
+** ++priority++
+** ++text_rule++
+** ++num_services++
+
+*Flow*
+
+* ++Flow.new() -> Flow++
+* ++Flow:reset()++
+
+*Packet*
+
+* ++Packet.new() -> Packet++
+* ++Packet.new(string[data]) -> Packet++
+* ++Packet.new(uint[size]) -> Packet++
+* ++Packet.new(fields) -> Packet++
+* ++Packet.new(RawBuffer) -> Packet++
+* ++Packet.new(DAQHeader) -> Packet++
+* ++Packet:set_decode_data(DecodeData)++
+* ++Packet:set_data(uint[offset], uint[length])++
+* ++Packet:set_flow(Flow)++
+* ++Packet:get() -> fields++
+* ++Packet:set() ++
+* ++Packet:set(string[data]) ++
+* ++Packet:set(uint[size]) ++
+* ++Packet:set(fields) ++
+* ++Packet:set(RawBuffer) ++
+* ++Packet:set(DAQHeader) ++
+
+++fields++ is a table with the following contents:
+
+* ++packet_flags++
+* ++xtradata_mask++
+* ++proto_bits++
+* ++application_protocol_ordinal++
+* ++alt_dsize++
+* ++num_layers++
+* ++iplist_id++
+* ++user_policy_id++
+* ++ps_proto++
+
+Note: ++Packet.new()++ and ++Packet:set()++ accept multiple arguments of the
+types described above in any order
+
+*RawBuffer*
+
+* ++RawBuffer.new() -> RawBuffer++
+* ++RawBuffer.new(uint[size]) -> RawBuffer++
+* ++RawBuffer.new(string[data]) -> RawBuffer++
+* ++RawBuffer:size() -> int++
+* ++RawBuffer:resize(uint[size])++
+* ++RawBuffer:write(string[data])++
+* ++RawBuffer:write(string[data], uint[size])++
+* ++RawBuffer:read() -> string++
+* ++RawBuffer:read(uint[end]) -> string++
+* ++RawBuffer:read(uint[start], uint[end]) -> string++
+
+Note: calling ++RawBuffer.new()++ with no arguments returns a RawBuffer of size 0
+
+*StreamSplitter*
+
+* ++StreamSplitter:scan(Flow, RawBuffer) -> int, int++
+* ++StreamSplitter:scan(Flow, RawBuffer, uint[len]) -> int, int++
+* ++StreamSplitter:scan(Flow, RawBuffer, uint[len], uint[flags]) -> int, int++
+* ++StreamSplitter:reassemble(Flow, uint[total], uint[offset], RawBuffer) -> int, RawBuffer++
+* ++StreamSplitter:reassemble(Flow, uint[total], uint[offset], RawBuffer, uint[len]) -> int, RawBuffer++
+* ++StreamSplitter:reassemble(Flow, uint[total], uint[offset], RawBuffer, uint[len], uint[flags]) -> int, RawBuffer++
+* ++StreamSplitter:finish(Flow) -> bool++
+
+Note: StreamSplitter does not have a ++new()++ method, it must be created by an inspector via
+++Inspector.get_splitter()++
index 2b2b152dd70fdedcabff3a4d136cd439e86d2131..d33d5a3091ae2f4062d1d53cf50c01ce55e9010e 100644 (file)
@@ -28,13 +28,12 @@ tests =
     end,
 
     decode = function()
-        local rb = RawBuffer.new()
+        local daq = DAQHeader.new()
+        local rb = RawBuffer.new("foobar")
         local cd = CodecData.new()
         local dd = DecodeData.new()
-        local daq = DAQHeader.new()
-        local rd = RawData.new(rb, daq)
 
-        local rv = Codec.decode(rd, cd, dd)
+        local rv = Codec.decode(daq, rb, cd, dd)
         assert(not rv)
     end,
 
@@ -59,11 +58,11 @@ tests =
         local rb = RawBuffer.new(64)
 
         -- FIXIT-H: checksum calculation is failing (temporarily set UPD_COOKED (0x1))
-        local rv = Codec.update(1, rb)
+        local rv = Codec.update(0, 1, rb)
         assert(rv == 0)
 
         -- FIXIT-H: checksum calculation is failing (temporarily set UPD_COOKED (0x1))
-        local rv = Codec.update(1, rb, 64)
+        local rv = Codec.update(0, 1, rb, 64)
         assert(rv == 0)
     end,
 
index 7d37a6d05d660b81f2199c59bdef9c1816cc46b6..cedef29b6f1e83d2a8c38f5718294a14cca387d8 100644 (file)
@@ -5,7 +5,9 @@ plugin =
     test = function()
         dofile(SCRIPT_DIR .. "/common.lua")
         return run_all(tests)
-    end
+    end,
+    -- FIXIT-L: Need this to keep Inspector.configure() happy
+    use_defaults = true
 }
 
 HEADER = [[
@@ -59,7 +61,7 @@ tests =
         local p, rb = get_packet()
         local ib = RawBuffer.new()
 
-        local rv = Inspector.get_buf_from_key(0, p, ib)
+        local rv = Inspector.get_buf_from_id(0, p, ib)
         assert(not rv)
     end,
 
@@ -69,5 +71,22 @@ tests =
 
         spl = Inspector.get_splitter(true)
         assert(type(spl) == "userdata")
+    end,
+
+    configure = function()
+        assert(Inspector.configure())
+    end,
+
+    tinit = function()
+        Inspector.tinit()
+    end,
+
+    tterm = function()
+        Inspector.tterm()
+    end,
+
+    likes = function()
+        local p = Packet.new()
+        assert(not Inspector.likes(p))
     end
 }
index 37ae2bcf0fa156dfb3792524df727184490199e8..a48ba5cb3e18dcd11ec93dc80551c5f9a7015588 100644 (file)
@@ -12,5 +12,33 @@ tests =
 {
     initialize = function()
         assert(IpsOption)
+    end,
+
+    hash = function()
+        local rv = IpsOption.hash()
+    end,
+
+    is_relative = function() assert(not IpsOption.is_relative()) end,
+
+    fp_research = function() assert(not IpsOption.fp_research()) end,
+
+    get_cursor_type = function()
+        local rv = IpsOption.get_cursor_type()
+        assert(rv == 1)
+    end,
+
+    eval = function()
+        local rb = RawBuffer.new("foobar")
+        local cur = Cursor.new(rb)
+        local p = Packet.new(rb)
+
+        local rv = IpsOption.eval(cur, p)
+        assert(rv)
+    end,
+
+    action = function()
+        local rb = RawBuffer.new("foobar")
+        local p = Packet.new(rb)
+        IpsOption.action(p)
     end
 }
index b17a5e2a7623a75fa60cab4b60e6b3231b740468..58d2e61e239586062213bd5887c8124d7eae3ef9 100644 (file)
@@ -2,6 +2,7 @@ plugin =
 {
     type = "piglet",
     name = "logger::alert_csv",
+    use_defaults = true,
     test = function()
         Logger.open()
         dofile(SCRIPT_DIR .. "/common.lua")
index f663fee5bc58770d710935e6751db1fe33a3895c..b58dc47742cbc70bf97d3d562a7923dc9ccef7bf 100644 (file)
@@ -11,9 +11,40 @@ plugin =
 
 tests =
 {
-    initialization = function()
-        local rb = RawBuffer.new()
+    init_with_raw_buffer = function()
+        local rb = RawBuffer.new("abcdefghijklmnopqrstuvwxyz")
         local buf = Buffer.new(rb)
         assert(buf)
+    end,
+
+    init_with_string = function()
+        local buf = Buffer.new("abcdefg")
+        assert(buf)
+    end,
+
+    init_with_length = function()
+        local buf = Buffer.new(128)
+        assert(buf)
+    end,
+
+    allocate = function()
+        local buf = Buffer.new(16)
+        assert(buf:allocate(10))
+        assert(not buf:allocate(10))
+    end,
+
+    clear = function()
+        local buf = Buffer.new(16)
+        buf:allocate(16)
+        buf:clear()
+        assert(buf:allocate(10))
+    end,
+
+    to_string = function()
+        local buf = Buffer.new("abcdefgh")
+        buf:allocate(3)
+        local v = tostring(buf)
+        assert(#v == 3)
+        assert(v == "gh\0")
     end
 }
index 6b1b762bdf874d1ba0772d974d0b679d2a3683c4..ec978c4f176b91a6d414491ce5b32bfa4dfebae0 100644 (file)
@@ -11,10 +11,33 @@ plugin =
 
 tests =
 {
-    initialize = function()
-        local rb = RawBuffer.new()
-        local p = Packet.new(rb)
-        local cur = Cursor.new(p)
+    init_default = function()
+        local cur = Cursor.new()
         assert(cur)
+    end,
+
+    init_from_string = function()
+        local cur = Cursor.new("abcdefgh")
+        assert(cur)
+    end,
+
+    init_from_raw_buffer = function()
+        local cur = Cursor.new(RawBuffer.new("abcdefgh"))
+        assert(cur)
+    end,
+
+    reset_default = function()
+        local cur = Cursor.new()
+        cur:reset()
+    end,
+
+    reset_from_string = function()
+        local cur = Cursor.new()
+        cur:reset("abcdefgh")
+    end,
+
+    reset_from_raw_buffer = function()
+        local cur = Cursor.new()
+        cur:reset(RawBuffer.new("abcdefgh"))
     end
 }
index 97fb4ec69d0f0385e98a86ef309cd1fc22796ad0..54d7ef24004720f673394a375c67c16d3769898a 100644 (file)
@@ -14,5 +14,8 @@ tests =
     initialize = function()
         local es = EncState.new()
         assert(es)
+
+        es = EncState.new(0x80000000, 0xffffffff, 2, 24, 128)
+        assert(es)
     end
 }
index 43e3dddc93eca9507e2438f5c2350b4a9d6139be..a04f226f026dadb506fdba6ac8ff2138904caca9 100644 (file)
@@ -45,11 +45,16 @@ SIGINFO_VALUES =
 
 tests =
 {
-    initialize = function()
+    init_default = function()
         local event = Event.new()
         assert(event)
     end,
 
+    init_with_table = function()
+        local event = Event.new(VALUES)
+        assert_table_eq("get()", VALUES, event:get())
+    end,
+
     get_and_set = function()
         local event = Event.new()
         assert_table_eq("get()", DEFAULT_VALUES, event:get())
index b520183a35d30cbb87dc05dc9e47dc3c2c9ee863..350a7ba6c7bdde71a991f2112f2f2c691ba4852a 100644 (file)
@@ -42,16 +42,35 @@ tests =
         assert(p)
     end,
 
-    initialize_with_data = function()
+    init_with_string = function()
+        local p = Packet.new("foobar")
+        assert(p)
+    end,
+
+    init_with_size = function()
+        local p = Packet.new(128)
+        assert(p)
+    end,
+
+    init_with_raw_buffer = function()
         local rb = RawBuffer.new()
         local p = Packet.new(rb)
         assert(p)
     end,
 
-    initialize_with_daq = function()
-        local rb = RawBuffer.new()
+    init_with_daq = function()
         local daq = DAQHeader.new()
-        local p = Packet.new(rb, daq)
+        local p = Packet.new(daq)
+        assert(p)
+    end,
+
+    init_with_table = function()
+        local p = Packet.new(VALUES)
+        assert_table_eq("get()", VALUES, p:get())
+    end,
+
+    init_with_everything = function()
+        local p = Packet.new("foobar", DAQHeader.new(), { packet_flags = 4 })
         assert(p)
     end,
 
@@ -78,17 +97,5 @@ tests =
         assert_table_eq("get()", DEFAULT_VALUES, p:get())
         p:set(VALUES)
         assert_table_eq("set()", VALUES, p:get())
-    end,
-
-    set_pkt = function()
-        local rb = RawBuffer.new()
-        local p = Packet.new()
-        p:set_pkt(rb)
-    end,
-
-    set_daq = function()
-        local daq = DAQHeader.new()
-        local p = Packet.new()
-        p:set_daq(daq)
     end
 }
diff --git a/piglet/tests/interface/raw_data.lua b/piglet/tests/interface/raw_data.lua
deleted file mode 100644 (file)
index edbd54d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-plugin =
-{
-    type = "piglet",
-    name = "piglet::raw_data",
-    test = function()
-        -- Put the dofile here so that it doesn't get loaded twice
-        dofile(SCRIPT_DIR .. "/common.lua")
-        return run_all(tests)
-    end
-}
-
-tests =
-{
-    initialize = function()
-        local rb = RawBuffer.new()
-        local daq = DAQHeader.new()
-        local rd = RawData.new(rb, daq)
-        assert(rd)
-    end
-}
index 9f90ccfc4df78d6e5b7524e0c5cc8dc9e555e5ec..8619ff5a6670d9b15b979e499b7f58be653ad90d 100644 (file)
@@ -1,7 +1,8 @@
 add_library (lua STATIC
     lua.cc
     lua.h
-    lua_iface.cc
+    lua_ref.cc
+    lua_ref.h
     lua_iface.h
     lua_util.cc
     lua_util.h
index 17ce1d6df3ed73a4b4d7ac53f64d102105d014d1..c3b090fa65bac69072a9442ee390383219ddb41f 100644 (file)
@@ -6,6 +6,7 @@ x_includedir = $(pkgincludedir)/lua
 
 x_include_HEADERS = \
 lua.h \
+lua_ref.h \
 lua_iface.h \
 lua_table.h \
 lua_arg.h \
@@ -15,7 +16,8 @@ lua_util.h
 liblua_a_SOURCES = \
 lua.cc \
 lua.h \
-lua_iface.cc \
+lua_ref.cc \
+lua_ref.h \
 lua_iface.h \
 lua_util.cc \
 lua_util.h \
index 4de70a7bb3180ceb2af27a5c010b9104d3b10524..d92f2c4cbae70cb655bef0cd1656ab1618feb491 100644 (file)
 
 #include <luajit-2.0/lua.hpp>
 
+#include "lua_stack.h"
+
 namespace Lua
 {
-// FIXIT-M: generate better oob error messages
-struct Arg
+class Args
 {
+public:
+    template<typename T>
+    using ArgCallback = void (*)(lua_State*, int, T& ud);
+
+    Args(lua_State* _L) : L { _L }, count { lua_gettop(L) } { }
+
+private:
     lua_State* L;
-    int count;
 
-    inline bool exists(int n)
-    { return !lua_isnone(L, n); }
+    struct ArgRef
+    {
+    public:
+        ArgRef(lua_State* _L, int ct, int i) :
+            L { _L }, count { ct }, index { i } { }
 
-    inline void check_type(int n, int type)
-    { luaL_checktype(L, n, type); }
+        // We treat nil as !exists
+        inline bool exists()
+        { return (index > 0) && (index <= count) && !lua_isnoneornil(L, index); }
 
-    // Types
-    inline bool is_type(int n, int type)
-    { return lua_type(L, n) == type; }
+        inline bool is_table()
+        { return exists() && lua_istable(L, index); }
 
-    inline bool is_number(int n)
-    { return is_type(n, LUA_TNUMBER); }
+        inline void check_table()
+        { luaL_checktype(L, index, LUA_TTABLE); }
 
-    inline bool is_string(int n)
-    { return is_type(n, LUA_TSTRING); }
+        template<typename T>
+        inline void check_table(ArgCallback<T> cb, T& ud)
+        {
+            check_table();
+            cb(L, index, ud);
+        }
 
-    inline bool is_table(int n)
-    { return is_type(n, LUA_TTABLE); }
+        template<typename T>
+        inline bool opt_table(ArgCallback<T> cb, T& ud)
+        {
+            if ( exists() )
+            {
+                check_table(cb, ud);
+                return true;
+            }
 
-    inline bool is_boolean(int n)
-    { return is_type(n, LUA_TBOOLEAN); }
+            return false;
+        }
 
-    // Table
-    inline void check_table(int n)
-    { check_type(n, LUA_TTABLE); }
+        inline bool is_function()
+        { return exists() && lua_isfunction(L, index); }
 
-    // Boolean
-    inline bool check_boolean(int n)
-    {
-        check_type(n, LUA_TBOOLEAN);
-        return lua_toboolean(L, n);
-    }
+        // FIXIT-L: We *may* need to insert checks for userdata, pointers, etc here
 
-    inline bool opt_boolean(int n, bool d = false)
-    {
-        if ( is_boolean(n) )
-            return check_boolean(n);
+        inline bool is_int()
+        { return is<int>(); }
 
-        return d;
-    }
+        inline int get_int()
+        { return get<int>(); }
 
-    // String
-    inline const char* check_string(int n, size_t* len = nullptr)
-    {
-        check_type(n, LUA_TSTRING);
-        return lua_tolstring(L, n, len);
-    }
+        inline int check_int()
+        { return check<int>("expected an integer"); }
 
-    inline const char* opt_string(int n, const char* d, size_t* len = nullptr)
-    {
-        if ( is_string(n) )
-            return check_string(n, len);
+        inline int check_int(int max)
+        {
+            int v = check_int();
+            return argcheck((v <= max), v, "Too big");
+        }
 
-        return d;
-    }
+        inline int check_int(int min, int max)
+        {
+            int v = check_int(max);
+            return argcheck((v >= min), v, "Too small");
+        }
 
-    // Integers
-    inline lua_Integer check_int(int n)
-    {
-        check_type(n, LUA_TNUMBER);
-        return lua_tointeger(L, n);
-    }
+        inline int opt_int(int d = 0)
+        { return ( exists() )? check_int() : d; }
 
-    inline lua_Integer check_int(int n, lua_Integer min, lua_Integer max)
-    {
-        auto v = check_int(n);
-        luaL_argcheck(L, ((v >= min) && (v <= max)), n, "oob");
-        return v;
-    }
+        inline int opt_int(int d, int max)
+        { return ( exists() )? check_int(max) : d; }
 
-    inline lua_Integer opt_int(int n, lua_Integer d = 0)
-    {
-        if ( is_number(n) )
-            return check_int(n);
+        inline int opt_int(int d, int min, int max)
+        { return ( exists() )? check_int(min, max) : d; }
 
-        return d;
-    }
+        inline bool is_size()
+        { return is<unsigned>(); }
 
-    inline lua_Integer opt_int(
-        int n, lua_Integer d, lua_Integer min, lua_Integer max)
-    {
-        auto v = opt_int(n, d);
-        luaL_argcheck(L, ((v >= min) && (v <= max)), n, "oob");
-        return v;
-    }
+        inline unsigned get_size()
+        { return get<unsigned>(); }
 
-    inline unsigned check_size(int n)
-    {
-        auto v = check_int(n);
-        luaL_argcheck(L, (v >= 0), n, "oob");
-        return v;
-    }
+        inline unsigned check_size()
+        { return check<unsigned>("expected an unsigned integer"); }
 
-    inline unsigned check_size(int n, unsigned max)
-    {
-        auto v = check_size(n);
-        luaL_argcheck(L, (v <= max), n, "oob");
-        return v;
-    }
+        inline unsigned check_size(unsigned max)
+        {
+            unsigned v = check_size();
+            return argcheck((v <= max), v, "too big");
+        }
 
-    inline unsigned check_size(int n, unsigned min, unsigned max)
-    {
-        auto v = check_size(n, max);
-        luaL_argcheck(L, (v >= min), n, "oob");
-        return v;
-    }
+        inline unsigned check_size(unsigned min, unsigned max)
+        {
+            unsigned v = check_size(max);
+            return argcheck((v >= min), v, "too small");
+        }
 
-    inline unsigned opt_size(int n, unsigned d = 0)
-    {
-        if ( is_number(n) )
-            return check_size(n);
+        inline unsigned opt_size(unsigned d = 0)
+        { return ( exists() ) ? check_size() : d; }
 
-        return d;
-    }
+        inline unsigned opt_size(unsigned d, unsigned max)
+        { return ( exists() ) ? check_size(max) : d; }
 
-    inline unsigned opt_size(int n, unsigned d, unsigned max)
-    {
-        auto v = opt_size(n, d);
-        luaL_argcheck(L, (v <= max), n, "oob");
-        return v;
-    }
+        inline unsigned opt_size(unsigned d, unsigned min, unsigned max)
+        { return ( exists() ) ? check_size(min, max) : d; }
+
+        inline bool is_string()
+        { return is<const char*>(); }
+
+        inline const char* get_string()
+        { return get<const char*>(); }
+
+        inline const char* check_string()
+        { return check<const char*>("expected a string"); }
+
+        inline const char* check_string(size_t& len)
+        { return check<const char*>("expected a string", len); }
+
+        inline const char* opt_string(const char* d = "")
+        { return ( exists() ) ? check_string() : d; }
+
+        inline const char* opt_string(const char* d, size_t& len)
+        { return ( exists() ) ? check_string(len) : d; }
+
+        inline bool is_bool()
+        { return is<bool>(); }
+
+        inline bool get_bool()
+        { return get<bool>(); }
+
+        inline bool check_bool()
+        { return check<bool>("expected a boolean"); }
 
-    inline unsigned opt_size(int n, unsigned d, unsigned min, unsigned max)
+        inline bool opt_bool(bool d = false)
+        { return ( exists() ) ? check_bool() : d; }
+
+    private:
+        lua_State* L;
+        const int count;
+
+        template<typename T>
+        inline T argcheck(bool cond, T v, const char* msg)
+        {
+            luaL_argcheck(L, exists() && cond, index, msg);
+            return v;
+        }
+
+        template<typename T, typename... Args>
+        inline T check(const char* msg, Args&&... args)
+        {
+            T v;
+            return argcheck(
+                Stack<T>::validate(L, index, v, std::forward<Args>(args)...),
+                v, msg
+            );
+        }
+
+        inline bool is(int type)
+        { return exists() && (type == lua_type(L, index)); }
+
+        template<typename T>
+        inline bool is()
+        { return is(Stack<T>::type()); }
+
+        template<typename T>
+        inline T get()
+        { return Stack<T>::get(L, index); }
+
+    public:
+        const int index;
+    };
+
+public:
+    const int count;
+
+    ArgRef operator[](int i)
     {
-        auto v = opt_size(n, d, max);
-        luaL_argcheck(L, (v >= min), n, "oob");
-        return v;
-    }
+        if ( i < 0 )
+            i += count + 1;
+
+        // If the index is invalid, mark it as such with 0
+        if ( i < 0 )
+            i = 0;
 
-    Arg(lua_State* state) : L(state)
-    { count = lua_gettop(L); }
+        return ArgRef(L, count, i);
+    }
 };
 }
 #endif
diff --git a/src/lua/lua_iface.cc b/src/lua/lua_iface.cc
deleted file mode 100644 (file)
index 66abf7a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//--------------------------------------------------------------------------
-// lua_iface.cc author Joel Cornett <jocornet@cisco.com>
-
-#include "lua_iface.h"
-
-#include <luajit-2.0/lua.hpp>
-
-namespace Lua { }
index 0ed3cdbec89bc75c99fbf96cb00ca7e977084e27..d372eb5c0919827e53dc436612d4f38ad8733d45 100644 (file)
 #ifndef LUA_IFACE_H
 #define LUA_IFACE_H
 
-#include <vector>
 #include <luajit-2.0/lua.hpp>
 
 #include "lua.h"
-#include "lua_stack.h"
+#include "lua_ref.h"
 #include "lua_table.h"
 
 namespace Lua
@@ -78,6 +77,8 @@ template<typename T>
 struct TypeInterface
 {
     using type = T;
+    using AccessorCallback = void (*)(lua_State*, int, T&);
+
     const char* name;
     const luaL_Reg* methods;
     const luaL_Reg* metamethods;
@@ -88,12 +89,57 @@ struct TypeInterface
     T& get(lua_State* L, int arg = 1) const
     { return **regurgitate(L, arg); }
 
+    bool is(lua_State* L, int arg = 1) const
+    {
+        ManageStack ms(L, 1);
+
+        if ( lua_type(L, arg) != LUA_TUSERDATA )
+            return false;
+
+        // Check the registry for metatable with name
+        lua_getfield(L, LUA_REGISTRYINDEX, name);
+        lua_getmetatable(L, arg);
+
+        if ( !lua_rawequal(L, -1, -2) )
+            return false;
+
+        return true;
+    }
+
     T** allocate(lua_State*) const;
 
     template<typename... Args>
     T& create(lua_State*, Args&&...) const;
 
     void destroy(lua_State*, T** = nullptr) const;
+
+    int default_tostring(lua_State* L) const
+    {
+        lua_pushfstring(L, "%s@0x%p", this->name, &this->get(L));
+        return 1;
+    }
+
+    int default_gc(lua_State* L) const
+    {
+        this->destroy(L);
+        return 0;
+    }
+
+    int default_getter(lua_State* L, AccessorCallback acb) const
+    {
+        auto& self = this->get(L);
+        lua_newtable(L);
+        acb(L, lua_gettop(L), self);
+        return 1;
+    }
+
+    int default_setter(lua_State* L, AccessorCallback acb) const
+    {
+        auto& self = this->get(L, 1);
+        luaL_checktype(L, 2, LUA_TTABLE);
+        acb(L, 2, self);
+        return 0;
+    }
 };
 
 template<typename T>
@@ -126,6 +172,7 @@ void TypeInterface<T>::destroy(lua_State* L, T** t) const
 
     if ( *t )
     {
+        remove_refs(L, static_cast<void*>(*t));
         delete *t;
         t = nullptr;
     }
@@ -152,6 +199,16 @@ T& InstanceInterface<T>::get(lua_State* L, int up) const
     return *static_cast<T*>(const_cast<void*>(lua_topointer(L, idx)));
 }
 
+// -----------------------------------------------------------------------------
+// Library
+// -----------------------------------------------------------------------------
+
+struct Library
+{
+    const char* name;
+    const luaL_Reg* methods;
+};
+
 // -----------------------------------------------------------------------------
 // Installers
 // -----------------------------------------------------------------------------
@@ -178,5 +235,10 @@ void install(lua_State* L, const struct InstanceInterface<T>& iface, T* instance
     int inst = lua_gettop(L);
     register_with_closure(L, iface.methods, table, inst);
 }
+
+static inline void install(lua_State* L, const struct Library& lib)
+{ register_methods(L, lib.methods, lib.name); }
+
 }
+
 #endif
diff --git a/src/lua/lua_ref.cc b/src/lua/lua_ref.cc
new file mode 100644 (file)
index 0000000..b70bcfb
--- /dev/null
@@ -0,0 +1,100 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// lua_ref.cc author Joel Cornett <jocornet@cisco.com>
+
+#include "lua_ref.h"
+
+#include <luajit-2.0/lua.hpp>
+
+#include "lua.h"
+
+// leave 2 items on the stack (key, ref table)
+// uses 4 slots
+static inline void create_registry_table(lua_State* L, void* p)
+{
+    // key = address of object
+    lua_pushlightuserdata(L, p);
+    // dup key
+    lua_pushvalue(L, -1);
+    // get: registry[key]
+    lua_gettable(L, LUA_REGISTRYINDEX);
+
+    if ( lua_isnil(L, -1) )
+    {
+        // remove nil
+        lua_pop(L, 1);
+        // ref = new ref table
+        lua_newtable(L);
+        // dup key
+        lua_pushvalue(L, -2);
+        // dup ref
+        lua_pushvalue(L, -2);
+        // set: registry[key] = ref
+        lua_settable(L, LUA_REGISTRYINDEX);
+    }
+}
+
+// leaves 1 item on the stack (ref table or nil)
+// uses 1 slot
+static inline void lookup_registry_table(lua_State* L, void* p)
+{
+    lua_pushlightuserdata(L, p);
+    lua_gettable(L, LUA_REGISTRYINDEX);
+}
+
+// leaves nothing extra on the stack
+// uses 1 slot
+static inline void add_entry(lua_State* L, const char* key, int index, int table)
+{
+    lua_pushvalue(L, index);
+    lua_setfield(L, table, key);
+}
+
+// leaves nothing extra on the stack
+// uses 1 slot
+static inline void remove_entry(lua_State* L, const char* key, int table)
+{
+    lua_pushnil(L);
+    lua_setfield(L, table, key);
+}
+
+namespace Lua
+{
+void add_ref(lua_State* L, void* owner, const char* key, int ref_index)
+{
+    Lua::ManageStack ms(L, 4);
+    create_registry_table(L, owner);
+    add_entry(L, key, ref_index, lua_gettop(L));
+}
+
+void remove_ref(lua_State* L, void* owner, const char* key)
+{
+    Lua::ManageStack ms(L, 2);
+    lookup_registry_table(L, owner);
+    if ( !lua_isnil(L, -1) )
+        remove_entry(L, key, lua_gettop(L));
+}
+
+void remove_refs(lua_State* L, void* owner)
+{
+    Lua::ManageStack ms(L, 2);
+    lua_pushlightuserdata(L, owner);
+    lua_pushnil(L);
+    lua_settable(L, LUA_REGISTRYINDEX);
+}
+}
similarity index 74%
rename from src/piglet_plugins/pp_raw_data_iface.h
rename to src/lua/lua_ref.h
index 7a9f4946cad47a1eb4e62baff2617294097e26f4..78449d424db1ad400039f71a0941c2cd284b82b6 100644 (file)
 // with this program; if not, write to the Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
-// pp_raw_data_iface.h author Joel Cornett <jocornet@cisco.com>
+// lua_ref.h author Joel Cornett <jocornet@cisco.com>
 
-#ifndef PP_RAW_DATA_IFACE_H
-#define PP_RAW_DATA_IFACE_H
+#ifndef LUA_REF_H
+#define LUA_REF_H
 
-#include "lua/lua_iface.h"
+// Keep references to C objects in Lua to prevent premature garbage collection
 
-struct RawData;
-
-extern const struct Lua::TypeInterface<RawData> RawDataIface;
+struct lua_State;
 
+namespace Lua
+{
+void add_ref(lua_State*, void*, const char*, int);
+void remove_ref(lua_State*, void*, const char*);
+void remove_refs(lua_State*, void*);
+}
 #endif
index a59a824197d6eceee587236bc99f6c4b3acb0da0..e7d0b2a4336bf48a1b8d309d269cad569deb52b9 100644 (file)
 
 #include <string>
 #include <type_traits>
-
 #include <luajit-2.0/lua.hpp>
 
-#include "lua_util.h"
-
 namespace Lua
 {
-template<typename T, typename Integral = void>
+template<typename T>
+static inline constexpr bool IsInteger()
+{ return std::is_integral<T>::value && !std::is_same<T, bool>::value; }
+
+template<typename T, typename Integral = void, typename Unsigned = void>
 struct Stack {};
 
+// unsigned integer
 template<typename T>
-struct Stack<T, typename std::enable_if<std::is_integral<T>::value>::type>
+struct Stack<T, typename std::enable_if<IsInteger<T>()>::type,
+    typename std::enable_if<std::is_unsigned<T>::value>::type>
 {
     static inline void push(lua_State* L, const T& v)
-    { lua_pushnumber(L, v); }
+    { lua_pushinteger(L, v); }
 
     static inline T get(lua_State* L, int n)
-    { return lua_tonumber(L, n); }
+    { return lua_tointeger(L, n); }
 
     static inline constexpr int type()
     { return LUA_TNUMBER; }
+
+    static inline bool validate(lua_State* L, int n, T& v)
+    {
+        if ( lua_type(L, n) != type() )
+            return false;
+
+        lua_Integer tmp = lua_tointeger(L, n);
+        if ( tmp < 0 )
+            return false;
+
+        v = tmp;
+        return true;
+    }
+
+    static inline bool validate(lua_State* L, int n)
+    {
+        T v;
+        return validate(L, n, v);
+    }
 };
 
-template<>
-struct Stack<const char*>
+// integer
+template<typename T>
+struct Stack<T, typename std::enable_if<IsInteger<T>()>::type,
+    typename std::enable_if<!std::is_unsigned<T>::value>::type>
 {
-    static inline void push(lua_State* L, const char* v)
-    { lua_pushstring(L, v); }
+    static inline void push(lua_State* L, const T& v)
+    { lua_pushinteger(L, v); }
 
-    static inline const char* get(lua_State* L, int n)
-    { return lua_tostring(L, n); }
+    static inline T get(lua_State* L, int n)
+    { return lua_tointeger(L, n); }
 
     static inline constexpr int type()
-    { return LUA_TSTRING; }
+    { return LUA_TNUMBER; }
+
+    static inline bool validate(lua_State* L, int n, T& v)
+    {
+        if ( lua_type(L, n) != type() )
+            return false;
+
+        v = lua_tointeger(L, n);
+        return true;
+    }
+
+    static inline bool validate(lua_State* L, int n)
+    {
+        T v;
+        return validate(L, n, v);
+    }
 };
 
-template<>
-struct Stack<std::string>
+// default
+template<typename T>
+struct Stack<T, typename std::enable_if<!IsInteger<T>()>::type>
 {
-    static inline void push(lua_State* L, const std::string& v)
-    { lua_pushlstring(L, v.c_str(), v.size()); }
+    static inline void push(lua_State*, T);
+    static inline void push(lua_State*, T, size_t);
+
+    static inline T get(lua_State*, int);
+    static inline T get(lua_State*, int, size_t&);
 
-    static inline std::string get(lua_State* L, int n)
+    static inline constexpr int type();
+
+    static inline bool validate(lua_State* L, int n, T& v)
     {
-        size_t len = 0;
-        const char* s = lua_tolstring(L, n, &len);
-        return std::string(s, len);
+        if ( lua_type(L, n) != type() )
+            return false;
+
+        v = get(L, n);
+        return true;
     }
 
-    static inline constexpr int type()
-    { return LUA_TSTRING; }
+    static inline bool validate(lua_State* L, int n)
+    {
+        T v;
+        return validate(L, n, v);
+    }
+
+    static inline bool validate(lua_State*, int, T&, size_t&);
 };
 
+// const char*
+template<>
+inline void Stack<const char*>::push(lua_State* L, const char* s)
+{ lua_pushstring(L, s); }
+
+template<>
+inline void Stack<const char*>::push(lua_State* L, const char* s, size_t len)
+{ lua_pushlstring(L, s, len); }
+
 template<>
-struct Stack<bool>
+inline const char* Stack<const char*>::get(lua_State* L, int n)
+{ return lua_tostring(L, n); }
+
+template<>
+inline const char* Stack<const char*>::get(lua_State* L, int n, size_t& len)
+{ return lua_tolstring(L, n, &len); }
+
+template<>
+inline constexpr int Stack<const char*>::type()
+{ return LUA_TSTRING; }
+
+template<>
+inline bool Stack<const char*>::validate(
+    lua_State* L, int n, const char*& v, size_t& len)
 {
-    static inline void push(lua_State* L, const bool& v)
-    { lua_pushboolean(L, v); }
+    if ( lua_type(L, n) != type() )
+        return false;
 
-    static inline bool get(lua_State* L, int n)
-    { return lua_toboolean(L, n); }
+    v = get(L, n, len);
+    return true;
+}
 
-    static inline constexpr int type()
-    { return LUA_TBOOLEAN; }
-};
+// string
+template<>
+inline void Stack<std::string>::push(lua_State* L, std::string s)
+{ lua_pushlstring(L, s.c_str(), s.length()); }
+
+template<>
+inline std::string Stack<std::string>::get(lua_State* L, int n)
+{
+    size_t len = 0;
+    const char* s = lua_tolstring(L, n, &len);
+    return std::string(s, len);
+}
+
+template<>
+inline constexpr int Stack<std::string>::type()
+{ return LUA_TSTRING; }
+
+// bool
+template<>
+inline void Stack<bool>::push(lua_State* L, bool v)
+{ lua_pushboolean(L, v); }
+
+template<>
+inline bool Stack<bool>::get(lua_State* L, int n)
+{ return lua_toboolean(L, n); }
+
+template<>
+inline constexpr int Stack<bool>::type()
+{ return LUA_TBOOLEAN; }
 }
 #endif
index 771c830420755ec939f0c7722501935fbd327128..fd4e689d2fb8584ed20afd5d84118db0cfc6c057 100644 (file)
@@ -75,6 +75,18 @@ struct Table
         return rv;
     }
 
+    template<typename T>
+    inline bool get_default(const char* k, T& v, T d = 0)
+    {
+        if ( !get_field<T>(k, v) )
+        {
+            v = d;
+            return false;
+        }
+
+        return true;
+    }
+
     template<typename T>
     inline bool raw_get_field(const char* k, T& v)
     {
index 3312e0592d5ac530ed94fdc6a679ba154089c118..b7a2216558dd95886073f0e28f0841517753c540 100644 (file)
@@ -26,9 +26,9 @@
 #include <luajit-2.0/lua.hpp>
 
 #include "ips_manager.h"
+#include "plugin_manager.h"
 #include "lua/lua.h"
 #include "lua/lua_util.h"
-#include "plugin_manager.h"
 #include "framework/ips_option.h"
 #include "framework/logger.h"
 #include "framework/lua_api.h"
index c5c762aa6e4494822f480a522d5aa7ac538e8b80..f121b1efc099897a62094603ebed633fe7eed3ea 100644 (file)
@@ -78,7 +78,8 @@ static const Api* find_piglet(PlugType key)
     return nullptr;
 }
 
-static BasePlugin* instantiate(Lua::State& lua, PlugType key, std::string name)
+static BasePlugin* instantiate(
+    Lua::State& lua, PlugType key, std::string name, bool use_defaults)
 {
     auto piglet_api = find_piglet(key);
 
@@ -93,8 +94,7 @@ static BasePlugin* instantiate(Lua::State& lua, PlugType key, std::string name)
     }
 
     Module* m;
-
-    if ( key == PT_IPS_OPTION )
+    if ( key == PT_IPS_OPTION || use_defaults )
         // FIXIT-M: this is just a workaround.
         // Need to be able to get parsed rule module
         m = ModuleManager::get_default_module(name.c_str(), snort_conf);
@@ -124,7 +124,8 @@ void Manager::add_plugin(Api* api)
 { plugins[api->target] = api; }
 
 BasePlugin* Manager::instantiate(
-    Lua::State& lua, const string& target, string& type, string& name)
+    Lua::State& lua, const string& target,
+    string& type, string& name, bool use_defaults)
 {
     PlugType pt = PT_MAX;
     split_key(target, type, name);
@@ -150,7 +151,7 @@ BasePlugin* Manager::instantiate(
         return nullptr;
     }
 
-    return ::Piglet::instantiate(lua, pt, name);
+    return ::Piglet::instantiate(lua, pt, name, use_defaults);
 }
 
 void Manager::destroy(BasePlugin* p)
index 4f7ebad7881883f47477171ad26779a063642bb7..be34f76bf4cc0b74b191686da9a96a66a7c65919 100644 (file)
@@ -47,7 +47,8 @@ public:
     static void add_plugin(Api*);
 
     static BasePlugin* instantiate(
-        Lua::State&, const std::string&, std::string&, std::string&);
+        Lua::State&, const std::string&,
+        std::string&, std::string&, bool = false);
 
     static void destroy(BasePlugin*);
 
index a9d0eef75f5e7e4d14d14993306ac8e34d90e8cf..f1a932a1b006dc8f79796bfb3d392d39020528ad 100644 (file)
@@ -51,6 +51,12 @@ static bool configure_test(lua_State* L, Test& t)
 {
     Lua::ManageStack ms(L);
 
+    if ( setup_globals(L, t) )
+    {
+        t.set_error("couldn't setup globals");
+        return true;
+    }
+
     if ( load_chunk(L, t.chunk) )
     {
         t.set_error("couldn't load test chunk");
@@ -75,8 +81,9 @@ static bool configure_test(lua_State* L, Test& t)
 
     Lua::Table table(L, -1);
     table.get_field("description", t.description);
+    table.get_field("use_defaults", t.use_defaults);
 
-    return setup_globals(L, t);
+    return false;
 }
 
 static bool run_test(lua_State* L, Test& t)
@@ -125,7 +132,8 @@ void Runner::run(const struct Output& output, Test& t, unsigned i)
         return;
     }
 
-    auto p = Manager::instantiate(state, t.chunk.target, t.type, t.name);
+    auto p = Manager::instantiate(
+        state, t.chunk.target, t.type, t.name, t.use_defaults);
 
     // FIXIT-L: This injection is a hack so we can log the test header
     //          with all the parsed information filled in
index be575ef65c2f49166650b6c0617792e263e53f1e..9f60638d2192110507f7ee50aee061c269de1c98 100644 (file)
@@ -88,6 +88,7 @@ struct Test
     std::string type;
     std::string name;
     std::string description;
+    bool use_defaults = false;
 
     std::vector<std::string> messages;
 
index 8a2fa33efb47435bfaea0104af8da5cb2447eb2a..51cf2375f97e641d683526a15b66b3701a20fc59 100644 (file)
@@ -1,7 +1,6 @@
 set (
     PP_CODEC_DEPENDENCIES
     pp_codec_data_iface.cc
-    pp_raw_data_iface.cc
     pp_enc_state_iface.cc
     pp_buffer_iface.cc
     pp_event_iface.cc
index be6ea00ec7bbdae7d8adc4263f9b62f8eeb06b49..e2653f2b1d6ea62ca16ab86db81462adb3e936cc 100644 (file)
@@ -7,7 +7,6 @@ piglet_plugins.h
 
 interface_list = \
 pp_codec_data_iface.cc \
-pp_raw_data_iface.cc \
 pp_enc_state_iface.cc \
 pp_buffer_iface.cc \
 pp_event_iface.cc \
index 0aa1e79a8298a383dd654dbe930e4df0cc30f90b..646137ef778ce3d19489bfc8f19671d402d3e498 100644 (file)
@@ -3,5 +3,5 @@ each Snort plugin type. Each pp_\*.cc source file is a Snort plugin proper.
 
 piglet_plugins_common contains utilities for working with the Lua C API and
 Lua interfaces for some useful Snort data structures (Packet, DecodeData).
-There is also an interface called RawData.  This is essentially a wrapper
-around a vector<char>.
+There is also an interface called RawBuffer.  This is essentially a wrapper
+around a std::string.
index 7fae7d56530aa43b36d6eec9d8ec0414536de2c7..058af769afe0e866d9fd32435e6022baa441031c 100644 (file)
@@ -22,6 +22,8 @@
 #include <luajit-2.0/lua.hpp>
 
 #include "framework/codec.h"
+#include "lua/lua_arg.h"
+#include "lua/lua_ref.h"
 #include "pp_raw_buffer_iface.h"
 
 static const luaL_Reg methods[] =
@@ -30,19 +32,61 @@ static const luaL_Reg methods[] =
         "new",
         [](lua_State* L)
         {
-            // FIXIT-M: need a way to track refs to other
-            //          objs in lua so the don't get gc'd too early
-            auto& rb = RawBufferIface.get(L);
-            BufferIface.create(
-                L,
-                const_cast<uint8_t*>(
-                    reinterpret_cast<const uint8_t*>(rb.data())),
-                rb.size()
-            );
+            Lua::Args args(L);
+
+            RawBuffer* rb;
+            size_t len;
+            int idx = 1;
+
+            if ( args[1].is_string() )
+            {
+                // Create a RawBuffer object to back the string
+                len = 0;
+                const char* s = args[1].check_string(len);
+                rb = &RawBufferIface.create(L, s, len);
+                idx = lua_gettop(L);
+            }
+            else if ( args[1].is_size() )
+            {
+                len = args[1].check_size();
+                // Create a RawBuffer object to back the string
+                rb = &RawBufferIface.create(L, len, '\0');
+                idx = lua_gettop(L);
+            }
+            else
+            {
+                rb = &RawBufferIface.get(L, 1);
+            }
+
+            auto& self = BufferIface.create(L, get_mutable_data(*rb), rb->size());
+            // Save a reference to the RawBuffer
+            // FIXIT-M: Integrate this into the interface code so we don't
+            // have to do this explicitly
+            Lua::add_ref(L, &self, "data", idx);
 
             return 1;
         }
     },
+    {
+        "allocate",
+        [](lua_State* L)
+        {
+            Lua::Args args(L);
+            auto& self = BufferIface.get(L, 1);
+            uint32_t len = args[2].check_size();
+            bool result = self.allocate(len);
+            lua_pushboolean(L, result);
+            return 1;
+        }
+    },
+    {
+        "clear",
+        [](lua_State* L)
+        {
+            BufferIface.get(L).clear();
+            return 0;
+        }
+    },
     { nullptr, nullptr }
 };
 
@@ -53,7 +97,9 @@ static const luaL_Reg metamethods[] =
         [](lua_State* L)
         {
             auto& self = BufferIface.get(L);
-            lua_pushfstring(L, "%s@%p", BufferIface.name, &self);
+            lua_pushlstring(L, reinterpret_cast<const char*>(self.data()),
+                self.size());
+            // lua_pushfstring(L, "%s@%p", BufferIface.name, &self);
 
             return 1;
         }
index a93ef6287fdfc04598d3b67a559d6f2d2802778f..5abc40796ec8995dff5640af6ae9d0fb2295de43 100644 (file)
@@ -31,7 +31,6 @@
 #include "pp_decode_data_iface.h"
 #include "pp_enc_state_iface.h"
 #include "pp_raw_buffer_iface.h"
-#include "pp_raw_data_iface.h"
 
 #include "pp_codec_iface.h"
 
@@ -64,7 +63,6 @@ bool CodecPiglet::setup()
 
     install(L, RawBufferIface);
     install(L, DecodeDataIface);
-    install(L, RawDataIface);
     install(L, CodecDataIface);
     install(L, EncStateIface);
     install(L, BufferIface);
index 4ca1fadc3a4aa9faa809ead3dc864537172b520a..6f4f9c5fa969f7713185bbfc5ca2768f72445394 100644 (file)
 
 #include "pp_codec_data_iface.h"
 
+#include <string.h>
 #include <luajit-2.0/lua.hpp>
 
 #include "framework/codec.h"
 #include "lua/lua_table.h"
 #include "lua/lua_arg.h"
 
-static void set_fields(lua_State* L, int tindex, CodecData& cd)
+static void set_fields(lua_State* L, int tindex, CodecData& self)
 {
     Lua::Table table(L, tindex);
 
-    table.get_field("next_prot_id", cd.next_prot_id);
-    table.get_field("lyr_len", cd.lyr_len);
-    table.get_field("invalid_bytes", cd.invalid_bytes);
-    table.get_field("proto_bits", cd.proto_bits);
-    table.get_field("codec_flags", cd.codec_flags);
-    table.get_field("ip_layer_cnt", cd.ip_layer_cnt);
-    table.get_field("ip6_extension_count", cd.ip6_extension_count);
-    table.get_field("curr_ip6_extension", cd.curr_ip6_extension);
-    table.get_field("ip6_csum_proto", cd.ip6_csum_proto);
+    table.get_field("next_prot_id", self.next_prot_id);
+    table.get_field("lyr_len", self.lyr_len);
+    table.get_field("invalid_bytes", self.invalid_bytes);
+    table.get_field("proto_bits", self.proto_bits);
+    table.get_field("codec_flags", self.codec_flags);
+    table.get_field("ip_layer_cnt", self.ip_layer_cnt);
+    table.get_field("ip6_extension_count", self.ip6_extension_count);
+    table.get_field("curr_ip6_extension", self.curr_ip6_extension);
+    table.get_field("ip6_csum_proto", self.ip6_csum_proto);
+}
+
+static void get_fields(lua_State* L, int tindex, CodecData& self)
+{
+    Lua::Table table(L, tindex);
+
+    table.set_field("next_prot_id", self.next_prot_id);
+    table.set_field("lyr_len", self.lyr_len);
+    table.set_field("invalid_bytes", self.invalid_bytes);
+    table.set_field("proto_bits", self.proto_bits);
+    table.set_field("codec_flags", self.codec_flags);
+    table.set_field("ip_layer_cnt", self.ip_layer_cnt);
+    table.set_field("ip6_extension_count", self.ip6_extension_count);
+    table.set_field("curr_ip6_extension", self.curr_ip6_extension);
+    table.set_field("ip6_csum_proto", self.ip6_csum_proto);
 }
 
 static const luaL_Reg methods[] =
@@ -46,17 +62,15 @@ static const luaL_Reg methods[] =
         "new",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = CodecDataIface.create(L, 0);
+            memset(&self, 0, sizeof(self));
 
-            if ( arg.count )
-            {
-                if ( arg.is_table(1) )
-                    set_fields(L, 1, self);
-                else
-                    self.next_prot_id = arg.check_size(1);
-            }
+            if ( args[1].is_table() )
+                args[1].check_table(set_fields, self);
+            else if ( args[1].is_size() )
+                self.next_prot_id = args[1].check_size();
 
             return 1;
         }
@@ -64,38 +78,12 @@ static const luaL_Reg methods[] =
     {
         "get",
         [](lua_State* L)
-        {
-            auto& self = CodecDataIface.get(L);
-            lua_newtable(L);
-
-            Lua::Table table(L, lua_gettop(L));
-
-            table.set_field("next_prot_id", self.next_prot_id);
-            table.set_field("lyr_len", self.lyr_len);
-            table.set_field("invalid_bytes", self.invalid_bytes);
-            table.set_field("proto_bits", self.proto_bits);
-            table.set_field("codec_flags", self.codec_flags);
-            table.set_field("ip_layer_cnt", self.ip_layer_cnt);
-            table.set_field("ip6_extension_count", self.ip6_extension_count);
-            table.set_field("curr_ip6_extension", self.curr_ip6_extension);
-            table.set_field("ip6_csum_proto", self.ip6_csum_proto);
-
-            return 1;
-        }
+        { return CodecDataIface.default_getter(L, get_fields); }
     },
     {
         "set",
         [](lua_State* L)
-        {
-            Lua::Arg arg(L);
-
-            auto& self = CodecDataIface.get(L, 1);
-
-            arg.check_table(2);
-            set_fields(L, 2, self);
-
-            return 0;
-        }
+        { return CodecDataIface.default_setter(L, set_fields); }
     },
     { nullptr, nullptr }
 };
@@ -105,20 +93,12 @@ static const luaL_Reg metamethods[] =
     {
         "__tostring",
         [](lua_State* L)
-        {
-            auto& self = CodecDataIface.get(L);
-            lua_pushfstring(L, "%s@%p", CodecDataIface.name, &self);
-
-            return 1;
-        }
+        { return CodecDataIface.default_tostring(L); }
     },
     {
         "__gc",
         [](lua_State* L)
-        {
-            CodecDataIface.destroy(L);
-            return 0;
-        }
+        { return CodecDataIface.default_gc(L); }
     },
     { nullptr, nullptr }
 };
index fb63bc434254f0ac8c4ac0bc5f0eff381ca5acff..af91e8629314f17e65045afbf1639b088cc073ab 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <limits>
 #include <vector>
+#include <assert.h>
 #include <luajit-2.0/lua.hpp>
 
 #include "framework/codec.h"
 
 #include "pp_buffer_iface.h"
 #include "pp_codec_data_iface.h"
+#include "pp_daq_pkthdr_iface.h"
 #include "pp_decode_data_iface.h"
 #include "pp_enc_state_iface.h"
 #include "pp_raw_buffer_iface.h"
-#include "pp_raw_data_iface.h"
-
-static std::vector<int> data_link_types;
-static std::vector<uint16_t> protocol_ids;
 
+// FIXIT-M: This should be its own object
 static const ip::IpApi ip_api {};
 
 struct TextLogWrapper
@@ -46,7 +45,10 @@ struct TextLogWrapper
     TextLog* text_log;
 
     TextLogWrapper(const char* name)
-    { text_log = TextLog_Init(name); }
+    {
+        text_log = TextLog_Init(name);
+        assert(text_log);
+    }
 
     ~TextLogWrapper()
     {
@@ -91,13 +93,32 @@ static const luaL_Reg methods[] =
         "decode",
         [](lua_State* L)
         {
-            auto& rd = RawDataIface.get(L, 1);
-            auto& cd = CodecDataIface.get(L, 2);
-            auto& dd = DecodeDataIface.get(L, 3);
+            bool result;
+
+            auto& daq = DAQHeaderIface.get(L, 1);
+            auto& cd = CodecDataIface.get(L, 3);
+            auto& dd = DecodeDataIface.get(L, 4);
 
             auto& self = CodecIface.get(L);
 
-            bool result = self.decode(rd, cd, dd);
+            if ( RawBufferIface.is(L, 2) )
+            {
+                RawData rd(&daq, get_data(RawBufferIface.get(L, 2)));
+                result = self.decode(rd, cd, dd);
+            }
+            else
+            {
+                size_t len = 0;
+                RawData rd(
+                    &daq,
+                    reinterpret_cast<const uint8_t*>(
+                        luaL_checklstring(L, 2, &len)
+                    )
+                );
+
+                result = self.decode(rd, cd, dd);
+            }
+
             lua_pushboolean(L, result);
 
             return 1;
@@ -107,20 +128,15 @@ static const luaL_Reg methods[] =
         "log",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& rb = RawBufferIface.get(L, 1);
-            uint16_t lyr_len = arg.opt_size(2, rb.size(), rb.size());
+            uint16_t lyr_len = args[2].opt_size(rb.size(), rb.size());
 
             auto& self = CodecIface.get(L);
 
             TextLogWrapper tl_wrap("stdout");
-            // FIXIT-L: Do we need to check for null tl_wrap.text_log?
-            self.log(
-                tl_wrap.text_log,
-                reinterpret_cast<const uint8_t*>(rb.data()),
-                lyr_len
-            );
+            self.log(tl_wrap.text_log, get_data(rb), lyr_len);
 
             return 0;
         }
@@ -135,8 +151,7 @@ static const luaL_Reg methods[] =
 
             auto& self = CodecIface.get(L);
 
-            bool result = self.encode(
-                reinterpret_cast<const uint8_t*>(rb.data()), rb.size(), es, b);
+            bool result = self.encode(get_data(rb), rb.size(), es, b);
 
             lua_pushboolean(L, result);
 
@@ -147,23 +162,23 @@ static const luaL_Reg methods[] =
         "update",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
-            // FIXIT-M: We can't represent all flags int lua_Integer type
-            uint64_t flags = arg.check_size(1);
-            auto& rb = RawBufferIface.get(L, 2);
-            uint16_t lyr_len = arg.opt_size(3, 0, rb.size());
+            uint32_t flags_hi = args[1].check_size();
+            uint32_t flags_lo = args[2].check_size();
+            auto& rb = RawBufferIface.get(L, 3);
+
+            // FIXIT-L: Args vs Iface is not orthogonal
+            uint16_t lyr_len = args[4].opt_size(0, rb.size());
 
             auto& self = CodecIface.get(L);
 
             uint32_t updated_len = 0;
 
-            self.update(
-                ip_api, flags,
-                const_cast<uint8_t*>(
-                    reinterpret_cast<const uint8_t*>(rb.data())),
-                lyr_len, updated_len
-            );
+            uint64_t flags = (static_cast<uint64_t>(flags_hi) << 8) | flags_lo;
+
+            self.update(ip_api, flags, get_mutable_data(rb), lyr_len,
+                updated_len);
 
             lua_pushinteger(L, updated_len);
 
@@ -174,17 +189,15 @@ static const luaL_Reg methods[] =
         "format",
         [](lua_State* L)
         {
-            bool reverse = lua_toboolean(L, 1);
+            Lua::Args args(L);
+
+            bool reverse = args[1].get_bool();
             auto& rb = RawBufferIface.get(L, 2);
             auto& dd = DecodeDataIface.get(L, 3);
 
             auto& self = CodecIface.get(L);
-            self.format(
-                reverse,
-                const_cast<uint8_t*>(
-                    reinterpret_cast<const uint8_t*>(rb.data())),
-                dd
-            );
+
+            self.format(reverse, get_mutable_data(rb), dd);
 
             return 0;
         }
index 32002bbcc13df8312afbc42b9c7615efc5f7b78c..2f099fa1e8753e980c1a9ab44670ce4daa155db6 100644 (file)
 #include <luajit-2.0/lua.hpp>
 
 #include "framework/cursor.h"
+#include "lua/lua_arg.h"
+#include "lua/lua_ref.h"
+#include "protocols/packet.h"
 #include "pp_packet_iface.h"
+#include "pp_raw_buffer_iface.h"
+
+static void reset_from_packet(
+    lua_State* L, Cursor& self, Packet& p, int p_idx)
+{
+    self.reset(&p);
+    Lua::add_ref(L, &self, "data", p_idx);
+}
+
+static void reset_from_raw_buffer(
+    lua_State* L, Cursor& self, RawBuffer& rb, int rb_idx)
+{
+    Packet p;
+    p.reset();
+
+    p.data = get_data(rb);
+    p.dsize = rb.size();
+
+    self.reset(&p);
+    Lua::add_ref(L, &self, "data", rb_idx);
+}
 
 static const luaL_Reg methods[] =
 {
@@ -30,12 +54,79 @@ static const luaL_Reg methods[] =
         "new",
         [](lua_State* L)
         {
-            auto& p = PacketIface.get(L);
-            CursorIface.create(L, &p);
+            Lua::Args args(L);
+            Packet p;
+            p.reset();
+
+            auto& self = CursorIface.create(L, &p);
+
+            if ( args.count )
+            {
+                if ( PacketIface.is(L, 1) )
+                {
+                    reset_from_packet(L, self, PacketIface.get(L, 1), 1);
+                }
+                else if ( args[1].is_string() )
+                {
+                    size_t len = 0;
+                    const char* s = args[1].check_string(len);
+                    auto& rb = RawBufferIface.create(L, s, len);
+                    reset_from_raw_buffer(L, self, rb, lua_gettop(L));
+                    lua_pop(L, 1);
+                }
+                else
+                {
+                    reset_from_raw_buffer(L, self, RawBufferIface.get(L, 1), 1);
+                }
+            }
 
             return 1;
         }
     },
+    {
+        "reset",
+        [](lua_State* L)
+        {
+            Lua::Args args(L);
+
+            auto& self = CursorIface.get(L, 1);
+
+            if ( args.count > 1 )
+            {
+                if ( PacketIface.is(L, 2) )
+                {
+                    auto& p = PacketIface.get(L, 2);
+                    reset_from_packet(L, self, p, 2);
+                }
+                else
+                {
+                    if ( args[2].is_string() )
+                    {
+                        size_t len = 0;
+                        const char* s = args[2].check_string(len);
+                        auto& rb = RawBufferIface.create(L, s, len);
+                        reset_from_raw_buffer(L, self, rb, lua_gettop(L));
+                    }
+                    else
+                    {
+                        auto& rb = RawBufferIface.get(L, 2);
+                        reset_from_raw_buffer(L, self, rb, 2);
+                    }
+                }
+            }
+            else
+            {
+                Packet p;
+
+                p.reset();
+                self.reset(&p);
+
+                Lua::remove_ref(L, &self, "data");
+            }
+
+            return 0;
+        }
+    },
     { nullptr, nullptr }
 };
 
@@ -44,20 +135,12 @@ static const luaL_Reg metamethods[] =
     {
         "__tostring",
         [](lua_State* L)
-        {
-            auto& self = CursorIface.get(L);
-            lua_pushfstring(L, "%s@%p", CursorIface.name, &self);
-
-            return 1;
-        }
+        { return CursorIface.default_tostring(L); }
     },
     {
         "__gc",
         [](lua_State* L)
-        {
-            CursorIface.destroy(L);
-            return 0;
-        }
+        { return CursorIface.default_gc(L); }
     },
     { nullptr, nullptr }
 };
index 53a659f2f46fc6bf809f26ce7fef8927527fb1f5..ecb12e8978ebf2928d6422d5278283cb61db1ba9 100644 (file)
@@ -15,7 +15,7 @@
 // with this program; if not, write to the Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
-// pp_daq_pkthdr_iface.cc author Joel Cornett <jocornet@cisco.com>
+// pp_codec_data_iface.cc author Joel Cornett <jocornet@cisco.com>
 
 #include "pp_daq_pkthdr_iface.h"
 
 #include "config.h"
 #endif
 
+#include <string.h>
 #include <luajit-2.0/lua.hpp>
 
-#include "lua/lua_table.h"
-
 extern "C" {
 #include <daq.h>
 }
 
-static void daq_header_set(lua_State* L, int tindex, struct _daq_pkthdr& daq)
+#include "lua/lua_arg.h"
+#include "lua/lua_table.h"
+
+
+static void set_fields(lua_State* L, int tindex, struct _daq_pkthdr& self)
 {
     Lua::Table table(L, tindex);
 
-    table.get_field("caplen", daq.caplen);
-    table.get_field("pktlen", daq.pktlen);
-    table.get_field("ingress_index", daq.ingress_index);
-    table.get_field("egress_index", daq.egress_index);
-    table.get_field("ingress_group", daq.ingress_group);
-    table.get_field("egress_group", daq.egress_group);
-    table.get_field("flags", daq.flags);
-    table.get_field("opaque", daq.opaque);
+    table.get_field("caplen", self.caplen);
+    table.get_field("pktlen", self.pktlen);
+    table.get_field("ingress_index", self.ingress_index);
+    table.get_field("egress_index", self.egress_index);
+    table.get_field("ingress_group", self.ingress_group);
+    table.get_field("egress_group", self.egress_group);
+    table.get_field("flags", self.flags);
+    table.get_field("opaque", self.opaque);
 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
 #ifdef HAVE_DAQ_FLOW_ID
-    table.get_field("flow_id", daq.flow_id);
+    table.get_field("flow_id", self.flow_id);
 #endif
-    table.get_field("address_space_id", daq.address_space_id);
+    table.get_field("address_space_id", self.address_space_id);
 #endif
 
     // FIXIT-L: Do we want to be able to set the priv_ptr field?
 }
 
+static void get_fields(lua_State* L, int tindex, struct _daq_pkthdr& self)
+{
+    Lua::Table table(L, tindex);
+
+    table.set_field("caplen", self.caplen);
+    table.set_field("pktlen", self.pktlen);
+    table.set_field("ingress_index", self.ingress_index);
+    table.set_field("egress_index", self.egress_index);
+    table.set_field("ingress_group", self.ingress_group);
+    table.set_field("egress_group", self.egress_group);
+    table.set_field("flags", self.flags);
+    table.set_field("opaque", self.opaque);
+#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
+#ifdef HAVE_DAQ_FLOW_ID
+    table.set_field("flow_id", self.flow_id);
+#endif
+    table.set_field("address_space_id", self.address_space_id);
+#endif
+}
+
 static const luaL_Reg methods[] =
 {
     {
         "new",
         [](lua_State* L)
         {
+            Lua::Args args(L);
+
             auto& self = DAQHeaderIface.create(L);
+            memset(&self, 0, sizeof(self));
 
-            // If we had an initializer argument, there
-            // will be two items on the stack now
-            if ( lua_gettop(L) > 1 )
-            {
-                luaL_checktype(L, 1, LUA_TTABLE);
-                daq_header_set(L, 1, self);
-            }
+            args[1].opt_table(set_fields, self);
 
             return 1;
         }
@@ -75,43 +95,12 @@ static const luaL_Reg methods[] =
     {
         "get",
         [](lua_State* L)
-        {
-            auto& self = DAQHeaderIface.get(L);
-            lua_newtable(L);
-
-            Lua::Table table(L, lua_gettop(L));
-
-            table.set_field("caplen", self.caplen);
-            table.set_field("pktlen", self.pktlen);
-            table.set_field("ingress_index", self.ingress_index);
-            table.set_field("egress_index", self.egress_index);
-            table.set_field("ingress_group", self.ingress_group);
-            table.set_field("egress_group", self.egress_group);
-            table.set_field("flags", self.flags);
-            table.set_field("opaque", self.opaque);
-#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
-#ifdef HAVE_DAQ_FLOW_ID
-            table.set_field("flow_id", self.flow_id);
-#endif
-            table.set_field("address_space_id", self.address_space_id);
-#endif
-
-            // FIXIT-L: Do we want to be able to read the priv_ptr field?
-
-            return 1;
-        }
+        { return DAQHeaderIface.default_getter(L, get_fields); }
     },
     {
         "set",
         [](lua_State* L)
-        {
-            auto& self = DAQHeaderIface.get(L, 1);
-            luaL_checktype(L, 2, LUA_TTABLE);
-
-            daq_header_set(L, 2, self);
-
-            return 0;
-        }
+        { return DAQHeaderIface.default_setter(L, set_fields); }
     },
     { nullptr, nullptr }
 };
@@ -121,20 +110,12 @@ static const luaL_Reg metamethods[] =
     {
         "__tostring",
         [](lua_State* L)
-        {
-            auto& self = DAQHeaderIface.get(L);
-            lua_pushfstring(L, "%s@%p", DAQHeaderIface.name, &self);
-
-            return 1;
-        }
+        { return DAQHeaderIface.default_tostring(L); }
     },
     {
         "__gc",
         [](lua_State* L)
-        {
-            DAQHeaderIface.destroy(L);
-            return 0;
-        }
+        { return DAQHeaderIface.default_gc(L); }
     },
     { nullptr, nullptr }
 };
index a2e39fff5deea28bf8b8703c08f1bf9bdfe6a433..9392191a74bf6234c5a4af3cb3c3d4b1dc3da7f4 100644 (file)
 
 #include "pp_decode_data_iface.h"
 
+#include <assert.h>
 #include <luajit-2.0/lua.hpp>
 
 #include "framework/decode_data.h"
 #include "lua/lua_arg.h"
 #include "lua/lua_table.h"
 #include "protocols/ipv4.h"
+// #include "protocols/tcp.h"
+// #include "protocols/udp.h"
+// #include "protocols/icmp4.h"
 
 #include "pp_raw_buffer_iface.h"
 
-static void set_fields(lua_State* L, int tindex, DecodeData& dd)
+// FIXIT-H: Add Internet Header objects
+// FIXIT-H: Add Enum Interface
+static void set_fields(lua_State* L, int tindex, DecodeData& self)
 {
     Lua::Table table(L, tindex);
 
-    table.get_field("sp", dd.sp);
-    table.get_field("dp", dd.dp);
-    table.get_field("decode_flags", dd.decode_flags);
+    table.get_field("sp", self.sp);
+    table.get_field("dp", self.dp);
+    table.get_field("decode_flags", self.decode_flags);
 
     uint8_t pkt_type = 0;
     table.get_field("type", pkt_type);
-    dd.type = static_cast<PktType>(pkt_type);
+    self.type = static_cast<PktType>(pkt_type);
+}
+
+static void get_fields(lua_State* L, int tindex, DecodeData& self)
+{
+    Lua::Table table(L, tindex);
+
+    table.set_field("sp", self.sp);
+    table.set_field("dp", self.dp);
+    table.set_field("decode_flags", self.decode_flags);
+    table.set_field("type", static_cast<uint8_t>(self.type));
 }
 
 static const luaL_Reg methods[] =
@@ -47,15 +63,12 @@ static const luaL_Reg methods[] =
         "new",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = DecodeDataIface.create(L);
+            self.reset();
 
-            if ( arg.count )
-            {
-                arg.check_table(1);
-                set_fields(L, 1, self);
-            }
+            args[1].opt_table(set_fields, self);
 
             return 1;
         }
@@ -64,55 +77,30 @@ static const luaL_Reg methods[] =
         "reset",
         [](lua_State* L)
         {
-            auto& self = DecodeDataIface.get(L);
-            self.reset();
-
+            DecodeDataIface.get(L).reset();
             return 0;
         }
     },
     {
         "set",
         [](lua_State* L)
-        {
-            Lua::Arg arg(L);
-
-            auto& self = DecodeDataIface.get(L, 1);
-
-            arg.check_table(2);
-            set_fields(L, 2, self);
-
-            return 0;
-        }
+        { return DecodeDataIface.default_setter(L, set_fields); }
     },
     {
         "get",
         [](lua_State* L)
-        {
-            auto& self = DecodeDataIface.get(L);
-            lua_newtable(L);
-
-            Lua::Table table(L, lua_gettop(L));
-            table.set_field("sp", self.sp);
-            table.set_field("dp", self.dp);
-            table.set_field("decode_flags", self.decode_flags);
-            table.set_field(
-                "type",
-                static_cast<uint8_t>(self.type)
-            );
-
-            return 1;
-        }
+        { return DecodeDataIface.default_getter(L, get_fields); }
     },
     // FIXIT-L: Need a more sophisticated interface to decode data ip_api
     {
         "set_ipv4_hdr",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = DecodeDataIface.get(L, 1);
             auto& rb = RawBufferIface.get(L, 2);
-            size_t offset = arg.opt_size(3, 0, rb.size());
+            size_t offset = args[3].opt_size(0, rb.size());
 
             // Need enough room for an IPv4 header
             if ( (rb.size() - offset) < sizeof(IP4Hdr) )
@@ -136,19 +124,12 @@ static const luaL_Reg metamethods[] =
     {
         "__tostring",
         [](lua_State* L)
-        {
-            auto& self = DecodeDataIface.get(L);
-            lua_pushfstring(L, "%s@%p", DecodeDataIface.name, &self);
-            return 1;
-        }
+        { return DecodeDataIface.default_tostring(L); }
     },
     {
         "__gc",
         [](lua_State* L)
-        {
-            DecodeDataIface.destroy(L);
-            return 0;
-        }
+        { return DecodeDataIface.default_gc(L); }
     },
     { nullptr, nullptr }
 };
index 102c1c2e2886b5449bc7e36279c59f020590e57d..777b3b518bbd952ac011867f1ab86a525ba885cc 100644 (file)
 #include <luajit-2.0/lua.hpp>
 
 #include "framework/codec.h"
+#include "lua/lua_arg.h"
 #include "protocols/ip.h"
 
+// FIXIT-H: This should also be its own object (copyable)
 static const class ip::IpApi ip_api {};
 
+static inline uint64_t get_encode_flag(uint32_t hi, uint32_t lo)
+{ return (static_cast<uint64_t>(hi) << 4) | lo; }
+
 static const luaL_Reg methods[] =
 {
     {
         "new",
         [](lua_State* L)
         {
-            EncStateIface.create(L, ip_api, 0, 0, 0, 0);
+            Lua::Args args(L);
+
+            uint32_t efl_hi = args[1].opt_size();
+            uint32_t efl_lo = args[2].opt_size();
+            uint8_t next_proto = args[3].opt_size();
+            uint8_t ttl = args[4].opt_size();
+            uint16_t dsize = args[5].opt_int();
+
+            EncStateIface.create(L, ip_api, get_encode_flag(efl_hi, efl_lo),
+                    next_proto, ttl, dsize);
+
             return 1;
         }
     },
+    // FIXIT-L: Add get and set methods
     { nullptr, nullptr }
 };
 
@@ -44,20 +60,12 @@ static const luaL_Reg metamethods[] =
     {
         "__tostring",
         [](lua_State* L)
-        {
-            auto& self = EncStateIface.get(L);
-            lua_pushfstring(L, "%s@%p", EncStateIface.name, &self);
-
-            return 1;
-        }
+        { return EncStateIface.default_tostring(L); }
     },
     {
         "__gc",
         [](lua_State* L)
-        {
-            EncStateIface.destroy(L);
-            return 0;
-        }
+        { return EncStateIface.default_gc(L); }
     },
     { nullptr, nullptr }
 };
index 7c15e864aac699318275c69cb95c94566a94c61a..a0da6231309d6eac337ce262dd7f4caca17e4641 100644 (file)
 
 #include "detection/signature.h"
 #include "events/event.h"
+#include "lua/lua_arg.h"
 #include "lua/lua_table.h"
+#include "pp_raw_buffer_iface.h"
 
+// FIXIT-H: Should be its own object
 static struct SigInfo* create_sig_info()
 {
     auto si = new SigInfo;
@@ -34,15 +37,49 @@ static struct SigInfo* create_sig_info()
     return si;
 }
 
+static void set_fields(lua_State* L, int tindex, Event& self)
+{
+    Lua::Table table(L, tindex);
+
+    table.get_field("event_id", self.event_id);
+    table.get_field("event_reference", self.event_reference);
+
+    const char* s = nullptr;
+    // FIXIT-L: Shouldn't need both conditions
+    if ( table.get_field("alt_msg", s) && s )
+    {
+        self.alt_msg = RawBufferIface.create(L, s).c_str();
+        Lua::add_ref(L, &self, "alt_msg", lua_gettop(L));
+        lua_pop(L, 1);
+    }
+}
+
+static void get_fields(lua_State* L, int tindex, Event& self)
+{
+    Lua::Table table(L, tindex);
+
+    table.set_field("event_id", self.event_id);
+    table.set_field("event_reference", self.event_reference);
+
+    if ( self.alt_msg )
+        table.set_field("alt_msg", self.alt_msg);
+}
+
 static const luaL_Reg methods[] =
 {
     {
         "new",
         [](lua_State* L)
         {
+            Lua::Args args(L);
+
             auto& self = EventIface.create(L);
+            // FIXIT-M: This should be a separate object
+            // (to make resource tracking more uniform)
             self.sig_info = create_sig_info();
 
+            args[1].opt_table(set_fields, self);
+
             return 1;
         }
     },
@@ -54,9 +91,7 @@ static const luaL_Reg methods[] =
             auto& self = EventIface.get(L);
             lua_newtable(L);
 
-            Lua::Table table(L, lua_gettop(L));
-            table.set_field("event_id", self.event_id);
-            table.set_field("event_reference", self.event_reference);
+            get_fields(L, lua_gettop(L), self);
 
             auto si = self.sig_info;
 
@@ -74,7 +109,7 @@ static const luaL_Reg methods[] =
                 si_table.set_field("text_rule", si->text_rule);
                 si_table.set_field("num_services", si->num_services);
 
-                table.set_field_from_stack("sig_info", si_table.index);
+                Lua::Table(L, 2).set_field_from_stack("sig_info", si_table.index);
             }
 
             return 1;
@@ -107,8 +142,7 @@ static const luaL_Reg methods[] =
                 si_table.get_field("num_services", si->num_services);
             }
 
-            table.get_field("event_id", self.event_id);
-            table.get_field("event_reference", self.event_reference);
+            set_fields(L, 2, self);
 
             return 0;
         }
@@ -121,12 +155,7 @@ static const luaL_Reg metamethods[] =
     {
         "__tostring",
         [](lua_State* L)
-        {
-            auto& self = EventIface.get(L);
-            lua_pushfstring(L, "%s@%p", EventIface.name, &self);
-
-            return 1;
-        }
+        { return EventIface.default_tostring(L); }
     },
     {
         "__gc",
index 187148a524f28263d6eaf92c99f56cf063c8ed53..72de02905713cc25d429ff2b1b4ecd9fe2c412d4 100644 (file)
@@ -31,9 +31,9 @@ static const luaL_Reg methods[] =
         "new",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
-            PktType type = static_cast<PktType>(arg.opt_size(1));
+            PktType type = static_cast<PktType>(args[1].opt_size());
 
             FlowIface.create(L).init(type);
 
index a4de784ba4da8ca8368939d7b690b18418f6fdcc..280d340fe9c9c0bf20a19740bf491b108d7b4f21 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "framework/inspector.h"
 #include "lua/lua_arg.h"
+#include "main/snort_config.h"
 #include "pp_packet_iface.h"
 #include "pp_raw_buffer_iface.h"
 #include "pp_stream_splitter_iface.h"
@@ -45,6 +46,44 @@ static inline bool get_buf(
 
 static const luaL_Reg methods[] =
 {
+    {
+        "configure",
+        [](lua_State* L)
+        {
+            auto& self = InspectorIface.get(L);
+            // FIXIT-L: Do we need an opaque SnortConfig interface?
+            bool result = self.configure(snort_conf);
+            lua_pushboolean(L, result);
+            return 1;
+        }
+    },
+    {
+        "tinit",
+        [](lua_State* L)
+        {
+            InspectorIface.get(L).tinit();
+            return 0;
+        },
+    },
+    {
+        "tterm",
+        [](lua_State* L)
+        {
+            InspectorIface.get(L).tterm();
+            return 0;
+        }
+    },
+    {
+        "likes",
+        [](lua_State* L)
+        {
+            auto& p = PacketIface.get(L, 1);
+            auto& self = InspectorIface.get(L);
+            bool result = self.likes(&p);
+            lua_pushboolean(L, result);
+            return 1;
+        }
+    },
     {
         "eval",
         [](lua_State* L)
@@ -69,21 +108,20 @@ static const luaL_Reg methods[] =
             return 0;
         }
     },
+    // FIXIT-M: Add meta() method
+    // FIXIT-M: Add exec() method
     {
         "get_buf_from_key",
         [](lua_State* L)
         {
-            bool result;
+            Lua::Args args(L);
 
             auto& p = PacketIface.get(L, 2);
             auto& rb = RawBufferIface.get(L, 3);
-            auto& self = InspectorIface.get(L);
 
-            {
-                auto key = Lua::Stack<std::string>::get(L, 1);
-                result = get_buf(self, key.c_str(), p, rb);
-            }
+            auto& self = InspectorIface.get(L);
 
+            bool result = get_buf(self, args[1].check_string(), p, rb);
             lua_pushboolean(L, result);
 
             return 1;
@@ -93,16 +131,15 @@ static const luaL_Reg methods[] =
         "get_buf_from_id",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
-            int id = arg.check_int(1);
+            int id = args[1].check_int();
             auto& p = PacketIface.get(L, 2);
             auto& rb = RawBufferIface.get(L, 3);
 
             auto& self = InspectorIface.get(L);
 
             bool result = get_buf(self, id, p, rb);
-
             lua_pushboolean(L, result);
 
             return 1;
@@ -112,20 +149,15 @@ static const luaL_Reg methods[] =
         "get_buf_from_type",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
-            int type = arg.check_int(1);
+            auto type = static_cast<InspectionBuffer::Type>(args[1].check_int());
             auto& p = PacketIface.get(L, 2);
             auto& rb = RawBufferIface.get(L, 3);
 
             auto& self = InspectorIface.get(L);
 
-            bool result = get_buf(
-                self,
-                static_cast<InspectionBuffer::Type>(type),
-                p, rb
-            );
-
+            bool result = get_buf(self, type, p, rb);
             lua_pushboolean(L, result);
 
             return 1;
@@ -135,9 +167,9 @@ static const luaL_Reg methods[] =
         "get_splitter",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
-            bool to_server = arg.check_boolean(1);
+            bool to_server = args[1].check_bool();
             auto& self = InspectorIface.get(L);
 
             auto** sp = StreamSplitterIface.allocate(L);
index 5862a305d28b71c1429b1ff82c8f41482bc96a4c..4b282b4524b7e38747fd5ba292f9d7587ab23ad6 100644 (file)
 #include <luajit-2.0/lua.hpp>
 
 #include "framework/ips_option.h"
+#include "lua/lua_stack.h"
 #include "pp_packet_iface.h"
 #include "pp_cursor_iface.h"
 
 static const luaL_Reg methods[] =
 {
+    {
+        "hash",
+        [](lua_State* L)
+        {
+            uint32_t result = IpsOptionIface.get(L).hash();
+            Lua::Stack<uint32_t>::push(L, result);
+            return 1;
+        }
+    },
+    {
+        "is_relative",
+        [](lua_State* L)
+        {
+            bool result = IpsOptionIface.get(L).is_relative();
+            lua_pushboolean(L, result);
+            return 1;
+        }
+    },
+    {
+        "fp_research",
+        [](lua_State* L)
+        {
+            bool result = IpsOptionIface.get(L).fp_research();
+            lua_pushboolean(L, result);
+            return 1;
+        }
+    },
+    {
+        "get_cursor_type",
+        [](lua_State* L)
+        {
+            CursorActionType cat = IpsOptionIface.get(L).get_cursor_type();
+            Lua::Stack<unsigned>::push(L, static_cast<unsigned>(cat));
+            return 1;
+        }
+    },
     {
         "eval",
         [](lua_State* L)
index 4c350b7301c8ac448da08dfc2600c90eb8cac41b..64c706332ebce5c0b72351056c5d928f2ab63530 100644 (file)
@@ -33,8 +33,7 @@ static const luaL_Reg methods[] =
         "open",
         [](lua_State* L)
         {
-            auto& self = LoggerIface.get(L);
-            self.open();
+            LoggerIface.get(L).open();
             return 0;
         }
     },
@@ -42,8 +41,7 @@ static const luaL_Reg methods[] =
         "close",
         [](lua_State* L)
         {
-            auto& self = LoggerIface.get(L);
-            self.close();
+            LoggerIface.get(L).close();
             return 0;
         }
     },
@@ -51,8 +49,7 @@ static const luaL_Reg methods[] =
         "reset",
         [](lua_State* L)
         {
-            auto& self = LoggerIface.get(L);
-            self.reset();
+            LoggerIface.get(L).reset();
             return 0;
         }
     },
@@ -60,14 +57,14 @@ static const luaL_Reg methods[] =
         "alert",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& p = PacketIface.get(L, 1);
-            const char* msg = arg.check_string(2);
             auto& e = EventIface.get(L, 3);
 
             auto& self = LoggerIface.get(L);
 
+            const char* msg = args[2].check_string();
             self.alert(&p, msg, &e);
 
             return 0;
@@ -77,14 +74,14 @@ static const luaL_Reg methods[] =
         "log",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& p = PacketIface.get(L, 1);
-            const char* msg = arg.check_string(2);
             auto& e = EventIface.get(L, 3);
 
             auto& self = LoggerIface.get(L);
 
+            const char* msg = args[2].check_string();
             self.log(&p, msg, &e);
 
             return 0;
index 58094824ebde88ad964653391a28fc7a025660b8..c65d02094d4458cd0a62544f7f553eb89602223b 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "pp_packet_iface.h"
 
+#include <string.h>
 #include <luajit-2.0/lua.hpp>
 
 #include "lua/lua_arg.h"
 #include "pp_raw_buffer_iface.h"
 #include "pp_daq_pkthdr_iface.h"
 
+static void set_fields(lua_State* L, int tindex, Packet& self)
+{
+    Lua::Table table(L, tindex);
+
+    table.get_field("packet_flags", self.packet_flags);
+    table.get_field("xtradata_mask", self.xtradata_mask);
+    table.get_field("proto_bits", self.proto_bits);
+    table.get_field(
+        "application_protocol_ordinal",
+        self.application_protocol_ordinal
+    );
+
+    table.get_field("alt_dsize", self.alt_dsize);
+    table.get_field("num_layers", self.num_layers);
+    table.get_field("iplist_id", self.iplist_id);
+    table.get_field("user_policy_id", self.user_policy_id);
+    table.get_field("ps_proto", self.ps_proto);
+}
+
+static void get_fields(lua_State* L, int tindex, Packet& self)
+{
+    Lua::Table table(L, tindex);
+
+    table.set_field("packet_flags", self.packet_flags);
+    table.set_field("xtradata_mask", self.xtradata_mask);
+    table.set_field("proto_bits", self.proto_bits);
+    table.set_field(
+        "application_protocol_ordinal",
+        self.application_protocol_ordinal
+    );
+
+    table.set_field("alt_dsize", self.alt_dsize);
+    table.set_field("num_layers", self.num_layers);
+    table.set_field("iplist_id", self.iplist_id);
+    table.set_field("user_policy_id", self.user_policy_id);
+    table.set_field("ps_proto", self.ps_proto);
+}
+
+static void set(lua_State* L, Packet& self, Lua::Args& args, int start)
+{
+    for ( int i = start; i <= args.count; i++ )
+    {
+        if ( args[i].is_string() )
+        {
+            size_t len = 0;
+            const char* s = args[i].check_string(len);
+            auto& rb = RawBufferIface.create(L, s, len);
+            self.pkt = get_data(rb);
+            Lua::add_ref(L, &self, "pkt", lua_gettop(L));
+            lua_pop(L, 1);
+        }
+        else if ( args[i].is_size() )
+        {
+            size_t sz = args[i].check_size();
+            auto& rb = RawBufferIface.create(L, sz, '\0');
+            self.pkt = get_data(rb);
+            Lua::add_ref(L, &self, "pkt", lua_gettop(L));
+            lua_pop(L, 1);
+        }
+        else if ( args[i].is_table() )
+        {
+            args[i].check_table(set_fields, self);
+        }
+        else if ( RawBufferIface.is(L, i) )
+        {
+            self.pkt = get_data(RawBufferIface.get(L, i));
+            Lua::add_ref(L, &self, "pkt", i);
+        }
+        else if ( DAQHeaderIface.is(L, i) )
+        {
+            self.pkth = &DAQHeaderIface.get(L, i);
+            Lua::add_ref(L, &self, "pkth", i);
+        }
+        else
+        {
+            luaL_argerror(L, i,
+                "expected string or unsigned or table or RawBuffer or DAQHeader");
+        }
+    }
+}
+
 static const luaL_Reg methods[] =
 {
     {
         "new",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = PacketIface.create(L);
+            self.reset();
 
-            // (Optional) first argument is raw packet
-            if ( arg.count )
-            {
-                auto& rb = RawBufferIface.get(L, 1);
-                self.pkt = reinterpret_cast<const uint8_t*>(rb.data());
-            }
-
-            // (Optional) second argument is daq header
-            if ( arg.count > 1 )
-                self.pkth = &DAQHeaderIface.get(L, 2);
+            set(L, self, args, 1);
 
             return 1;
         }
@@ -57,11 +131,7 @@ static const luaL_Reg methods[] =
         "set_decode_data",
         [](lua_State* L)
         {
-            auto& self = PacketIface.get(L, 1);
-            auto& dd = DecodeDataIface.get(L, 2);
-
-            self.ptrs = dd;
-
+            PacketIface.get(L, 1).ptrs = DecodeDataIface.get(L, 2);
             return 0;
         }
     },
@@ -69,11 +139,11 @@ static const luaL_Reg methods[] =
         "set_data",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = PacketIface.get(L, 1);
-            size_t offset = arg.check_size(2);
-            size_t size = arg.check_size(3);
+            size_t offset = args[2].check_size();
+            size_t size = args[3].check_size();
 
             self.data = self.pkt + offset;
             self.dsize = size;
@@ -89,6 +159,7 @@ static const luaL_Reg methods[] =
             auto& flow = FlowIface.get(L, 2);
 
             self.flow = &flow;
+            Lua::add_ref(L, &self, "flow", 2);
 
             return 0;
         }
@@ -96,77 +167,17 @@ static const luaL_Reg methods[] =
     {
         "get",
         [](lua_State* L)
-        {
-            auto& self = PacketIface.get(L);
-            lua_newtable(L);
-
-            Lua::Table table(L, lua_gettop(L));
-
-            table.set_field("packet_flags", self.packet_flags);
-            table.set_field("xtradata_mask", self.xtradata_mask);
-            table.set_field("proto_bits", self.proto_bits);
-            table.set_field(
-                "application_protocol_ordinal",
-                self.application_protocol_ordinal
-            );
-
-            table.set_field("alt_dsize", self.alt_dsize);
-            table.set_field("num_layers", self.num_layers);
-            table.set_field("iplist_id", self.iplist_id);
-            table.set_field("user_policy_id", self.user_policy_id);
-            table.set_field("ps_proto", self.ps_proto);
-
-            return 1;
-        }
+        { return PacketIface.default_getter(L, get_fields); }
     },
     {
         "set",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
-
-            auto& self = PacketIface.get(L, 1);
-
-            arg.check_table(2);
+            Lua::Args args(L);
 
-            Lua::Table table(L, 2);
-            table.get_field("packet_flags", self.packet_flags);
-            table.get_field("xtradata_mask", self.xtradata_mask);
-            table.get_field("proto_bits", self.proto_bits);
-            table.get_field(
-                "application_protocol_ordinal",
-                self.application_protocol_ordinal
-            );
-
-            table.get_field("alt_dsize", self.alt_dsize);
-            table.get_field("num_layers", self.num_layers);
-            table.get_field("iplist_id", self.iplist_id);
-            table.get_field("user_policy_id", self.user_policy_id);
-            table.get_field("ps_proto", self.ps_proto);
-
-            return 0;
-        }
-    },
-    {
-        "set_pkt",
-        [](lua_State* L)
-        {
             auto& self = PacketIface.get(L, 1);
-            auto& rb = RawBufferIface.get(L, 2);
 
-            self.pkt = reinterpret_cast<const uint8_t*>(rb.data());
-
-            return 0;
-        }
-    },
-    {
-        "set_daq",
-        [](lua_State* L)
-        {
-            auto& self = PacketIface.get(L, 1);
-            auto& daq = DAQHeaderIface.get(L, 2);
-
-            self.pkth = &daq;
+            set(L, self, args, 2);
 
             return 0;
         }
@@ -179,19 +190,12 @@ static const luaL_Reg metamethods[] =
     {
         "__tostring",
         [](lua_State* L)
-        {
-            auto& self = PacketIface.get(L);
-            lua_pushfstring(L, "%s@%p", PacketIface.name, &self);
-            return 1;
-        }
+        { return PacketIface.default_tostring(L); }
     },
     {
         "__gc",
         [](lua_State* L)
-        {
-            PacketIface.destroy(L);
-            return 0;
-        }
+        { return PacketIface.default_gc(L); }
     },
     { nullptr, nullptr }
 };
index 6790fa1477a6c7264da31788ada22d76a1beaf30..5829e5aef2c148eb0abfae5aeeb3f250efdc6304 100644 (file)
 
 static int init_from_string(lua_State* L)
 {
-    Lua::Arg arg(L);
+    Lua::Args args(L);
 
     size_t len = 0;
-    const char* s = arg.check_string(1, &len);
-    size_t size = arg.opt_size(2, len);
+    const char* s = args[1].check_string(len);
+    size_t size = args[2].opt_size(len);
 
     // instantiate and adjust size if necessary
     RawBufferIface.create(L, s, len).resize(size, '\0');
@@ -44,9 +44,9 @@ static int init_from_string(lua_State* L)
 
 static int init_from_size(lua_State* L)
 {
-    Lua::Arg arg(L);
+    Lua::Args args(L);
 
-    size_t size = arg.opt_size(1);
+    size_t size = args[1].opt_size();
 
     RawBufferIface.create(L, size, '\0');
 
@@ -59,9 +59,9 @@ static const luaL_Reg methods[] =
         "new",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
-            if ( arg.is_string(1) )
+            if ( args[1].is_string() )
                 return init_from_string(L);
 
             return init_from_size(L);
@@ -73,7 +73,6 @@ static const luaL_Reg methods[] =
         {
             auto& self = RawBufferIface.get(L);
             lua_pushinteger(L, self.size());
-
             return 1;
         }
     },
@@ -81,10 +80,10 @@ static const luaL_Reg methods[] =
         "resize",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = RawBufferIface.get(L, 1);
-            size_t new_size = arg.check_size(2);
+            size_t new_size = args[2].check_size();
 
             self.resize(new_size, '\0');
 
@@ -95,13 +94,13 @@ static const luaL_Reg methods[] =
         "write",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = RawBufferIface.get(L, 1);
 
             size_t len = 0;
-            const char* s = arg.check_string(2, &len);
-            size_t offset = arg.opt_size(3);
+            const char* s = args[2].check_string(len);
+            size_t offset = args[3].opt_size();
 
             size_t required = offset + len;
             if ( self.size() < required )
@@ -116,19 +115,19 @@ static const luaL_Reg methods[] =
         "read",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = RawBufferIface.get(L, 1);
 
-            if ( arg.count > 2 )
+            if ( args.count > 2 )
             {
-                size_t start = arg.check_size(2, self.size());
-                size_t end = arg.check_size(3, start, self.size());
+                size_t start = args[2].check_size(self.size());
+                size_t end = args[3].check_size(start, self.size());
                 lua_pushlstring(L, self.data() + start, end - start);
             }
             else
             {
-                size_t end = arg.opt_size(2, self.size(), self.size());
+                size_t end = args[2].opt_size(self.size(), self.size());
                 lua_pushlstring(L, self.data(), end);
             }
 
@@ -145,17 +144,14 @@ static const luaL_Reg metamethods[] =
         [](lua_State* L)
         {
             auto& self = RawBufferIface.get(L);
-            lua_pushfstring(L, "%s@%p", RawBufferIface.name, &self);
+            lua_pushlstring(L, self.data(), self.size());
             return 1;
         }
     },
     {
         "__gc",
         [](lua_State* L)
-        {
-            RawBufferIface.destroy(L);
-            return 0;
-        }
+        { return RawBufferIface.default_gc(L); }
     },
     { nullptr, nullptr }
 };
index aa94edb7d07507bdc32971f375ba27d38d841bb4..7797ab40fb490e8c7c63a4734cc0ea2cb117a267 100644 (file)
 
 using RawBuffer = std::string;
 
+static inline const uint8_t* get_data(RawBuffer& rb)
+{ return reinterpret_cast<const uint8_t*>(rb.data()); }
+
+static inline uint8_t* get_mutable_data(RawBuffer& rb)
+{ return const_cast<uint8_t*>(get_data(rb)); }
+
 extern const struct Lua::TypeInterface<RawBuffer> RawBufferIface;
 
 #endif
diff --git a/src/piglet_plugins/pp_raw_data_iface.cc b/src/piglet_plugins/pp_raw_data_iface.cc
deleted file mode 100644 (file)
index 06def1d..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//--------------------------------------------------------------------------
-// pp_raw_data_iface.cc author Joel Cornett <jocornet@cisco.com>
-
-#include "pp_raw_data_iface.h"
-
-#include <luajit-2.0/lua.hpp>
-
-extern "C" {
-#include <daq.h>
-}
-
-#include "framework/codec.h"
-#include "pp_raw_buffer_iface.h"
-#include "pp_daq_pkthdr_iface.h"
-
-static const luaL_Reg methods[] =
-{
-    {
-        "new",
-        [](lua_State* L)
-        {
-            auto& rb = RawBufferIface.get(L, 1);
-            auto& daq = DAQHeaderIface.get(L, 2);
-
-            RawDataIface.create(
-                L, &daq, reinterpret_cast<const uint8_t*>(rb.data()));
-
-            return 1;
-        }
-    },
-    { nullptr, nullptr }
-};
-
-static const luaL_Reg metamethods[] =
-{
-    {
-        "__tostring",
-        [](lua_State* L)
-        {
-            auto& self = RawDataIface.get(L);
-            lua_pushfstring(L, "%s@%p", RawDataIface.name, &self);
-
-            return 1;
-        }
-    },
-    {
-        "__gc",
-        [](lua_State* L)
-        {
-            RawDataIface.destroy(L);
-            return 0;
-        }
-    },
-    { nullptr, nullptr }
-};
-
-const struct Lua::TypeInterface<RawData> RawDataIface =
-{
-    "RawData",
-    methods,
-    metamethods
-};
index 2eb20ab6ed310cee2302fb7fb47ecfbbc3797dd7..5623620886d5ade83ffec51669cbeec718185d34 100644 (file)
@@ -38,19 +38,16 @@ static const luaL_Reg methods[] =
         "scan",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = StreamSplitterIface.get(L, 1);
             auto& flow = FlowIface.get(L, 2);
             auto& rb = RawBufferIface.get(L, 3);
-            uint32_t len = arg.opt_size(4, rb.size(), rb.size());
-            uint32_t flags = arg.opt_size(5);
+            uint32_t len = args[4].opt_size(rb.size(), rb.size());
+            uint32_t flags = args[5].opt_size();
 
             uint32_t fp = 0;
-            auto status = self.scan(
-                &flow, reinterpret_cast<const uint8_t*>(rb.data()),
-                len, flags, &fp
-            );
+            auto status = self.scan(&flow, get_data(rb), len, flags, &fp);
 
             stack_push<StreamSplitter::Status, unsigned>(L, status);
             Lua::Stack<uint32_t>::push(L, fp);
@@ -62,23 +59,20 @@ static const luaL_Reg methods[] =
         "reassemble",
         [](lua_State* L)
         {
-            Lua::Arg arg(L);
+            Lua::Args args(L);
 
             auto& self = StreamSplitterIface.get(L, 1);
             auto& flow = FlowIface.get(L, 2);
-            unsigned total = arg.check_size(3);
-            unsigned offset = arg.check_size(4);
+            unsigned total = args[3].check_size();
+            unsigned offset = args[4].check_size();
             auto& rb = RawBufferIface.get(L, 5);
-            unsigned len = arg.opt_size(6, rb.size());
-            uint32_t flags = arg.opt_size(7);
+            unsigned len = args[6].opt_size(rb.size());
+            uint32_t flags = args[7].opt_size();
 
             unsigned copied = 0;
 
-            auto sb = self.reassemble(
-                &flow, total, offset,
-                reinterpret_cast<const uint8_t*>(rb.data()), len,
-                flags, copied
-            );
+            auto sb = self.reassemble(&flow, total, offset, get_data(rb), len,
+                flags, copied);
 
             Lua::Stack<unsigned>::push(L, copied);
 
@@ -99,7 +93,6 @@ static const luaL_Reg methods[] =
             auto& flow = FlowIface.get(L, 2);
 
             bool result = self.finish(&flow);
-
             lua_pushboolean(L, result);
 
             return 1;
@@ -113,20 +106,12 @@ static const luaL_Reg metamethods[] =
     {
         "__tostring",
         [](lua_State* L)
-        {
-            auto& self = StreamSplitterIface.get(L);
-            lua_pushfstring(L, "%s@%p", StreamSplitterIface.name, &self);
-
-            return 1;
-        }
+        { return StreamSplitterIface.default_tostring(L); }
     },
     {
         "__gc",
         [](lua_State* L)
-        {
-            StreamSplitterIface.destroy(L);
-            return 0;
-        }
+        { return StreamSplitterIface.default_gc(L); }
     },
     { nullptr, nullptr }
 };
index 9924b29937bcb0acbe4d72f91a54b7ccd7addf3b..165a2eba0a32317478e564cc24b380ca0d379efd 100644 (file)
@@ -38,7 +38,6 @@
 #include "pp_flow_iface.h"
 #include "pp_packet_iface.h"
 #include "pp_raw_buffer_iface.h"
-#include "pp_raw_data_iface.h"
 
 class TestPiglet : public Piglet::BasePlugin
 {
@@ -62,7 +61,6 @@ bool TestPiglet::setup()
     install(L, FlowIface);
     install(L, PacketIface);
     install(L, RawBufferIface);
-    install(L, RawDataIface);
 
     return false;
 }
index 1d4fbcede98f505a81b5a670831a3ca8f1a42d90..d68d7642038bacad46de382cae63273b3a0b07e4 100644 (file)
@@ -28,6 +28,8 @@ add_custom_command(
 add_library(unit_tests STATIC
     suite_decl.h
     suite_list.h
+    lua_stack_test.cc
+    lua_test_common.h
     sfip_test.cc
     sfrf_test.cc
     sfrt_test.cc
index 1411f5f773f2c9cd6585eacafb4f5bce92e44fc5..7306907ab38b9e15cb1a61b4bee11024777d5b3c 100644 (file)
@@ -6,6 +6,8 @@ suite_decl.h \
 suite_list.h
 
 libtest_a_SOURCES = \
+lua_stack_test.cc \
+lua_test_common.h \
 sfip_test.cc \
 sfrf_test.cc \
 sfrt_test.cc \
diff --git a/src/test/lua_stack_test.cc b/src/test/lua_stack_test.cc
new file mode 100644 (file)
index 0000000..0ff5119
--- /dev/null
@@ -0,0 +1,411 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// lua_stack_test.cc author Joel Cornett <jocornet@cisco.com>
+
+#include <string>
+#include <luajit-2.0/lua.hpp>
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#endif
+
+#include <check.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+#include "lua_test_common.h"
+#include "lua/lua_stack.h"
+
+static lua_State* L = nullptr;
+
+static void LuaCleanup(void)
+{ l_end_lua_state(L); }
+
+static void LuaFixture(void)
+{ l_reset_lua_state(L); }
+
+START_TEST(test_signed)
+{
+    bool b;
+    int k;
+
+    // Test get
+    lua_pushinteger(L, 3);
+    {
+        auto r = Lua::Stack<int>::get(L, -1);
+        ck_assert_int_eq(r, 3);
+    }
+    lua_pop(L, 1);
+
+    // Test push
+    int j = 4;
+    Lua::Stack<int>::push(L, j);
+    {
+        lua_Integer l = lua_tointeger(L, -1);
+        ck_assert_int_eq(l, j);
+    }
+    lua_pop(L, 1);
+
+    // Test validate, no output
+    lua_pushinteger(L, 1);
+    {
+        b = Lua::Stack<int>::validate(L, -1);
+        ck_assert(b);
+    }
+    lua_pop(L, 1);
+
+    // Test validate
+    k = 0;
+    lua_pushinteger(L, 5);
+    {
+        b = Lua::Stack<int>::validate(L, -1, k);
+        ck_assert_int_eq(k, 5);
+        ck_assert(b);
+    }
+    lua_pop(L, 1);
+
+    // Test validate false
+    k = 7;
+    lua_pushnil(L);
+    {
+        b = Lua::Stack<int>::validate(L, -1, k);
+        ck_assert_int_eq(k, 7);
+        ck_assert(!b);
+    }
+    lua_pop(L, 1);
+}
+END_TEST
+
+START_TEST(test_unsigned)
+{
+    bool b;
+    unsigned short k;
+
+    // Test get
+    lua_pushinteger(L, 3);
+    {
+        auto r = Lua::Stack<unsigned short>::get(L, -1);
+        ck_assert_int_eq(r, 3);
+    }
+    lua_pop(L, 1);
+
+    // Test push
+    unsigned short j = 4;
+    Lua::Stack<unsigned short>::push(L, j);
+    {
+        lua_Integer l = lua_tointeger(L, -1);
+        ck_assert_int_eq(l, j);
+    }
+    lua_pop(L, 1);
+
+    // Test validate, no output
+    lua_pushinteger(L, 1);
+    {
+        b = Lua::Stack<unsigned short>::validate(L, -1);
+        ck_assert(b);
+    }
+    lua_pop(L, 1);
+
+    // Test validate
+    k = 0;
+    lua_pushinteger(L, 5);
+    {
+        b = Lua::Stack<unsigned short>::validate(L, -1, k);
+        ck_assert_int_eq(k, 5);
+        ck_assert(b);
+    }
+    lua_pop(L, 1);
+
+    // Test validate false
+    k = 7;
+    lua_pushnil(L);
+    {
+        b = Lua::Stack<unsigned short>::validate(L, -1, k);
+        ck_assert_int_eq(k, 7);
+        ck_assert(!b);
+    }
+    lua_pop(L, 1);
+    lua_pushinteger(L, -1);
+    {
+        b = Lua::Stack<unsigned short>::validate(L, -1, k);
+        ck_assert_int_eq(k, 7);
+        ck_assert(!b);
+    }
+    lua_pop(L, 1);
+}
+END_TEST
+
+START_TEST(test_cstring)
+{
+    bool b;
+    const char* s;
+    size_t len;
+
+    // Test type
+    ck_assert_int_eq(Lua::Stack<const char*>::type(), LUA_TSTRING);
+
+    // Test get
+    s = nullptr;
+    lua_pushstring(L, "foo");
+    {
+        s = Lua::Stack<const char*>::get(L, -1);
+        ck_assert_str_eq(s, "foo");
+    }
+    lua_pop(L, 1);
+
+    // Test get w/length
+    s = nullptr;
+    len = 0;
+    lua_pushlstring(L, "f\0b", 3);
+    {
+        s = Lua::Stack<const char*>::get(L, -1, len);
+        ck_assert_uint_eq(len, 3);
+        l_assert_strn_eq(s, "f\0b", len);
+    }
+    lua_pop(L, 1);
+
+    // Test push
+    s = "foo";
+    Lua::Stack<const char*>::push(L, s);
+    {
+        s = lua_tostring(L, -1);
+        ck_assert_str_eq(s, "foo");
+    }
+    lua_pop(L, 1);
+
+    len = 0;
+    s = "f\0o";
+    Lua::Stack<const char*>::push(L, s);
+    {
+        s = lua_tolstring(L, -1, &len);
+        ck_assert_str_eq(s, "f");
+        ck_assert_uint_eq(len, 1);
+    }
+    lua_pop(L, 1);
+
+    // Test push w/length
+    len = 0;
+    s = "f\0b";
+    Lua::Stack<const char*>::push(L, s, 3);
+    {
+        s = lua_tolstring(L, -1, &len);
+        ck_assert_uint_eq(len, 3);
+        l_assert_strn_eq(s, "f\0b", len);
+    }
+    lua_pop(L, 1);
+
+    // Test validate, no output
+    lua_pushstring(L, "foo");
+    {
+        b = Lua::Stack<const char*>::validate(L, -1);
+        ck_assert(b);
+    }
+    lua_pop(L, 1);
+
+    // Test validate
+    len = 0;
+    s = "foo";
+    lua_pushstring(L, s);
+    {
+        s = nullptr;
+        b = Lua::Stack<const char*>::validate(L, -1, s);
+        ck_assert(b);
+        ck_assert_str_eq(s, "foo");
+    }
+    lua_pop(L, 1);
+
+    // Test validate w/length
+    len = 0;
+    s = "f\0b";
+    lua_pushlstring(L, s, 3);
+    {
+        s = nullptr;
+        b = Lua::Stack<const char*>::validate(L, -1, s, len);
+        ck_assert(b);
+        l_assert_strn_eq(s, "f\0b", 3);
+    }
+    lua_pop(L, 1);
+
+    // Test invalid
+    s = nullptr;
+    lua_pushnil(L);
+    {
+        b = Lua::Stack<const char*>::validate(L, -1, s);
+        ck_assert(!s);
+        ck_assert(!b);
+    }
+    lua_pop(L, 1);
+
+    s = nullptr;
+    lua_pushnil(L);
+    {
+        b = Lua::Stack<const char*>::validate(L, -1, s, len);
+        ck_assert(!s);
+        ck_assert(!b);
+    }
+    lua_pop(L, 1);
+}
+END_TEST
+
+START_TEST(test_string)
+{
+    bool b;
+    const char* cs;
+    std::string s;
+    size_t len;
+
+    // Test type
+    ck_assert_int_eq(Lua::Stack<std::string>::type(), LUA_TSTRING);
+
+    // Test get
+    lua_pushstring(L, "foo");
+    {
+        s = Lua::Stack<std::string>::get(L, -1);
+        ck_assert(s == "foo");
+    }
+    lua_pop(L, 1);
+
+    // Test get w/zeros
+    lua_pushlstring(L, "f\0b", 3);
+    {
+        s = Lua::Stack<std::string>::get(L, -1);
+        ck_assert(s.length() == 3);
+        l_assert_strn_eq(s.c_str(), "f\0b", 3);
+    }
+    lua_pop(L, 1);
+
+    // Test push
+    s = "foo";
+    Lua::Stack<std::string>::push(L, s);
+    {
+        cs = lua_tostring(L, -1);
+        ck_assert_str_eq(cs, "foo");
+    }
+    lua_pop(L, 1);
+
+    len = 0;
+    s.assign("f\0b", 3);
+    Lua::Stack<std::string>::push(L, s);
+    {
+        cs = lua_tolstring(L, -1, &len);
+        ck_assert_uint_eq(len, 3);
+        l_assert_strn_eq(cs, "f\0b", len);
+    }
+    lua_pop(L, 1);
+
+    // Test validate, no output
+    lua_pushstring(L, "foo");
+    {
+        b = Lua::Stack<std::string>::validate(L, -1);
+        ck_assert(b);
+    }
+    lua_pop(L, 1);
+
+    // Test validate
+    lua_pushstring(L, "foo");
+    {
+        b = Lua::Stack<std::string>::validate(L, -1, s);
+        ck_assert(b);
+        ck_assert(s == "foo");
+    }
+    lua_pop(L, 1);
+
+    lua_pushlstring(L, "f\0o", 3);
+    {
+        b = Lua::Stack<std::string>::validate(L, -1, s);
+        ck_assert(b);
+        ck_assert_uint_eq(s.length(), 3);
+        l_assert_strn_eq(s.c_str(), "f\0o", 3);
+    }
+    lua_pop(L, 1);
+
+    // Test invalid
+    lua_pushnil(L);
+    {
+        b = Lua::Stack<std::string>::validate(L, -1, s);
+        ck_assert(!b);
+    }
+    lua_pop(L, 1);
+}
+END_TEST
+
+START_TEST(test_bool)
+{
+    bool b, v;
+
+    // Test get
+    lua_pushboolean(L, true);
+    {
+        v = Lua::Stack<bool>::get(L, -1);
+        ck_assert(v);
+    }
+    lua_pop(L, 1);
+
+    // Test push
+    Lua::Stack<bool>::push(L, true);
+    {
+        v = lua_toboolean(L, -1);
+        ck_assert(v);
+    }
+    lua_pop(L, 1);
+
+    // Test validate, no output
+    lua_pushboolean(L, true);
+    {
+        b = Lua::Stack<bool>::validate(L, -1);
+        ck_assert(b);
+    }
+    lua_pop(L, 1);
+
+    // Test validate
+    lua_pushboolean(L, true);
+    {
+        b = Lua::Stack<bool>::validate(L, -1, v);
+        ck_assert(b);
+        ck_assert(v);
+    }
+    lua_pop(L, 1);
+
+    // Test invalid
+    lua_pushnil(L);
+    {
+        b = Lua::Stack<bool>::validate(L, -1, v);
+        ck_assert(!b);
+    }
+    lua_pop(L, 1);
+}
+END_TEST
+
+Suite* TEST_SUITE_lua_stack(void)
+{
+    Suite* ps = suite_create("lua_stack");
+
+    TCase* tc = tcase_create("lua_stack");
+    tcase_add_unchecked_fixture(tc, LuaFixture, LuaCleanup);
+    tcase_add_test(tc, test_signed);
+    tcase_add_test(tc, test_unsigned);
+    tcase_add_test(tc, test_cstring);
+    tcase_add_test(tc, test_string);
+    tcase_add_test(tc, test_bool);
+    suite_add_tcase(ps, tc);
+
+    return ps;
+}
diff --git a/src/test/lua_test_common.h b/src/test/lua_test_common.h
new file mode 100644 (file)
index 0000000..fb468b1
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef LUA_TEST_COMMON_H
+#define LUA_TEST_COMMON_H
+
+#include <utility>
+#include <string.h>
+#include <luajit-2.0/lua.hpp>
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#endif
+
+#include <check.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+static inline void l_assert_strn_eq(const char* a, const char* b, size_t n)
+{ ck_assert(!strncmp(a, b, n)); }
+
+static inline void l_end_lua_state(lua_State*& L_ptr)
+{
+    if ( L_ptr )
+    {
+        lua_close(L_ptr);
+        L_ptr = nullptr;
+    }
+}
+
+static inline void l_reset_lua_state(lua_State*& L_ptr)
+{
+    l_end_lua_state(L_ptr);
+    L_ptr = luaL_newstate();
+    luaL_openlibs(L_ptr);
+}
+
+template<typename T, size_t N>
+static inline constexpr size_t sizeofArray(T (&)[N])
+{ return N; }
+
+#endif