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);