3547f19bef80215ff22903637402f83a8268127b
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>
25 #include <linux/netdevice.h>
27 /* struct net_device_stats is buggy on amd64, redefine it */
40 uint32_t rx_length_errors
;
41 uint32_t rx_over_errors
;
42 uint32_t rx_crc_errors
;
43 uint32_t rx_frame_errors
;
44 uint32_t rx_fifo_errors
;
45 uint32_t rx_missed_errors
;
47 uint32_t tx_aborted_errors
;
48 uint32_t tx_carrier_errors
;
49 uint32_t tx_fifo_errors
;
50 uint32_t tx_heartbeat_errors
;
51 uint32_t tx_window_errors
;
53 uint32_t rx_compressed
;
54 uint32_t tx_compressed
;
59 #define NI_MAXHOST 1025
63 * address pushing helper
65 int nixio__addr_parse(nixio_addr
*addr
, struct sockaddr
*saddr
) {
68 addr
->family
= saddr
->sa_family
;
69 if (saddr
->sa_family
== AF_INET
) {
70 struct sockaddr_in
*inetaddr
= (struct sockaddr_in
*)saddr
;
71 addr
->port
= ntohs(inetaddr
->sin_port
);
72 baddr
= &inetaddr
->sin_addr
;
73 } else if (saddr
->sa_family
== AF_INET6
) {
74 struct sockaddr_in6
*inet6addr
= (struct sockaddr_in6
*)saddr
;
75 addr
->port
= ntohs(inet6addr
->sin6_port
);
76 baddr
= &inet6addr
->sin6_addr
;
78 } else if (saddr
->sa_family
== AF_PACKET
) {
79 struct sockaddr_ll
*etheradddr
= (struct sockaddr_ll
*)saddr
;
80 addr
->prefix
= etheradddr
->sll_hatype
;
81 addr
->port
= etheradddr
->sll_ifindex
;
83 for (size_t i
= 0; i
< etheradddr
->sll_halen
; i
++) {
84 *c
++ = nixio__bin2hex
[(etheradddr
->sll_addr
[i
] & 0xf0) >> 4];
85 *c
++ = nixio__bin2hex
[(etheradddr
->sll_addr
[i
] & 0x0f)];
96 if (!inet_ntop(saddr
->sa_family
, baddr
, addr
->host
, sizeof(addr
->host
))) {
104 * address pulling helper
106 int nixio__addr_write(nixio_addr
*addr
, struct sockaddr
*saddr
) {
107 if (addr
->family
== AF_UNSPEC
) {
108 if (strchr(addr
->host
, ':')) {
109 addr
->family
= AF_INET6
;
111 addr
->family
= AF_INET
;
114 if (addr
->family
== AF_INET
) {
115 struct sockaddr_in
*inetaddr
= (struct sockaddr_in
*)saddr
;
116 memset(inetaddr
, 0, sizeof(struct sockaddr_in
));
118 if (inet_pton(AF_INET
, addr
->host
, &inetaddr
->sin_addr
) < 1) {
122 inetaddr
->sin_family
= AF_INET
;
123 inetaddr
->sin_port
= htons((uint16_t)addr
->port
);
125 } else if (addr
->family
== AF_INET6
) {
126 struct sockaddr_in6
*inet6addr
= (struct sockaddr_in6
*)saddr
;
127 memset(inet6addr
, 0, sizeof(struct sockaddr_in6
));
129 if (inet_pton(AF_INET6
, addr
->host
, &inet6addr
->sin6_addr
) < 1) {
133 inet6addr
->sin6_family
= AF_INET6
;
134 inet6addr
->sin6_port
= htons((uint16_t)addr
->port
);
137 errno
= EAFNOSUPPORT
;
143 * netmask to prefix helper
145 int nixio__addr_prefix(struct sockaddr
*saddr
) {
150 if (saddr
->sa_family
== AF_INET
) {
151 addr
= (uint8_t*)(&((struct sockaddr_in
*)saddr
)->sin_addr
);
153 } else if (saddr
->sa_family
== AF_INET6
) {
154 addr
= (uint8_t*)(&((struct sockaddr_in6
*)saddr
)->sin6_addr
);
157 errno
= EAFNOSUPPORT
;
161 for (size_t i
= 0; i
< len
; i
++) {
162 if (addr
[i
] == 0xff) {
164 } else if (addr
[i
] == 0x00) {
167 for (uint8_t c
= addr
[i
]; c
; c
<<= 1) {
177 * getaddrinfo(host, family, port)
179 static int nixio_getaddrinfo(lua_State
*L
) {
180 const char *host
= NULL
;
181 if (!lua_isnoneornil(L
, 1)) {
182 host
= luaL_checklstring(L
, 1, NULL
);
184 const char *family
= luaL_optlstring(L
, 2, "any", NULL
);
185 const char *port
= lua_tolstring(L
, 3, NULL
);
187 struct addrinfo hints
, *result
, *rp
;
188 memset(&hints
, 0, sizeof(hints
));
190 if (!strcmp(family
, "any")) {
191 hints
.ai_family
= AF_UNSPEC
;
192 } else if (!strcmp(family
, "inet")) {
193 hints
.ai_family
= AF_INET
;
194 } else if (!strcmp(family
, "inet6")) {
195 hints
.ai_family
= AF_INET6
;
197 return luaL_argerror(L
, 2, "supported values: any, inet, inet6");
200 hints
.ai_socktype
= 0;
201 hints
.ai_protocol
= 0;
203 int aistat
= getaddrinfo(host
, port
, &hints
, &result
);
206 lua_pushinteger(L
, aistat
);
207 lua_pushstring(L
, gai_strerror(aistat
));
211 /* create socket object */
215 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
216 /* avoid duplicate results */
218 if (!port
&& rp
->ai_socktype
!= SOCK_STREAM
) {
223 if (rp
->ai_family
== AF_INET
|| rp
->ai_family
== AF_INET6
) {
224 lua_createtable(L
, 0, port
? 4 : 2);
225 if (rp
->ai_family
== AF_INET
) {
226 lua_pushliteral(L
, "inet");
227 } else if (rp
->ai_family
== AF_INET6
) {
228 lua_pushliteral(L
, "inet6");
230 lua_setfield(L
, -2, "family");
233 switch (rp
->ai_socktype
) {
235 lua_pushliteral(L
, "stream");
238 lua_pushliteral(L
, "dgram");
241 lua_pushliteral(L
, "raw");
247 lua_setfield(L
, -2, "socktype");
251 if (nixio__addr_parse(&addr
, rp
->ai_addr
)) {
252 freeaddrinfo(result
);
253 return nixio__perror_s(L
);
257 lua_pushinteger(L
, addr
.port
);
258 lua_setfield(L
, -2, "port");
261 lua_pushstring(L
, addr
.host
);
262 lua_setfield(L
, -2, "address");
263 lua_rawseti(L
, -2, i
++);
267 freeaddrinfo(result
);
273 * getnameinfo(address, family)
275 static int nixio_getnameinfo(lua_State
*L
) {
276 const char *ip
= luaL_checkstring(L
, 1);
277 const char *family
= luaL_optstring(L
, 2, NULL
);
278 char host
[NI_MAXHOST
];
280 struct sockaddr_storage saddr
;
282 memset(&addr
, 0, sizeof(addr
));
283 strncpy(addr
.host
, ip
, sizeof(addr
.host
) - 1);
286 addr
.family
= AF_UNSPEC
;
287 } else if (!strcmp(family
, "inet")) {
288 addr
.family
= AF_INET
;
289 } else if (!strcmp(family
, "inet6")) {
290 addr
.family
= AF_INET6
;
292 return luaL_argerror(L
, 2, "supported values: inet, inet6");
295 nixio__addr_write(&addr
, (struct sockaddr
*)&saddr
);
297 int res
= getnameinfo((struct sockaddr
*)&saddr
, sizeof(saddr
),
298 host
, sizeof(host
), NULL
, 0, NI_NAMEREQD
);
301 lua_pushinteger(L
, res
);
302 lua_pushstring(L
, gai_strerror(res
));
305 lua_pushstring(L
, host
);
313 static int nixio_sock_getsockname(lua_State
*L
) {
314 int sockfd
= nixio__checksockfd(L
);
315 struct sockaddr_storage saddr
;
316 socklen_t addrlen
= sizeof(saddr
);
319 if (getsockname(sockfd
, (struct sockaddr
*)&saddr
, &addrlen
) ||
320 nixio__addr_parse(&addr
, (struct sockaddr
*)&saddr
)) {
321 return nixio__perror_s(L
);
324 lua_pushstring(L
, addr
.host
);
325 lua_pushnumber(L
, addr
.port
);
332 static int nixio_sock_getpeername(lua_State
*L
) {
333 int sockfd
= nixio__checksockfd(L
);
334 struct sockaddr_storage saddr
;
335 socklen_t addrlen
= sizeof(saddr
);
338 if (getpeername(sockfd
, (struct sockaddr
*)&saddr
, &addrlen
) ||
339 nixio__addr_parse(&addr
, (struct sockaddr
*)&saddr
)) {
340 return nixio__perror_s(L
);
343 lua_pushstring(L
, addr
.host
);
344 lua_pushnumber(L
, addr
.port
);
348 #if defined(__linux__) || defined(BSD)
351 static int nixio_getifaddrs(lua_State
*L
) {
353 struct ifaddrs
*ifaddr
, *c
;
354 if (getifaddrs(&ifaddr
) == -1) {
355 return nixio__perror(L
);
361 for (c
= ifaddr
; c
; c
= c
->ifa_next
) {
364 lua_pushstring(L
, c
->ifa_name
);
365 lua_setfield(L
, -2, "name");
367 lua_createtable(L
, 0, 7);
368 lua_pushboolean(L
, c
->ifa_flags
& IFF_UP
);
369 lua_setfield(L
, -2, "up");
371 lua_pushboolean(L
, c
->ifa_flags
& IFF_BROADCAST
);
372 lua_setfield(L
, -2, "broadcast");
374 lua_pushboolean(L
, c
->ifa_flags
& IFF_LOOPBACK
);
375 lua_setfield(L
, -2, "loopback");
377 lua_pushboolean(L
, c
->ifa_flags
& IFF_POINTOPOINT
);
378 lua_setfield(L
, -2, "pointtopoint");
380 lua_pushboolean(L
, c
->ifa_flags
& IFF_NOARP
);
381 lua_setfield(L
, -2, "noarp");
383 lua_pushboolean(L
, c
->ifa_flags
& IFF_PROMISC
);
384 lua_setfield(L
, -2, "promisc");
386 lua_pushboolean(L
, c
->ifa_flags
& IFF_MULTICAST
);
387 lua_setfield(L
, -2, "multicast");
388 lua_setfield(L
, -2, "flags");
390 if (c
->ifa_addr
&& !nixio__addr_parse(&addr
, c
->ifa_addr
)) {
391 lua_pushstring(L
, addr
.host
);
392 lua_setfield(L
, -2, "addr");
394 if (c
->ifa_addr
->sa_family
== AF_INET
) {
395 lua_pushliteral(L
, "inet");
396 } else if (c
->ifa_addr
->sa_family
== AF_INET6
) {
397 lua_pushliteral(L
, "inet6");
399 } else if (c
->ifa_addr
->sa_family
== AF_PACKET
) {
400 lua_pushliteral(L
, "packet");
403 lua_pushliteral(L
, "unknown");
405 lua_setfield(L
, -2, "family");
408 if (c
->ifa_addr
->sa_family
== AF_PACKET
) {
409 lua_pushinteger(L
, addr
.port
);
410 lua_setfield(L
, -2, "ifindex");
412 lua_pushinteger(L
, addr
.prefix
);
413 lua_setfield(L
, -2, "hatype");
416 lua_createtable(L
, 0, 10);
417 struct nixio__nds
*stats
= c
->ifa_data
;
419 lua_pushnumber(L
, stats
->rx_packets
);
420 lua_setfield(L
, -2, "rx_packets");
422 lua_pushnumber(L
, stats
->tx_packets
);
423 lua_setfield(L
, -2, "tx_packets");
425 lua_pushnumber(L
, stats
->rx_bytes
);
426 lua_setfield(L
, -2, "rx_bytes");
428 lua_pushnumber(L
, stats
->tx_bytes
);
429 lua_setfield(L
, -2, "tx_bytes");
431 lua_pushnumber(L
, stats
->rx_errors
);
432 lua_setfield(L
, -2, "rx_errors");
434 lua_pushnumber(L
, stats
->tx_errors
);
435 lua_setfield(L
, -2, "tx_errors");
437 lua_pushnumber(L
, stats
->rx_dropped
);
438 lua_setfield(L
, -2, "rx_dropped");
440 lua_pushnumber(L
, stats
->tx_dropped
);
441 lua_setfield(L
, -2, "tx_dropped");
443 lua_pushnumber(L
, stats
->multicast
);
444 lua_setfield(L
, -2, "multicast");
446 lua_pushnumber(L
, stats
->collisions
);
447 lua_setfield(L
, -2, "collisions");
451 lua_setfield(L
, -2, "data");
456 if (c
->ifa_netmask
&& !nixio__addr_parse(&addr
, c
->ifa_netmask
)) {
457 lua_pushstring(L
, addr
.host
);
458 lua_setfield(L
, -2, "netmask");
460 lua_pushinteger(L
, nixio__addr_prefix(c
->ifa_netmask
));
461 lua_setfield(L
, -2, "prefix");
464 if (c
->ifa_broadaddr
&& !nixio__addr_parse(&addr
, c
->ifa_broadaddr
)) {
465 lua_pushstring(L
, addr
.host
);
466 lua_setfield(L
, -2, "broadaddr");
469 if (c
->ifa_dstaddr
&& !nixio__addr_parse(&addr
, c
->ifa_dstaddr
)) {
470 lua_pushstring(L
, addr
.host
);
471 lua_setfield(L
, -2, "dstaddr");
474 lua_rawseti(L
, -2, i
++);
484 static const luaL_reg R
[] = {
485 #if defined(__linux__) || defined(BSD)
486 {"getifaddrs", nixio_getifaddrs
},
488 {"getaddrinfo", nixio_getaddrinfo
},
489 {"getnameinfo", nixio_getnameinfo
},
494 static const luaL_reg M
[] = {
495 {"getsockname", nixio_sock_getsockname
},
496 {"getpeername", nixio_sock_getpeername
},
500 void nixio_open_address(lua_State
*L
) {
501 luaL_register(L
, NULL
, R
);
503 lua_pushvalue(L
, -2);
504 luaL_register(L
, NULL
, M
);