[求教]关于lua.ffi调用C

194 views
Skip to first unread message

赵安家

unread,
Sep 13, 2017, 10:42:21 PM9/13/17
to openresty
在网上找了一些lua.ffi的资料,也看过官网的文档,但是还是一知半解。


想弄一个lua的maxmind,根据ip获取geo信息。


这个库只写了获取country code的,虽然可以简单的通过复制粘贴,实现省市等其余信息的获取,但是无疑很笨重。


status = MMDB_get_entry_data_list(&result.entry,&entry_data_list);

发现可以直接从lua 通过ffi调用

MMDB_get_entry_data_list


int MMDB_get_entry_data_list(MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list)

参考https://github.com/lilien1010/lua-resty-maxminddb/blob/master/resty/maxminddb.lua#L178 

修改成如下代码

local entry_data_list   =   ffi_new('MMDB_entry_data_list_s **const')
local mmdb_error      =    maxm.MMDB_get_entry_data_list(result.entry, entry_data_list)


日志输出 

2017/09/14 10:39:52 [alert] 85284#85284: worker process 52105 exited on signal 11 (core dumped)

后面代码不执行。。。


赵安家

unread,
Sep 13, 2017, 11:17:40 PM9/13/17
to openresty
经过查找资料,发现是缺少将lua变量转换成c指针


local entry_data_list  = ffi_cast('MMDB_entry_data_list_s **const',ffi_new("MMDB_entry_data_list_s"))
local mmdb_error = maxm.MMDB_get_entry_data_list(result.entry,entry_data_list)

ngx.say(mmdb_error == MMDB_SUCCESS) -- output true

现在的问题是,咋循环 entry_data_list 。。。


在 2017年9月14日星期四 UTC+8上午10:42:21,赵安家写道:

赵安家

unread,
Sep 13, 2017, 11:39:27 PM9/13/17
to openresty
luajit ffi 咋遍历 linked list.....


在 2017年9月14日星期四 UTC+8上午10:42:21,赵安家写道:
在网上找了一些lua.ffi的资料,也看过官网的文档,但是还是一知半解。

Zexuan Luo

unread,
Sep 14, 2017, 3:43:09 AM9/14/17
to open...@googlegroups.com
你是指,像这样的操作吗?
local ffi = require "ffi"
ffi.cdef[[
typedef struct node {
    int value;
    struct node* next;
} node;
]]
local node = ffi.new("node")
node.value = 1
local node2 = ffi.new("node")
node2.value = 2
node.next = node2
print(node.next.value)

--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty+subscribe@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+unsubscribe@googlegroups.com
归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html

赵安家

unread,
Sep 14, 2017, 7:01:39 AM9/14/17
to openresty
对的,超级超级超级感谢。

经过一番努力,终于搞定了。

贴出关键部分代码,方便后人查阅。

local function _dump_entry_data_list(entry_data_list,status,resultTab)

    if not entry_data_list then
        return nil,nil,resultTab
    end
    
    if not resultTab then
        resultTab = {}
    end
    
    local flag = false
    
    local entry_data_item = entry_data_list[0].entry_data
    local data_type = entry_data_item.type
    local data_size = entry_data_item.data_size
    
    if data_type == MMDB_DATA_TYPE_MAP then
        table.insert(resultTab,"{")
        
        local size = entry_data_item.data_size
        
        entry_data_list = entry_data_list[0].next
        
        while(size > 0 and entry_data_list)
        do 
            entry_data_item = entry_data_list[0].entry_data
            data_type = entry_data_item.type
            data_size = entry_data_item.data_size
            
            if MMDB_DATA_TYPE_UTF8_STRING  ~= data_type then
                return nil,MMDB_INVALID_DATA_ERROR,resultTab
            end
            
            local val = ffi_str(entry_data_item.utf8_string,data_size)

            if not val then
                return nil,MMDB_OUT_OF_MEMORY_ERROR,resultTab
            end
            
            table.insert(resultTab,(flag and ',\"%s\":' or '\"%s\":'):format(val))
            
            flag = true
            
            entry_data_list = entry_data_list[0].next
            entry_data_list,status,resultTab = _dump_entry_data_list(entry_data_list,status,resultTab)
            
            if status ~= MMDB_SUCCESS then
                return nil,nil,resultTab
            end
            
            size = size -1 
        end
        table.insert(resultTab,"}")
        

    elseif entry_data_list[0].entry_data.type == MMDB_DATA_TYPE_ARRAY then
        local size = entry_data_list[0].entry_data.data_size

        table.insert(resultTab,"[")
        
        entry_data_list = entry_data_list[0].next
        
        while(size >0 and entry_data_list)
        do
            entry_data_list,status,resultTab = _dump_entry_data_list(entry_data_list,status,resultTab)
            
            if status ~= MMDB_SUCCESS then
                return nil,nil,resultTab
            end
            
            size = size -1 
        end
        table.insert(resultTab,"]")

        
    else
        entry_data_item = entry_data_list[0].entry_data
        data_type = entry_data_item.type
        data_size = entry_data_item.data_size
        
        local val
        local fmt="%s"
        if data_type == MMDB_DATA_TYPE_UTF8_STRING then
            val = ffi_str(entry_data_item.utf8_string,data_size)
            fmt='\"%s\"'
            if not val then
                status = MMDB_OUT_OF_MEMORY_ERROR
                return nil,status,resultTab
            end
        elseif data_type == MMDB_DATA_TYPE_BYTES then
            val = ffi_str(ffi_cast('char * ',entry_data_item.bytes),data_size)
            fmt='\"%s\"'
            if not val then
                status = MMDB_OUT_OF_MEMORY_ERROR
                return nil,status,resultTab
            end
        elseif data_type == MMDB_DATA_TYPE_DOUBLE then
            val = entry_data_item.double_value
        elseif data_type == MMDB_DATA_TYPE_FLOAT then
            val = entry_data_item.float_value
        elseif data_type == MMDB_DATA_TYPE_UINT16 then
            val = entry_data_item.uint16
        elseif data_type == MMDB_DATA_TYPE_UINT32 then
            val = entry_data_item.uint32
        elseif data_type == MMDB_DATA_TYPE_BOOLEAN then
            val = entry_data_item.boolean == 1
        elseif data_type == MMDB_DATA_TYPE_UINT64 then
            val = entry_data_item.uint64
        elseif data_type == MMDB_DATA_TYPE_INT32 then
            val = entry_data_item.int32
        else
            return nil,MMDB_INVALID_DATA_ERROR,resultTab
        end
        
        table.insert(resultTab,(fmt):format(val))
        entry_data_list = entry_data_list[0].next
    end
    status = MMDB_SUCCESS
    return entry_data_list,status,resultTab
end




在 2017年9月14日星期四 UTC+8下午3:43:09,Zexuan Luo写道:
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com

赵安家

unread,
Sep 14, 2017, 9:40:29 PM9/14/17
to openresty


在 2017年9月14日星期四 UTC+8上午10:42:21,赵安家写道:
在网上找了一些lua.ffi的资料,也看过官网的文档,但是还是一知半解。
Reply all
Reply to author
Forward
0 new messages