7957e8cc19aafa49bc220d3078b61500f452ce5d
2 * nixio - Linux I/O library for lua
4 * Copyright (C) 2009 Steven Barth <steven@midlink.org>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <sys/types.h>
21 #include <sys/param.h>
32 /* setjmp() / longjmp() stuff */
33 static jmp_buf nixio__jump_alarm
;
34 static void nixio__handle_alarm(int sig
) { longjmp(nixio__jump_alarm
, 1); }
36 #include <linux/netdevice.h>
38 /* struct net_device_stats is buggy on amd64, redefine it */
51 uint32_t rx_length_errors
;
52 uint32_t rx_over_errors
;
53 uint32_t rx_crc_errors
;
54 uint32_t rx_frame_errors
;
55 uint32_t rx_fifo_errors
;
56 uint32_t rx_missed_errors
;
58 uint32_t tx_aborted_errors
;
59 uint32_t tx_carrier_errors
;
60 uint32_t tx_fifo_errors
;
61 uint32_t tx_heartbeat_errors
;
62 uint32_t tx_window_errors
;
64 uint32_t rx_compressed
;
65 uint32_t tx_compressed
;
70 #define NI_MAXHOST 1025
74 * address pushing helper
76 int nixio__addr_parse(nixio_addr
*addr
, struct sockaddr
*saddr
) {
79 addr
->family
= saddr
->sa_family
;
80 if (saddr
->sa_family
== AF_INET
) {
81 struct sockaddr_in
*inetaddr
= (struct sockaddr_in
*)saddr
;
82 addr
->port
= ntohs(inetaddr
->sin_port
);
83 baddr
= &inetaddr
->sin_addr
;
84 } else if (saddr
->sa_family
== AF_INET6
) {
85 struct sockaddr_in6
*inet6addr
= (struct sockaddr_in6
*)saddr
;
86 addr
->port
= ntohs(inet6addr
->sin6_port
);
87 baddr
= &inet6addr
->sin6_addr
;
89 } else if (saddr
->sa_family
== AF_PACKET
) {
90 struct sockaddr_ll
*etheradddr
= (struct sockaddr_ll
*)saddr
;
91 addr
->prefix
= etheradddr
->sll_hatype
;
92 addr
->port
= etheradddr
->sll_ifindex
;
94 for (size_t i
= 0; i
< etheradddr
->sll_halen
; i
++) {
95 *c
++ = nixio__bin2hex
[(etheradddr
->sll_addr
[i
] & 0xf0) >> 4];
96 *c
++ = nixio__bin2hex
[(etheradddr
->sll_addr
[i
] & 0x0f)];
103 errno
= EAFNOSUPPORT
;
107 if (!inet_ntop(saddr
->sa_family
, baddr
, addr
->host
, sizeof(addr
->host
))) {
115 * address pulling helper
117 int nixio__addr_write(nixio_addr
*addr
, struct sockaddr
*saddr
) {
118 if (addr
->family
== AF_UNSPEC
) {
119 if (strchr(addr
->host
, ':')) {
120 addr
->family
= AF_INET6
;
122 addr
->family
= AF_INET
;
125 if (addr
->family
== AF_INET
) {
126 struct sockaddr_in
*inetaddr
= (struct sockaddr_in
*)saddr
;
127 memset(inetaddr
, 0, sizeof(struct sockaddr_in
));
129 if (inet_pton(AF_INET
, addr
->host
, &inetaddr
->sin_addr
) < 1) {
133 inetaddr
->sin_family
= AF_INET
;
134 inetaddr
->sin_port
= htons((uint16_t)addr
->port
);
136 } else if (addr
->family
== AF_INET6
) {
137 struct sockaddr_in6
*inet6addr
= (struct sockaddr_in6
*)saddr
;
138 memset(inet6addr
, 0, sizeof(struct sockaddr_in6
));
140 if (inet_pton(AF_INET6
, addr
->host
, &inet6addr
->sin6_addr
) < 1) {
144 inet6addr
->sin6_family
= AF_INET6
;
145 inet6addr
->sin6_port
= htons((uint16_t)addr
->port
);
148 errno
= EAFNOSUPPORT
;
154 * netmask to prefix helper
156 int nixio__addr_prefix(struct sockaddr
*saddr
) {
161 if (saddr
->sa_family
== AF_INET
) {
162 addr
= (uint8_t*)(&((struct sockaddr_in
*)saddr
)->sin_addr
);
164 } else if (saddr
->sa_family
== AF_INET6
) {
165 addr
= (uint8_t*)(&((struct sockaddr_in6
*)saddr
)->sin6_addr
);
168 errno
= EAFNOSUPPORT
;
172 for (size_t i
= 0; i
< len
; i
++) {
173 if (addr
[i
] == 0xff) {
175 } else if (addr
[i
] == 0x00) {
178 for (uint8_t c
= addr
[i
]; c
; c
<<= 1) {
188 * getaddrinfo(host, family, port)
190 static int nixio_getaddrinfo(lua_State
*L
) {
191 const char *host
= NULL
;
192 if (!lua_isnoneornil(L
, 1)) {
193 host
= luaL_checklstring(L
, 1, NULL
);
195 const char *family
= luaL_optlstring(L
, 2, "any", NULL
);
196 const char *port
= lua_tolstring(L
, 3, NULL
);
198 struct addrinfo hints
, *result
, *rp
;
199 memset(&hints
, 0, sizeof(hints
));
201 if (!strcmp(family
, "any")) {
202 hints
.ai_family
= AF_UNSPEC
;
203 } else if (!strcmp(family
, "inet")) {
204 hints
.ai_family
= AF_INET
;
205 } else if (!strcmp(family
, "inet6")) {
206 hints
.ai_family
= AF_INET6
;
208 return luaL_argerror(L
, 2, "supported values: any, inet, inet6");
211 hints
.ai_socktype
= 0;
212 hints
.ai_protocol
= 0;
214 int aistat
= getaddrinfo(host
, port
, &hints
, &result
);
217 lua_pushinteger(L
, aistat
);
218 lua_pushstring(L
, gai_strerror(aistat
));
222 /* create socket object */
226 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
227 /* avoid duplicate results */
229 if (!port
&& rp
->ai_socktype
!= SOCK_STREAM
) {
234 if (rp
->ai_family
== AF_INET
|| rp
->ai_family
== AF_INET6
) {
235 lua_createtable(L
, 0, port
? 4 : 2);
236 if (rp
->ai_family
== AF_INET
) {
237 lua_pushliteral(L
, "inet");
238 } else if (rp
->ai_family
== AF_INET6
) {
239 lua_pushliteral(L
, "inet6");
241 lua_setfield(L
, -2, "family");
244 switch (rp
->ai_socktype
) {
246 lua_pushliteral(L
, "stream");
249 lua_pushliteral(L
, "dgram");
252 lua_pushliteral(L
, "raw");
258 lua_setfield(L
, -2, "socktype");
262 if (nixio__addr_parse(&addr
, rp
->ai_addr
)) {
263 freeaddrinfo(result
);
264 return nixio__perror_s(L
);
268 lua_pushinteger(L
, addr
.port
);
269 lua_setfield(L
, -2, "port");
272 lua_pushstring(L
, addr
.host
);
273 lua_setfield(L
, -2, "address");
274 lua_rawseti(L
, -2, i
++);
278 freeaddrinfo(result
);
284 * getnameinfo(address, family[, timeout])
286 static int nixio_getnameinfo(lua_State
*L
) {
287 const char *ip
= luaL_checkstring(L
, 1);
288 const char *family
= luaL_optstring(L
, 2, NULL
);
291 struct sigaction sa_new
, sa_old
;
292 int timeout
= luaL_optnumber(L
, 3, 0);
293 const struct itimerval t
= { {timeout
* 1000 * 1000, 0} , {0, 0} };
294 if (timeout
> 0 && timeout
< 1000)
296 sa_new
.sa_handler
= nixio__handle_alarm
;
298 sigemptyset(&sa_new
.sa_mask
);
299 sigaction(SIGALRM
, &sa_new
, &sa_old
);
301 /* user timeout exceeded */
302 if (setjmp(nixio__jump_alarm
))
304 sigaction(SIGALRM
, &sa_old
, NULL
);
307 lua_pushinteger(L
, EAI_AGAIN
);
308 lua_pushstring(L
, gai_strerror(EAI_AGAIN
));
313 setitimer(ITIMER_REAL
, &t
, NULL
);
317 char host
[NI_MAXHOST
];
319 struct sockaddr_storage saddr
;
321 memset(&addr
, 0, sizeof(addr
));
322 strncpy(addr
.host
, ip
, sizeof(addr
.host
) - 1);
325 addr
.family
= AF_UNSPEC
;
326 } else if (!strcmp(family
, "inet")) {
327 addr
.family
= AF_INET
;
328 } else if (!strcmp(family
, "inet6")) {
329 addr
.family
= AF_INET6
;
331 return luaL_argerror(L
, 2, "supported values: inet, inet6");
334 nixio__addr_write(&addr
, (struct sockaddr
*)&saddr
);
336 int res
= getnameinfo((struct sockaddr
*)&saddr
,
337 (saddr
.ss_family
== AF_INET
)
338 ? sizeof(struct sockaddr_in
) : sizeof(struct sockaddr_in6
),
339 host
, sizeof(host
), NULL
, 0, NI_NAMEREQD
);
342 if (timeout
> 0 && timeout
< 1000)
345 sigaction(SIGALRM
, &sa_old
, NULL
);
351 lua_pushinteger(L
, res
);
352 lua_pushstring(L
, gai_strerror(res
));
355 lua_pushstring(L
, host
);
363 static int nixio_sock_getsockname(lua_State
*L
) {
364 int sockfd
= nixio__checksockfd(L
);
365 struct sockaddr_storage saddr
;
366 socklen_t addrlen
= sizeof(saddr
);
369 if (getsockname(sockfd
, (struct sockaddr
*)&saddr
, &addrlen
) ||
370 nixio__addr_parse(&addr
, (struct sockaddr
*)&saddr
)) {
371 return nixio__perror_s(L
);
374 lua_pushstring(L
, addr
.host
);
375 lua_pushinteger(L
, addr
.port
);
382 static int nixio_sock_getpeername(lua_State
*L
) {
383 int sockfd
= nixio__checksockfd(L
);
384 struct sockaddr_storage saddr
;
385 socklen_t addrlen
= sizeof(saddr
);
388 if (getpeername(sockfd
, (struct sockaddr
*)&saddr
, &addrlen
) ||
389 nixio__addr_parse(&addr
, (struct sockaddr
*)&saddr
)) {
390 return nixio__perror_s(L
);
393 lua_pushstring(L
, addr
.host
);
394 lua_pushinteger(L
, addr
.port
);
398 #if defined(__linux__) || defined(BSD)
404 static int nixio_getifaddrs(lua_State
*L
) {
406 struct ifaddrs
*ifaddr
, *c
;
407 if (getifaddrs(&ifaddr
) == -1) {
408 return nixio__perror(L
);
414 for (c
= ifaddr
; c
; c
= c
->ifa_next
) {
417 lua_pushstring(L
, c
->ifa_name
);
418 lua_setfield(L
, -2, "name");
420 lua_createtable(L
, 0, 7);
421 lua_pushboolean(L
, c
->ifa_flags
& IFF_UP
);
422 lua_setfield(L
, -2, "up");
424 lua_pushboolean(L
, c
->ifa_flags
& IFF_BROADCAST
);
425 lua_setfield(L
, -2, "broadcast");
427 lua_pushboolean(L
, c
->ifa_flags
& IFF_LOOPBACK
);
428 lua_setfield(L
, -2, "loopback");
430 lua_pushboolean(L
, c
->ifa_flags
& IFF_POINTOPOINT
);
431 lua_setfield(L
, -2, "pointtopoint");
433 lua_pushboolean(L
, c
->ifa_flags
& IFF_NOARP
);
434 lua_setfield(L
, -2, "noarp");
436 lua_pushboolean(L
, c
->ifa_flags
& IFF_PROMISC
);
437 lua_setfield(L
, -2, "promisc");
439 lua_pushboolean(L
, c
->ifa_flags
& IFF_MULTICAST
);
440 lua_setfield(L
, -2, "multicast");
441 lua_setfield(L
, -2, "flags");
444 if (!nixio__addr_parse(&addr
, c
->ifa_addr
)) {
445 lua_pushstring(L
, addr
.host
);
446 lua_setfield(L
, -2, "addr");
449 if (c
->ifa_addr
->sa_family
== AF_INET
) {
450 lua_pushliteral(L
, "inet");
451 } else if (c
->ifa_addr
->sa_family
== AF_INET6
) {
452 lua_pushliteral(L
, "inet6");
454 } else if (c
->ifa_addr
->sa_family
== AF_PACKET
) {
455 lua_pushliteral(L
, "packet");
458 lua_pushliteral(L
, "unknown");
460 lua_setfield(L
, -2, "family");
463 if (c
->ifa_addr
->sa_family
== AF_PACKET
) {
464 lua_pushinteger(L
, addr
.port
);
465 lua_setfield(L
, -2, "ifindex");
467 lua_pushinteger(L
, addr
.prefix
);
468 lua_setfield(L
, -2, "hatype");
474 if (c
->ifa_data
&& (!c
->ifa_addr
475 || c
->ifa_addr
->sa_family
== AF_PACKET
)) {
477 lua_pushliteral(L
, "packet");
478 lua_setfield(L
, -2, "family");
481 lua_createtable(L
, 0, 10);
482 struct nixio__nds
*stats
= c
->ifa_data
;
484 lua_pushnumber(L
, stats
->rx_packets
);
485 lua_setfield(L
, -2, "rx_packets");
487 lua_pushnumber(L
, stats
->tx_packets
);
488 lua_setfield(L
, -2, "tx_packets");
490 lua_pushnumber(L
, stats
->rx_bytes
);
491 lua_setfield(L
, -2, "rx_bytes");
493 lua_pushnumber(L
, stats
->tx_bytes
);
494 lua_setfield(L
, -2, "tx_bytes");
496 lua_pushnumber(L
, stats
->rx_errors
);
497 lua_setfield(L
, -2, "rx_errors");
499 lua_pushnumber(L
, stats
->tx_errors
);
500 lua_setfield(L
, -2, "tx_errors");
502 lua_pushnumber(L
, stats
->rx_dropped
);
503 lua_setfield(L
, -2, "rx_dropped");
505 lua_pushnumber(L
, stats
->tx_dropped
);
506 lua_setfield(L
, -2, "tx_dropped");
508 lua_pushnumber(L
, stats
->multicast
);
509 lua_setfield(L
, -2, "multicast");
511 lua_pushnumber(L
, stats
->collisions
);
512 lua_setfield(L
, -2, "collisions");
516 lua_setfield(L
, -2, "data");
519 if (c
->ifa_netmask
&& !nixio__addr_parse(&addr
, c
->ifa_netmask
)) {
520 lua_pushstring(L
, addr
.host
);
521 lua_setfield(L
, -2, "netmask");
523 lua_pushinteger(L
, nixio__addr_prefix(c
->ifa_netmask
));
524 lua_setfield(L
, -2, "prefix");
527 if (c
->ifa_broadaddr
&& !nixio__addr_parse(&addr
, c
->ifa_broadaddr
)) {
528 lua_pushstring(L
, addr
.host
);
529 lua_setfield(L
, -2, "broadaddr");
532 if (c
->ifa_dstaddr
&& !nixio__addr_parse(&addr
, c
->ifa_dstaddr
)) {
533 lua_pushstring(L
, addr
.host
);
534 lua_setfield(L
, -2, "dstaddr");
537 lua_rawseti(L
, -2, i
++);
547 static const luaL_reg R
[] = {
548 #if defined(__linux__) || defined(BSD)
549 {"getifaddrs", nixio_getifaddrs
},
551 {"getaddrinfo", nixio_getaddrinfo
},
552 {"getnameinfo", nixio_getnameinfo
},
557 static const luaL_reg M
[] = {
558 {"getsockname", nixio_sock_getsockname
},
559 {"getpeername", nixio_sock_getpeername
},
563 void nixio_open_address(lua_State
*L
) {
564 luaL_register(L
, NULL
, R
);
566 lua_pushvalue(L
, -2);
567 luaL_register(L
, NULL
, M
);