libs/web: remove debugging code
[project/luci.git] / libs / nixio / src / sockopt.c
index b80e2e3532b3db229dd90a4b6549066c73070837..cede884ce4616d7748c16a4613a2b4aa31eb8a1f 100644 (file)
  */
 
 #include "nixio.h"
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
+
+#ifndef __WINNT__
+#include <net/if.h>
+#endif
+
+#include <sys/types.h>
 #include <sys/time.h>
 #include <string.h>
 #include <fcntl.h>
-#include "nixio.h"
+#include <errno.h>
+
+#ifndef IPV6_ADD_MEMBERSHIP
+#define IPV6_ADD_MEMBERSHIP            IPV6_JOIN_GROUP
+#endif
 
+#ifndef IPV6_DROP_MEMBERSHIP
+#define IPV6_DROP_MEMBERSHIP   IPV6_LEAVE_GROUP
+#endif
+
+static int nixio_sock_fileno(lua_State *L) {
+       lua_pushinteger(L, nixio__checkfd(L, 1));
+       return 1;
+}
 
 /**
  * setblocking()
@@ -33,6 +48,9 @@ static int nixio_sock_setblocking(lua_State *L) {
        int fd = nixio__checkfd(L, 1);
        luaL_checkany(L, 2);
        int set = lua_toboolean(L, 2);
+
+#ifndef __WINNT__
+
        int flags = fcntl(fd, F_GETFL);
 
        if (flags == -1) {
@@ -46,50 +64,64 @@ static int nixio_sock_setblocking(lua_State *L) {
        }
 
        return nixio__pstatus(L, !fcntl(fd, F_SETFL, flags));
+
+#else /* __WINNT__ */
+
+       lua_getmetatable(L, 1);
+       luaL_getmetatable(L, NIXIO_META);
+       if (lua_equal(L, -1, -2)) {     /* Socket */
+               unsigned long val = !set;
+               return nixio__pstatus_s(L, !ioctlsocket(fd, FIONBIO, &val));
+       } else {                                        /* File */
+               WSASetLastError(WSAENOTSOCK);
+               return nixio__perror_s(L);
+       }
+
+#endif /* __WINNT__ */
 }
 
 static int nixio__gso_int(lua_State *L, int fd, int level, int opt, int set) {
        int value;
        socklen_t optlen = sizeof(value);
        if (!set) {
-               if (!getsockopt(fd, level, opt, &value, &optlen)) {
+               if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) {
                        lua_pushinteger(L, value);
                        return 1;
                }
        } else {
                value = luaL_checkinteger(L, set);
-               if (!setsockopt(fd, level, opt, &value, optlen)) {
+               if (!setsockopt(fd, level, opt, (char *)&value, optlen)) {
                        lua_pushboolean(L, 1);
                        return 1;
                }
        }
-       return nixio__perror(L);
+       return nixio__perror_s(L);
 }
 
 static int nixio__gso_ling(lua_State *L, int fd, int level, int opt, int set) {
        struct linger value;
        socklen_t optlen = sizeof(value);
        if (!set) {
-               if (!getsockopt(fd, level, opt, &value, &optlen)) {
+               if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) {
                        lua_pushinteger(L, value.l_onoff ? value.l_linger : 0);
                        return 1;
                }
        } else {
                value.l_linger = luaL_checkinteger(L, set);
                value.l_onoff = value.l_linger ? 1 : 0;
-               if (!setsockopt(fd, level, opt, &value, optlen)) {
+               if (!setsockopt(fd, level, opt, (char *)&value, optlen)) {
                        lua_pushboolean(L, 1);
                        return 1;
                }
        }
-       return nixio__perror(L);
+       return nixio__perror_s(L);
 }
 
 static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) {
        struct timeval value;
        socklen_t optlen = sizeof(value);
        if (!set) {
-               if (!getsockopt(fd, level, opt, &value, &optlen)) {
+               if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) {
                        lua_pushinteger(L, value.tv_sec);
                        lua_pushinteger(L, value.tv_usec);
                        return 2;
@@ -97,12 +129,96 @@ static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) {
        } else {
                value.tv_sec  = luaL_checkinteger(L, set);
                value.tv_usec = luaL_optinteger(L, set + 1, 0);
-               if (!setsockopt(fd, level, opt, &value, optlen)) {
+               if (!setsockopt(fd, level, opt, (char *)&value, optlen)) {
                        lua_pushboolean(L, 1);
                        return 1;
                }
        }
-       return nixio__perror(L);
+       return nixio__perror_s(L);
+}
+
+#ifdef SO_BINDTODEVICE
+
+static int nixio__gso_b(lua_State *L, int fd, int level, int opt, int set) {
+       if (!set) {
+               socklen_t optlen = IFNAMSIZ;
+               char ifname[IFNAMSIZ];
+               if (!getsockopt(fd, level, opt, (char *)ifname, &optlen)) {
+                       lua_pushlstring(L, ifname, optlen);
+                       return 1;
+               }
+       } else {
+               size_t valuelen;
+               const char *value = luaL_checklstring(L, set, &valuelen);
+               luaL_argcheck(L, valuelen <= IFNAMSIZ, set, "invalid interface name");
+               if (!setsockopt(fd, level, opt, (char *)value, valuelen)) {
+                       lua_pushboolean(L, 1);
+                       return 1;
+               }
+       }
+       return nixio__perror_s(L);
+}
+
+#endif /* SO_BINDTODEVICE */
+
+static int nixio__gso_mreq4(lua_State *L, int fd, int level, int opt, int set) {
+       struct ip_mreq value;
+       socklen_t optlen = sizeof(value);
+       if (!set) {
+               char buf[INET_ADDRSTRLEN];
+               if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) {
+                       if (!inet_ntop(AF_INET, &value.imr_multiaddr, buf, sizeof(buf))) {
+                               return nixio__perror_s(L);
+                       }
+                       lua_pushstring(L, buf);
+                       if (!inet_ntop(AF_INET, &value.imr_interface, buf, sizeof(buf))) {
+                               return nixio__perror_s(L);
+                       }
+                       lua_pushstring(L, buf);
+                       return 2;
+               }
+       } else {
+               const char *maddr = luaL_checkstring(L, set);
+               const char *iface = luaL_optstring(L, set + 1, "0.0.0.0");
+               if (inet_pton(AF_INET, maddr, &value.imr_multiaddr) < 1) {
+                       return nixio__perror_s(L);
+               }
+               if (inet_pton(AF_INET, iface, &value.imr_interface) < 1) {
+                       return nixio__perror_s(L);
+               }
+               if (!setsockopt(fd, level, opt, (char *)&value, optlen)) {
+                       lua_pushboolean(L, 1);
+                       return 1;
+               }
+       }
+       return nixio__perror_s(L);
+}
+
+static int nixio__gso_mreq6(lua_State *L, int fd, int level, int opt, int set) {
+       struct ipv6_mreq val;
+       socklen_t optlen = sizeof(val);
+       if (!set) {
+               char buf[INET_ADDRSTRLEN];
+               if (!getsockopt(fd, level, opt, (char *)&val, &optlen)) {
+                       if (!inet_ntop(AF_INET6, &val.ipv6mr_multiaddr, buf, sizeof(buf))) {
+                               return nixio__perror_s(L);
+                       }
+                       lua_pushstring(L, buf);
+                       lua_pushinteger(L, val.ipv6mr_interface);
+                       return 2;
+               }
+       } else {
+               const char *maddr = luaL_checkstring(L, set);
+               if (inet_pton(AF_INET6, maddr, &val.ipv6mr_multiaddr) < 1) {
+                       return nixio__perror_s(L);
+               }
+               val.ipv6mr_interface = luaL_optlong(L, set + 1, 0);
+               if (!setsockopt(fd, level, opt, (char *)&val, optlen)) {
+                       lua_pushboolean(L, 1);
+                       return 1;
+               }
+       }
+       return nixio__perror_s(L);
 }
 
 /**
@@ -124,33 +240,114 @@ static int nixio__getsetsockopt(lua_State *L, int set) {
                } else if (!strcmp(option, "sndbuf")) {
                        return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_SNDBUF, set);
                } else if (!strcmp(option, "priority")) {
+#ifdef SO_PRIORITY
                        return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_PRIORITY, set);
+#else
+                       return nixio__pstatus(L, !(errno = ENOPROTOOPT));
+#endif
                } else if (!strcmp(option, "broadcast")) {
                        return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_BROADCAST, set);
+               } else if (!strcmp(option, "dontroute")) {
+                       return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_DONTROUTE, set);
+               } else if (!strcmp(option, "error")) {
+                       return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_ERROR, set);
+               } else if (!strcmp(option, "oobinline")) {
+                       return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_OOBINLINE, set);
                } else if (!strcmp(option, "linger")) {
                        return nixio__gso_ling(L, sock->fd, SOL_SOCKET, SO_LINGER, set);
                } else if (!strcmp(option, "sndtimeo")) {
                        return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_SNDTIMEO, set);
                } else if (!strcmp(option, "rcvtimeo")) {
                        return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_RCVTIMEO, set);
+               } else if (!strcmp(option, "bindtodevice")) {
+#ifdef SO_BINDTODEVICE
+                       return nixio__gso_b(L, sock->fd, SOL_SOCKET, SO_BINDTODEVICE, set);
+#else
+                       return nixio__pstatus(L, !(errno = ENOPROTOOPT));
+#endif
                } else {
                        return luaL_argerror(L, 3, "supported values: keepalive, reuseaddr,"
-                        " sndbuf, rcvbuf, priority, broadcast, linger, sndtimeo, rcvtimeo"
+                        " sndbuf, rcvbuf, priority, broadcast, linger, sndtimeo, rcvtimeo,"
+                        " dontroute, bindtodevice, error, oobinline"
                        );
                }
        } else if (!strcmp(level, "tcp")) {
-               if (sock->type != SOCK_STREAM) {
-                       return luaL_error(L, "not a TCP socket");
-               }
                if (!strcmp(option, "cork")) {
+#ifdef TCP_CORK
                        return nixio__gso_int(L, sock->fd, IPPROTO_TCP, TCP_CORK, set);
+#else
+                       return nixio__pstatus(L, !(errno = ENOPROTOOPT));
+#endif
                } else if (!strcmp(option, "nodelay")) {
                        return nixio__gso_int(L, sock->fd, IPPROTO_TCP, TCP_NODELAY, set);
                } else {
                        return luaL_argerror(L, 3, "supported values: cork, nodelay");
                }
+       } else if (!strcmp(level, "ip")) {
+               if (!strcmp(option, "mtu")) {
+#ifdef IP_MTU
+                       return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MTU, set);
+#else
+                       return nixio__pstatus(L, !(errno = ENOPROTOOPT));
+#endif
+               } else if (!strcmp(option, "hdrincl")) {
+                       return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_HDRINCL,
+                                       set);
+               } else if (!strcmp(option, "multicast_loop")) {
+                       return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MULTICAST_LOOP,
+                                       set);
+               } else if (!strcmp(option, "multicast_ttl")) {
+                       return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MULTICAST_TTL,
+                                       set);
+               } else if (!strcmp(option, "multicast_if")) {
+                       return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_MULTICAST_IF,
+                                       set);
+               } else if (!strcmp(option, "add_membership")) {
+                       return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                                       set);
+               } else if (!strcmp(option, "drop_membership")) {
+                       return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+                                       set);
+               } else {
+                       return luaL_argerror(L, 3,
+                               "supported values: hdrincl, mtu, multicast_loop, "
+                               "multicast_ttl, multicast_if, add_membership, drop_membership");
+               }
+       } else if (!strcmp(level, "ipv6")) {
+               if (!strcmp(option, "mtu")) {
+#ifdef IPV6_MTU
+                       return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, IPV6_MTU, set);
+#else
+                       return nixio__pstatus(L, !(errno = ENOPROTOOPT));
+#endif
+               } else if (!strcmp(option, "v6only")) {
+#ifdef IPV6_V6ONLY
+                       return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, set);
+#else
+                       return nixio__pstatus(L, !(errno = ENOPROTOOPT));
+#endif
+               } else if (!strcmp(option, "multicast_loop")) {
+                       return nixio__gso_int(L, sock->fd, IPPROTO_IPV6,
+                                       IPV6_MULTICAST_LOOP, set);
+               } else if (!strcmp(option, "multicast_hops")) {
+                       return nixio__gso_int(L, sock->fd, IPPROTO_IPV6,
+                                       IPV6_MULTICAST_HOPS, set);
+               } else if (!strcmp(option, "multicast_if")) {
+                       return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6,
+                                       IPV6_MULTICAST_IF, set);
+               } else if (!strcmp(option, "add_membership")) {
+                       return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6,
+                                       IPV6_ADD_MEMBERSHIP, set);
+               } else if (!strcmp(option, "drop_membership")) {
+                       return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6,
+                                       IPV6_DROP_MEMBERSHIP, set);
+               } else {
+                       return luaL_argerror(L, 3,
+                               "supported values: v6only, mtu, multicast_loop, multicast_hops,"
+                               " multicast_if, add_membership, drop_membership");
+               }
        } else {
-               return luaL_argerror(L, 2, "supported values: socket, tcp");
+               return luaL_argerror(L, 2, "supported values: socket, tcp, ip, ipv6");
        }
 }
 
@@ -173,6 +370,9 @@ static const luaL_reg M[] = {
        {"setblocking", nixio_sock_setblocking},
        {"getsockopt",  nixio_sock_getsockopt},
        {"setsockopt",  nixio_sock_setsockopt},
+       {"getopt",              nixio_sock_getsockopt},
+       {"setopt",              nixio_sock_setsockopt},
+       {"fileno",              nixio_sock_fileno},
        {NULL,                  NULL}
 };
 
@@ -184,5 +384,7 @@ void nixio_open_sockopt(lua_State *L) {
        luaL_getmetatable(L, NIXIO_FILE_META);
        lua_pushcfunction(L, nixio_sock_setblocking);
        lua_setfield(L, -2, "setblocking");
+       lua_pushcfunction(L, nixio_sock_fileno);
+       lua_setfield(L, -2, "fileno");
        lua_pop(L, 1);
 }