How to convert a luajit pointer to a string and back? - lua

I need some help converting a luajit pointer to a string and back.
First I define the ctype:
ffi.cdef[[
typedef struct {
unsigned char Bytes[16];
} EncryptionKeys[100000000];
void* malloc(size_t);
void free(void*);
]]
Then use malloc to allocate some memory and then create the 'EncryptionKeys' variable.
local EncryptionKeyMemoryAddress = ffi.C.malloc(ffi.sizeof("EncryptionKeys"))
local EncryptionKeys = ffi.cast("EncryptionKeys(&)", EncryptionKeyMemoryAddress)
I first convert the variable into a lua string using:
ffi.string(EncryptionKeyMemoryAddress)
But I can't figure out how to convert it back!
Can someone please help me?
FYI: I am passing the 'EncryptionKeyMemoryAddress' variable to one of the function parameters for a lua lane (https://lualanes.github.io/lanes/).
Edit:
Here is the section of code that I am working on:
This is for the client managers module of my server that manages a list of lua states that all have access to any clients connected to the server. They all use a shared section of memory that I want them to have access to using a pointer.
local ClientFFIString = [[
typedef struct {
unsigned char Bytes[16];
} EncryptionKeys[100000000];
void* malloc(size_t);
void free(void*);
]]
ffi.cdef(Matchpools.FFIString)
local EncryptionKeyMemoryAddress = ffi.C.malloc(ffi.sizeof("EncryptionKeys"))
--------------------------------------------
function ClientManagers.CreateNewClientManager()
local EncryptionKeys = ffi.cast("EncryptionKeys(&)", EncryptionKeyMemoryAddress)
EncryptionKeys[0].Bytes[0] = 24
print("___a", EncryptionKeys[0].Bytes[0])
local NewIndex = #ClientManagers.List+1
ClientManagers.List[NewIndex] = ClientManagerFunc(
ClientFFIString,
ffi.string(EncryptionKeysMemoryAddress)
)
end
--------------------------------------------
local ClientManagerFunc = Lanes.gen("*", function(ClientFFIString, EncryptionKeysMemoryAddress)
ffi = require("ffi")
ffi.cdef(ClientFFIString)
local EncryptionKeys = ffi.cast("EncryptionKeys(&)", EncryptionKeyMemoryAddress)
print("___a", EncryptionKeys[0].Bytes[0])
-- I want this to be 24 just like it is in the function that created this lua state
local ClientManagerRunning = true
while ClientManagerRunning do
--local dt = GetDt()
--UpdateClientData(dt)
--UpdateMatchmaking(dt)
end
end)

You can convert Lua string to your structure pointer (and later use it as an array):
ffi.cdef"typedef struct {unsigned char Bytes[16];} Key;"
ptr=ffi.cast("Key *", your_string)
print("First Byte of the First Key in your Array:", ptr[0].Bytes[0])
UPDATE:
Let's test how it works for an array containing three keys:
local ffi = require'ffi'
ffi.cdef"typedef struct {unsigned char Bytes[16];} Key;"
local your_string = string.char(11):rep(16)..string.char(22):rep(16)..string.char(33):rep(16)
local ptr=ffi.cast("Key *", your_string)
print("First Byte of the First Key in your Array:", ptr[0].Bytes[0])
print("First Byte of the Second Key in your Array:", ptr[1].Bytes[0])
print("First Byte of the Third Key in your Array:", ptr[2].Bytes[0])
It prints 11, 22, 33
UPDATE 2:
Pass the address of buffer instead of the content of buffer
In the main thread
-- allocate the buffer
local Keys = ffi.cast("EncryptionKeys&", ffi.C.malloc(ffi.sizeof("EncryptionKeys")))
-- write to the buffer
Keys[2].Bytes[5] = 42
-- create string containing 64-bit address
local string_to_send = tostring(ffi.cast("uint64_t", Keys))
-- Send string_to_send to a lane
Inside the lane
-- receive the string
local received_string = .....
-- restore the buffer pointer
local Keys = ffi.cast("EncryptionKeys&", loadstring("return "..received_string)())
-- read the data from the buffer
print(Keys[2].Bytes[5])

Related

Returning a string table array from C to LuaJIT via FFI

I would like to have a C function return a string table array (e.g. {"a", "b", "c"}) to a Lua script via LuaJIT.
Which is the best way to do it?
I thought of returning a single concatenated string with some separator (e.g. "a|b|c") then splitting it in Lua, but I was wondering if there is a better way.
EDIT: I'm using LuaJIT FFI to call C functions.
I think the easiest way to accomplish this would be to have the C code return a struct containing an array of strings and a length to Lua and write a little Lua to reify it to your desired data structure.
In C:
typedef struct {
char *strings[];
size_t len;
} string_array;
string_array my_func(...) {
/* do what you are going to do here */
size_t nstrs = n; /* however many strings you are returning */
char** str_array = malloc(sizeof(char*)*nstrs);
/* put all your strings into the array here */
return {str_array, nstrs};
}
In Lua:
-- load my_func and string_array declarations
local str_array_C = C.ffi.my_func(...)
local str_array_lua = {}
for i = 0, str_array_C.len-1 do
str_array_lua[i+1] = ffi.string(str_array_C.strings[i])
end
-- str_array_lua now holds your list of strings

Luajit ffi how to call funcitons in time.h?

I tried to call function tan of math.h this way (directly copy the declaration) and it works:
local ffi = require("ffi")
ffi.cdef[[
double tan(double x);
]]
print(ffi.C.tan(45))
But when I tried to call the function localtime of time.h the same way:
local ffi = require("ffi")
ffi.cdef[[
struct tm *localtime(const time_t *tp);
]]
print(ffi.C.localtime(1234544))
And get error:
lua: C:\Users\xiang\Desktop\bm.lua:4: declaration specifier expected near 'time_t'
stack traceback:
[C]: in function 'cdef'
C:\Users\xiang\Desktop\bm.lua:4: in main chunk
[C]: at 0x00401f00
[Finished in 0.1s with exit code 1]
I've checked the official manual this and this but still confused.
Every function you would like to call from FFI, it needs to be defined before. If not LuaJIT does not how to parse a FFI function call, how to do data-type conversion from Lua to C (and viceversa), etc.
Keeping that in my mind, to make your code work you would need to define time_t and struct tm. time_t is generally defined as a signed integer. You can find the definition of struct tm in localtime docs (man localtime).
ffi.cdef[[
struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Year - 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
struct tm *localtime(const int32_t *tp);
]]
In addition, function localtime expects a pointer value, not a constant integer. So it would be necessary to pass a c-data pointer storing an integer to localtime. There's a sort of LuaJIT idiom for that.
local time = ffi.new("int32_t[1]")
time[0] = 1234544
local tm = C.localtime(time)
Since arrays and pointers in C, although not the exactly same, are interchangeable in most cases.
Lastly, you cannot print a struct tm directly. Should store it into a variable and print out the fields you're interested.
print(tm.tm_sec)
You cannot use time_t as it isn't native C type. Replace it with proper native type or use a corresponding struct typedef. Then it should work.

Love 2D and ffi luajit, trying to use the PHYSFS_enumerateFiles()

It always return a String which is (at least I guess) the table identifier someone can help in anyway?
Thats my function:
function listFiles(dir)
local ffi = require("ffi")
ffi.cdef[[char ** PHYSFS_enumerateFiles ( const char * dir );]]
local liblove = ffi.os == "Windows" and ffi.load("love") or ffi.C
local tb={}
tb=liblove.PHYSFS_enumerateFiles(dir)
return tb
end
It should return me a String with filecontents of the "Dir" I pass to it, but it doesnt. Can't figure out why.
You should read the reference properly. The enumeration function returns a pointer to string pointers, after the last string follows a NULL pointer. Conversion from char* to Lua string can be done with ffi.string.

How to use strtok in luajit?

My code are as follow:
local ffi = require "ffi"
local ffi_C = ffi.C
local ffi_typeof = ffi.typeof
local ffi_new = ffi.new
local ffi_string = ffi.string
local NULL = ngx.null
local tostring = tostring
ffi.cdef[[
char * strtok(char * str, const char * delimiters);
]]
local p_char_type = ffi_typeof("char[?]")
function split(src, c)
local result = {}
local pch = ffi_new(p_char_type, 1)
local psrc = ffi_new(p_char_type, #src)
local pc = ffi_new(p_char_type, #c)
ffi.copy(psrc, src)
ffi.copy(pc, c)
pch = ffi_C.strtok(psrc, pc)
while pch do
table.insert(result, ffi_string(pch))
pch = ffi_C.strtok(NULL, pc)
ngx.log(ngx.ERR, "pch ok")
end
ngx.log(ngx.ERR, "split ok")
return result
end
When I run my nginx, there are something wrong happened!
After return by the while loop, the nginx worker process crashed with signal 11.
The last ngx.log can not run.
How can I deal with it?
local psrc = ffi_new(p_char_type, #src)
ffi.copy(psrc, src)
ffi.copy when given a string source also copies a null terminator, but your array is too small to hold it, resulting an overflow.
Also, instead of using strtok, consider using Lua patterns. They are safer, easier to use, and don't depend on the FFI.

Wireshark Lua Dissector - How to use a TAP?

I would like to do some analysis on top of my custom protocol that is dissected via my lua dissector. Therefore I tried to do this
myproto_proto = Proto("myproto", "Myproto Protocol")
m_dest = ProtoField.uint16("myproto.dest", "Destination", base.HEX)
m_src = ProtoField.uint16("myproto.src", "Source", base.HEX)
myproto_proto.fields = { sm_dest, sm_src }
dofile(MYPROTO_PROTO_PATH.."parser.lua")
function myproto_proto.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = "MYPROTO"
local subtree = tree:add(myproto_proto, buffer(), "Myproto Protocol Data")
parse_msg(buffer, pinfo, subtree) -- does the actual parsing and sets the fields
end
udp_table = DissectorTable.get("udp.port")
udp_table:add(9000,myproto_proto)
-- LISTENER / TAP
f_test = Field.new("myproto.dest") -- fails because "field does not exist"
local function my_tap()
local window = TextWindow.new("Myproto Tap")
local tap = Listener.new(nil, "myproto")
local counter = 0
function remove()
tap:remove()
end
window:set_atclose(remove)
function tap.packet(pinfo, buffer)
counter = counter + 1
end
function tap.draw(t)
window:append("Counter: \t" .. counter .. "\n")
end
function tap.reset()
window:clear()
counter = 0
end
retap_packets()
end
register_menu("My Tap", my_tap, MENU_TOOLS_UNSORTED)
My problem is, I'm unable to access the dissected data with a field extractor. So how else could I get the dissected data in my lua tap?
Thanks in advance.
It's a known problem that custom Lua Field objects aren't usable in OSX (it apparently works in Windows XP but not Windows 7).
There are a few ways to pass data from your dissector to your tap.
Option 1: Use a shared Lua table
Create a global dictionary that is keyed by the packet number (from pinfo.number, which is visible to both dissector and tap).
-- we omit the 'local' keyword to make `dict` a global variable
dict = {}
In your dissector, add the packet data to the dictionary:
dict[pinfo.number] = { dest = m_dest, src = m_src }
In your tap, you can access the data by a simple lookup.
print('dest', dict[pinfo.number].dest )
XXX: Requires a global; Duplicates storage for a variable that is already held in the protocol tree (and should be accessible from the tap).
Option 2: Use pinfo.private
This was added in the dev build (1.7.0). It's similar to the solution above. pinfo.private is a PrivateTable, which is a hash table that stores only strings.
In your dissector, add your data to the packet's private table:
pinfo.private["src"] = tostring(m_src)
pinfo.private["dest"] = tostring(m_dest)
In your tap, access the data from the pinfo object:
print('dest', pinfo.private["dest"] )
XXX: Can only store string values
Option 3: Reparse the buffer
In your tap, call your parser (i.e., from parser.lua) to reparse the data in buffer, which is passed to the tap.
XXX: Duplicates work already done by dissector (can double processing time for X-large capture files)

Resources