[PATCH] Abstract address UNIX sockets not binding properly (by capnbry@gmail.com...
[project/luci.git] / libs / nixio / src / bind.c
index b636c0a..68e1df8 100644 (file)
 
 #include "nixio.h"
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <sys/un.h>
 #include <string.h>
 #include <unistd.h>
-#include <netdb.h>
 #include <errno.h>
-#include "nixio.h"
+
 
 /**
  * connect()/bind() shortcut
@@ -87,6 +83,9 @@ static int nixio__bind_connect(lua_State *L, int do_bind) {
                }
 
                if (do_bind) {
+                       int one = 1;
+                       setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR,
+                        (char*)&one, sizeof(one));
                        status = bind(sock->fd, rp->ai_addr, rp->ai_addrlen);
                } else {
                        do {
@@ -103,7 +102,11 @@ static int nixio__bind_connect(lua_State *L, int do_bind) {
                }
 
                do {
+#ifndef __WINNT__
                        clstat = close(sock->fd);
+#else
+                       clstat = closesocket(sock->fd);
+#endif
                } while (clstat == -1 && errno == EINTR);
        }
 
@@ -111,7 +114,7 @@ static int nixio__bind_connect(lua_State *L, int do_bind) {
 
        /* on failure */
        if (status) {
-               return nixio__perror(L);
+               return nixio__perror_s(L);
        }
 
        luaL_getmetatable(L, NIXIO_META);
@@ -177,33 +180,35 @@ static int nixio_sock__bind_connect(lua_State *L, int do_bind) {
                        }
 
                        /* on success */
-                       if (!status) {
+                       if (!status || errno == EINPROGRESS) {
                                break;
                        }
                }
 
                freeaddrinfo(result);
+#ifndef __WINNT__
        } else if (sock->domain == AF_UNIX) {
                size_t pathlen;
                const char *path = luaL_checklstring(L, 2, &pathlen);
 
                struct sockaddr_un addr;
                addr.sun_family = AF_UNIX;
-               luaL_argcheck(L, pathlen < sizeof(addr.sun_path), 2, "out of range");
-               strncpy(addr.sun_path, path, sizeof(addr.sun_path));
+               luaL_argcheck(L, pathlen <= sizeof(addr.sun_path), 2, "out of range");
+               memcpy(addr.sun_path, path, pathlen);
+               socklen_t alen = sizeof(sa_family_t) + pathlen;
 
                if (do_bind) {
-                       status = bind(sock->fd, (struct sockaddr*)&addr, sizeof(addr));
+                       status = bind(sock->fd, (struct sockaddr*)&addr, alen);
                } else {
                        do {
-                               status = connect(sock->fd, (struct sockaddr*)&addr,
-                                               sizeof(addr));
+                               status = connect(sock->fd, (struct sockaddr*)&addr, alen);
                        } while (status == -1 && errno == EINTR);
                }
+#endif
        } else {
                return luaL_error(L, "not supported");
        }
-       return nixio__pstatus(L, !status);
+       return nixio__pstatus_s(L, !status);
 }
 
 /**
@@ -225,8 +230,8 @@ static int nixio_sock_connect(lua_State *L) {
  */
 static int nixio_sock_listen(lua_State *L) {
        int sockfd = nixio__checksockfd(L);
-       lua_Integer backlog = luaL_checkinteger(L, 2);
-       return nixio__pstatus(L, !listen(sockfd, backlog));
+       int backlog = luaL_checkinteger(L, 2);
+       return nixio__pstatus_s(L, !listen(sockfd, backlog));
 }
 
 /**
@@ -234,18 +239,16 @@ static int nixio_sock_listen(lua_State *L) {
  */
 static int nixio_sock_accept(lua_State *L) {
        nixio_sock *sock = nixio__checksock(L);
-       struct sockaddr_storage addr;
-       socklen_t addrlen = sizeof(addr);
-       char ipaddr[INET6_ADDRSTRLEN];
-       void *binaddr;
-       uint16_t port;
+       struct sockaddr_storage saddr;
+       nixio_addr addr;
+       socklen_t saddrlen = sizeof(saddr);
        int newfd;
 
        do {
-               newfd = accept(sock->fd, (struct sockaddr *)&addr, &addrlen);
+               newfd = accept(sock->fd, (struct sockaddr *)&saddr, &saddrlen);
        } while (newfd == -1 && errno == EINTR);
        if (newfd < 0) {
-               return nixio__perror(L);
+               return nixio__perror_s(L);
        }
 
        /* create userdata */
@@ -256,25 +259,13 @@ static int nixio_sock_accept(lua_State *L) {
        memcpy(clsock, sock, sizeof(clsock));
        clsock->fd = newfd;
 
-       if (addr.ss_family == AF_INET) {
-               struct sockaddr_in *inetaddr = (struct sockaddr_in*)&addr;
-               port = inetaddr->sin_port;
-               binaddr = &inetaddr->sin_addr;
-       } else if (addr.ss_family == AF_INET6) {
-               struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)&addr;
-               port = inet6addr->sin6_port;
-               binaddr = &inet6addr->sin6_addr;
+       if (!nixio__addr_parse(&addr, (struct sockaddr *)&saddr)) {
+               lua_pushstring(L, addr.host);
+               lua_pushinteger(L, addr.port);
+               return 3;
        } else {
-               return luaL_error(L, "unknown address family");
+               return 1;
        }
-
-       if (!inet_ntop(addr.ss_family, binaddr, ipaddr, sizeof(ipaddr))) {
-               return nixio__perror(L);
-       }
-
-       lua_pushstring(L, ipaddr);
-       lua_pushinteger(L, ntohs(port));
-       return 3;
 }
 
 /* module table */