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 const struct itimerval t = { {timeout * 1000 * 1000, 0} , {0, 0} };
292 struct sigaction sa_new, sa_old;
293 int timeout = luaL_optnumber(L, 3, 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);