libs/nixio: cancel pending alarm after successfully returning from getnameinfo()
[project/luci.git] / libs / nixio / src / address.c
index 41c6b8a..d4f13d7 100644 (file)
 #include <string.h>
 
 #ifdef __linux__
+
+#include <signal.h>
+#include <setjmp.h>
+#include <unistd.h>
+
+/* setjmp() / longjmp() stuff */
+static jmp_buf nixio__jump_alarm;
+static void nixio__handle_alarm(int sig) { longjmp(nixio__jump_alarm, 1); }
+
 #include <linux/netdevice.h>
 
 /* struct net_device_stats is buggy on amd64, redefine it */
@@ -271,11 +280,38 @@ static int nixio_getaddrinfo(lua_State *L) {
 }
 
 /**
- * getnameinfo(address, family)
+ * getnameinfo(address, family[, timeout])
  */
 static int nixio_getnameinfo(lua_State *L) {
        const char *ip = luaL_checkstring(L, 1);
        const char *family = luaL_optstring(L, 2, NULL);
+
+#ifdef __linux__
+       struct sigaction sa_new, sa_old;
+       int timeout = luaL_optnumber(L, 3, 0);
+       if (timeout > 0 && timeout < 1000)
+       {
+               sa_new.sa_handler = nixio__handle_alarm;
+               sa_new.sa_flags   = 0;
+               sigemptyset(&sa_new.sa_mask);
+               sigaction(SIGALRM, &sa_new, &sa_old);
+
+               /* user timeout exceeded */
+               if (setjmp(nixio__jump_alarm))
+               {
+                       sigaction(SIGALRM, &sa_old, NULL);
+
+                       lua_pushnil(L);
+                       lua_pushinteger(L, EAI_AGAIN);
+                       lua_pushstring(L, gai_strerror(EAI_AGAIN));
+
+                       return 3;
+               }
+
+               ualarm(timeout * 1000, 0);
+       }
+#endif
+
        char host[NI_MAXHOST];
 
        struct sockaddr_storage saddr;
@@ -297,6 +333,15 @@ static int nixio_getnameinfo(lua_State *L) {
 
        int res = getnameinfo((struct sockaddr *)&saddr, sizeof(saddr),
         host, sizeof(host), NULL, 0, NI_NAMEREQD);
+
+#ifdef __linux__
+       if (timeout > 0 && timeout < 1000)
+       {
+               ualarm(0);
+               sigaction(SIGALRM, &sa_old, NULL);
+       }
+#endif
+
        if (res) {
                lua_pushnil(L);
                lua_pushinteger(L, res);
@@ -391,9 +436,11 @@ static int nixio_getifaddrs(lua_State *L) {
                        lua_setfield(L, -2, "multicast");
                lua_setfield(L, -2, "flags");
 
-               if (c->ifa_addr && !nixio__addr_parse(&addr, c->ifa_addr)) {
-                       lua_pushstring(L, addr.host);
-                       lua_setfield(L, -2, "addr");
+               if (c->ifa_addr) {
+                       if (!nixio__addr_parse(&addr, c->ifa_addr)) {
+                               lua_pushstring(L, addr.host);
+                               lua_setfield(L, -2, "addr");
+                       }
 
                        if (c->ifa_addr->sa_family == AF_INET) {
                                lua_pushliteral(L, "inet");
@@ -415,47 +462,55 @@ static int nixio_getifaddrs(lua_State *L) {
 
                                lua_pushinteger(L, addr.prefix);
                                lua_setfield(L, -2, "hatype");
+                       }
+#endif
+               }
 
-                               if (c->ifa_data) {
-                                       lua_createtable(L, 0, 10);
-                                       struct nixio__nds *stats = c->ifa_data;
+#ifdef __linux__
+               if (c->ifa_data && (!c->ifa_addr
+                                                       || c->ifa_addr->sa_family == AF_PACKET)) {
+                       if (!c->ifa_addr) {
+                               lua_pushliteral(L, "packet");
+                               lua_setfield(L, -2, "family");
+                       }
 
-                                       lua_pushnumber(L, stats->rx_packets);
-                                       lua_setfield(L, -2, "rx_packets");
+                       lua_createtable(L, 0, 10);
+                       struct nixio__nds *stats = c->ifa_data;
 
-                                       lua_pushnumber(L, stats->tx_packets);
-                                       lua_setfield(L, -2, "tx_packets");
+                       lua_pushnumber(L, stats->rx_packets);
+                       lua_setfield(L, -2, "rx_packets");
 
-                                       lua_pushnumber(L, stats->rx_bytes);
-                                       lua_setfield(L, -2, "rx_bytes");
+                       lua_pushnumber(L, stats->tx_packets);
+                       lua_setfield(L, -2, "tx_packets");
 
-                                       lua_pushnumber(L, stats->tx_bytes);
-                                       lua_setfield(L, -2, "tx_bytes");
+                       lua_pushnumber(L, stats->rx_bytes);
+                       lua_setfield(L, -2, "rx_bytes");
 
-                                       lua_pushnumber(L, stats->rx_errors);
-                                       lua_setfield(L, -2, "rx_errors");
+                       lua_pushnumber(L, stats->tx_bytes);
+                       lua_setfield(L, -2, "tx_bytes");
 
-                                       lua_pushnumber(L, stats->tx_errors);
-                                       lua_setfield(L, -2, "tx_errors");
+                       lua_pushnumber(L, stats->rx_errors);
+                       lua_setfield(L, -2, "rx_errors");
 
-                                       lua_pushnumber(L, stats->rx_dropped);
-                                       lua_setfield(L, -2, "rx_dropped");
+                       lua_pushnumber(L, stats->tx_errors);
+                       lua_setfield(L, -2, "tx_errors");
 
-                                       lua_pushnumber(L, stats->tx_dropped);
-                                       lua_setfield(L, -2, "tx_dropped");
+                       lua_pushnumber(L, stats->rx_dropped);
+                       lua_setfield(L, -2, "rx_dropped");
 
-                                       lua_pushnumber(L, stats->multicast);
-                                       lua_setfield(L, -2, "multicast");
+                       lua_pushnumber(L, stats->tx_dropped);
+                       lua_setfield(L, -2, "tx_dropped");
 
-                                       lua_pushnumber(L, stats->collisions);
-                                       lua_setfield(L, -2, "collisions");
-                               } else {
-                                       lua_newtable(L);
-                               }
-                               lua_setfield(L, -2, "data");
-                       }
-#endif
+                       lua_pushnumber(L, stats->multicast);
+                       lua_setfield(L, -2, "multicast");
+
+                       lua_pushnumber(L, stats->collisions);
+                       lua_setfield(L, -2, "collisions");
+               } else {
+                       lua_newtable(L);
                }
+               lua_setfield(L, -2, "data");
+#endif
 
                if (c->ifa_netmask && !nixio__addr_parse(&addr, c->ifa_netmask)) {
                        lua_pushstring(L, addr.host);