LuaJIT ffi getaddrinfo

266 views
Skip to first unread message

ms2008

unread,
May 22, 2017, 3:45:23 AM5/22/17
to openresty
用 LuaJIT 获取系统 IP 

local ffi = require "ffi"
local C = ffi.C


ffi
.cdef([[
struct ifaddrs {
   
struct ifaddrs  *ifa_next;    /* Next item in list */
   
char            *ifa_name;    /* Name of interface */
   
unsigned int     ifa_flags;   /* Flags from SIOCGIFFLAGS */
   
struct sockaddr *ifa_addr;    /* Address of interface */
   
struct sockaddr *ifa_netmask; /* Netmask of interface */
   
union {
       
struct sockaddr *ifu_broadaddr;  /* Broadcast address of interface */
       
struct sockaddr *ifu_dstaddr;    /* Point-to-point destination address */
   
} ifa_ifu;
   
void            *ifa_data;    /* Address-specific data */
};
// the union will be populated based on the following ifa_flags:
enum {
    IFF_BROADCAST  
= 0x2,  /* broadcast address valid      */
    IFF_POINTOPOINT
= 0x10  /* interface is has p-p link    */
};


int getifaddrs(struct ifaddrs **ifap);
void freeifaddrs(struct ifaddrs *ifa);


]])


-- Returns a Lua array of interfaces retrieved via C.getifaddrs
-- The original ifaddrs linked list is stored in ret.ifaddrs and is freed upon GC of ret
local function getifaddrs()
   
local ifaddrs_root = ffi.new("struct ifaddrs *[1]")
   
local res = C.getifaddrs( ifaddrs_root )
   
assert( res == 0, ffi.errno() )


   
-- convert linked list to Lua array for convenience
   
local tret = {}
   
local iter = ifaddrs_root[0]
   
while iter ~= nil do
        tret
[#tret + 1] = iter
       
-- print(ffi.string(iter.ifa_name))
       
if ffi.string(iter.ifa_name) ~= "lo" then
           
print(ffi.string(iter.ifa_name), ffi.string(iter.ifa_addr))
       
end
        iter
= iter.ifa_next
   
end


   
-- free ifaddrs when tret is gc'd
    tret.ifaddrs = ifaddrs_root
    ffi.gc( ifaddrs_root, function(t) C.freeifaddrs(t[0]) end )
    return tret
end


getifaddrs()

目前的问题是 struct sockaddr 无法转换为 lua string, 报

luajit: ffi_getaddrinfo.lua:42: bad argument #1 to 'string' (cannot convert 'struct sockaddr *' to 'const char *')

ms2008

unread,
May 23, 2017, 4:07:21 AM5/23/17
to openresty
@agentzh @doujiang

在 2017年5月22日星期一 UTC+8下午3:45:23,ms2008写道:

Bingwu Yang

unread,
May 23, 2017, 11:13:07 AM5/23/17
to open...@googlegroups.com
Hello.
认真看下错误,iter.ifa_addr 明明是 struct sockaddr *,怎么能随随便便转换为 const char *
呢,建议 man getifaddrs 仔细看看 EXAMPLE 下的 C 例子是如何吐出接口的地址。

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];

if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}

/* Walk through linked list, maintaining head pointer so we
can free list later */

for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;

family = ifa->ifa_addr->sa_family;

/* Display interface name and family (including symbolic
form of the latter for the common families) */

printf("%s address family: %d%s\n",
ifa->ifa_name, family,
(family == AF_PACKET) ? " (AF_PACKET)" :
(family == AF_INET) ? " (AF_INET)" :
(family == AF_INET6) ? " (AF_INET6)" : "");

/* For an AF_INET* interface address, display the address */

if (family == AF_INET || family == AF_INET6) {
s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\taddress: <%s>\n", host);
}
}

freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
> --
> --
> 邮件来自列表“openresty”,专用于技术讨论!
> 订阅: 请发空白邮件到 openresty...@googlegroups.com
> 发言: 请发邮件到 open...@googlegroups.com
> 退订: 请发邮件至 openresty+...@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

Zexuan Luo

unread,
May 24, 2017, 12:23:21 PM5/24/17
to openresty
提个有点离题的建议:
建议用 C 封装一层,然后暴露出简单类型的 API 给 LuaJIT 调用。

根据经验教训,系统头文件里面的结构体通常会大量采用宏去实现头文件兼容。由于 LuaJIT FFI 不支持宏,只能直接把这些结构体定义暴露到 Lua 代码里面,那是相当的恶心。
而且兼容性并不好。如果是用 C 实现的,当系统的 ABI 变化时,可能重新编译一遍就可以了。用 Lua 实现的话,需要直接改代码,而且缺乏可靠的方式去判断当前到底用的是哪套 ABI。


在 2017年5月22日星期一 UTC+8下午3:45:23,ms2008写道:
用 LuaJIT 获取系统 IP 

ms2008

unread,
May 24, 2017, 9:41:43 PM5/24/17
to openresty
谢谢,找到了一个 Mashape 的解决方案

在 2017年5月25日星期四 UTC+8上午12:23:21,Zexuan Luo写道:

soul11201

unread,
May 24, 2017, 9:49:21 PM5/24/17
to open...@googlegroups.com

2017-05-25 9:41 GMT+08:00 ms2008 <ms20...@gmail.com>:
谢谢,找到了一个 Mashape 的解决方案

也让我们学习下
​ ​
:)


--
Reply all
Reply to author
Forward
0 new messages