]> Zhao Yanbai Git Server - minix.git/commitdiff
Add support for UNIX Domain Sockets to the C lib. Contributed by Thomas Cort
authorThomas Veerman <thomas@minix3.org>
Thu, 15 Jul 2010 14:05:23 +0000 (14:05 +0000)
committerThomas Veerman <thomas@minix3.org>
Thu, 15 Jul 2010 14:05:23 +0000 (14:05 +0000)
20 files changed:
docs/UPDATING
lib/libc/ip/Makefile.inc
lib/libc/ip/accept.c
lib/libc/ip/bind.c
lib/libc/ip/connect.c
lib/libc/ip/getpeereid.c [new file with mode: 0644]
lib/libc/ip/getpeername.c
lib/libc/ip/getsockname.c
lib/libc/ip/getsockopt.c
lib/libc/ip/listen.c
lib/libc/ip/recv.c
lib/libc/ip/recvfrom.c
lib/libc/ip/recvmsg.c [new file with mode: 0644]
lib/libc/ip/send.c
lib/libc/ip/sendmsg.c [new file with mode: 0644]
lib/libc/ip/sendto.c
lib/libc/ip/setsockopt.c
lib/libc/ip/shutdown.c
lib/libc/ip/socket.c
lib/libc/ip/socketpair.c [new file with mode: 0644]

index fcb9dcbcdd020b5b29ac946006050c6f9ff2d476..8fa56ea7544fd76116f763745333213212f5f7cb 100644 (file)
@@ -1,3 +1,6 @@
+20100714:
+       mknod /dev/uds c 18 0
+       chmod 666 /dev/uds
 20100713:
         /usr/src/etc/rc updated: copy it (or merge it) to /etc/rc.
         /usr/src/etc/system.conf updated to include boot sys services: copy
index c95e1ef71c9ffafa0c0f75a2ac6918756aeee345..944c62e81b005cb768786c7576a77eaf4a2e7f74 100644 (file)
@@ -22,6 +22,7 @@ SRCS+=  \
        getnetbyaddr.c \
        getnetbyname.c \
        getnetent.c \
+       getpeereid.c \
        getpeername.c \
        getproto.c \
        getprotoent.c \
@@ -42,6 +43,7 @@ SRCS+=  \
        rcmd.c \
        recv.c \
        recvfrom.c \
+       recvmsg.c \
        res_comp.c \
        res_init.c \
        res_mkquery.c \
@@ -49,10 +51,12 @@ SRCS+=  \
        res_send.c \
        ruserok.c \
        send.c \
+       sendmsg.c \
        sendto.c \
        servxcheck.c \
        sethostent.c \
        setsockopt.c \
        shutdown.c \
        socket.c \
+       socketpair.c \
        strcasecmp.c
index 8f1085ce72399f9e056b7d263bfcb445876043d3..cfbfe93570ecc8b4b860179b1791782c68615946 100644 (file)
@@ -1,10 +1,12 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 
 #include <net/netlib.h>
 #include <net/gen/in.h>
@@ -18,6 +20,9 @@
 static int _tcp_accept(int socket, struct sockaddr *_RESTRICT address,
        socklen_t *_RESTRICT address_len);
 
+static int _uds_accept(int socket, struct sockaddr *_RESTRICT address,
+       socklen_t *_RESTRICT address_len);
+
 int accept(int socket, struct sockaddr *_RESTRICT address,
        socklen_t *_RESTRICT address_len)
 {
@@ -28,6 +33,10 @@ int accept(int socket, struct sockaddr *_RESTRICT address,
        if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
                return r;
 
+       r= _uds_accept(socket, address, address_len);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+               return r;
+
        /* Unfortunately, we have to return EOPNOTSUPP for a socket that
         * does not support accept (such as a UDP socket) and ENOTSOCK for
         * filedescriptors that do not refer to a socket.
@@ -77,3 +86,45 @@ static int _tcp_accept(int socket, struct sockaddr *_RESTRICT address,
                getpeername(s1, address, address_len);
        return s1;
 }
+
+static int _uds_accept(int socket, struct sockaddr *_RESTRICT address,
+       socklen_t *_RESTRICT address_len)
+{
+       int s1;
+       int r;
+       struct sockaddr_un uds_addr;
+       socklen_t len;
+
+       memset(&uds_addr, '\0', sizeof(struct sockaddr_un));
+
+       r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
+       if (r == -1) {
+               return r;
+       }
+
+       if (uds_addr.sun_family != AF_UNIX) {
+               errno= EINVAL;
+               return -1;
+       }
+
+       len= *address_len;
+       if (len > sizeof(struct sockaddr_un))
+               len = sizeof(struct sockaddr_un);
+
+       memcpy(address, &uds_addr, len);
+       *address_len= len;
+
+       s1= open(UDS_DEVICE, O_RDWR);
+       if (s1 == -1)
+               return s1;
+
+       r= ioctl(s1, NWIOSUDSACCEPT, address);
+       if (r == -1) {
+               int ioctl_errno = errno;
+               close(s1);
+               errno = ioctl_errno;
+               return r;
+       }
+
+       return s1;
+}
index f84e2be7393c5fae9115aa3d35d34ab4ebecfbee..2749ab7b1799e89af7d5f860075d80badfc477a9 100644 (file)
@@ -1,8 +1,14 @@
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <limits.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <netinet/in.h>
 
 #include <net/gen/in.h>
 #include <net/gen/tcp_io.h>
 #include <net/gen/udp.h>
 #include <net/gen/udp_io.h>
+#include <sys/un.h>
+
+#include <minix/config.h>
+#include <minix/const.h>
 
 #define DEBUG 0
 
@@ -17,12 +27,15 @@ static int _tcp_bind(int socket, const struct sockaddr *address,
        socklen_t address_len, nwio_tcpconf_t *tcpconfp);
 static int _udp_bind(int socket, const struct sockaddr *address,
        socklen_t address_len, nwio_udpopt_t *udpoptp);
+static int _uds_bind(int socket, const struct sockaddr *address,
+       socklen_t address_len, struct sockaddr_un *uds_addr);
 
 int bind(int socket, const struct sockaddr *address, socklen_t address_len)
 {
        int r;
        nwio_tcpconf_t tcpconf;
        nwio_udpopt_t udpopt;
+       struct sockaddr_un uds_addr;
 
        r= ioctl(socket, NWIOGTCPCONF, &tcpconf);
        if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
@@ -50,6 +63,14 @@ int bind(int socket, const struct sockaddr *address, socklen_t address_len)
                return _udp_bind(socket, address, address_len, &udpopt);
        }
 
+       r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1)
+                       return r;
+               return _uds_bind(socket, address, address_len, &uds_addr);
+       }
+
 #if DEBUG
        fprintf(stderr, "bind: not implemented for fd %d\n", socket);
 #endif
@@ -151,3 +172,183 @@ static int _udp_bind(int socket, const struct sockaddr *address,
        r= ioctl(socket, NWIOSUDPOPT, &udpopt);
        return r;
 }
+
+static int in_group(uid_t uid, gid_t gid)
+{
+       int r, i;
+       int size;
+       gid_t *list;
+
+       size = sysconf(_SC_NGROUPS_MAX);
+       list = malloc(size * sizeof(gid_t));
+
+       if (list == NULL) {
+               return 0;
+       }
+
+       r= getgroups(size, list);
+       if (r == -1) {
+               free(list);
+               return 0;
+       }
+
+       for (i = 0; i < r; i++) {
+               if (gid == list[i]) {
+                       free(list);
+                       return 1;
+               }
+       }
+
+       free(list);
+       return 0;
+}
+
+
+static int _uds_bind(int socket, const struct sockaddr *address,
+       socklen_t address_len, struct sockaddr_un *uds_addr)
+{
+       mode_t bits, perm_bits, access_desired;
+       struct stat buf;
+       uid_t euid;
+       gid_t egid;
+       char real_sun_path[PATH_MAX+1];
+       char *realpath_result;
+       int i, r, shift;
+       int null_found;
+       int did_mknod;
+
+       if (address == NULL) {
+               errno = EFAULT;
+               return -1;
+       }
+
+       /* sun_family is always supposed to be AF_UNIX */
+       if (((struct sockaddr_un *) address)->sun_family != AF_UNIX) {
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       /* an empty path is not supported */
+       if (((struct sockaddr_un *) address)->sun_path[0] == '\0') {
+               errno = ENOENT;
+               return -1;
+       }
+
+       /* the path must be a null terminated string for realpath to work */
+       for (null_found = i = 0;
+               i < sizeof(((struct sockaddr_un *) address)->sun_path); i++) {
+               if (((struct sockaddr_un *) address)->sun_path[i] == '\0') {
+                       null_found = 1;
+                       break;
+               }
+       }
+
+       if (!null_found) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       /*
+        * Get the realpath(3) of the socket file.
+        */
+
+       realpath_result = realpath(((struct sockaddr_un *) address)->sun_path,
+                                               real_sun_path);
+       if (realpath_result == NULL) {
+               return -1;
+       }
+
+       if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
+               errno = ENAMETOOLONG;
+               return -1;
+       }
+
+       strcpy(((struct sockaddr_un *) address)->sun_path, real_sun_path);
+
+       /*
+        * input parameters look good -- create the socket file on the 
+        * file system
+        */
+
+       did_mknod = 0;
+
+       r = mknod(((struct sockaddr_un *) address)->sun_path,
+               S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0);
+
+       if (r == -1) {
+               if (errno == EEXIST) {
+                       /* file already exists, verify that it is a socket */
+
+                       r = stat(((struct sockaddr_un *) address)->sun_path,
+                                                               &buf);
+                       if (r == -1) {
+                               return -1;
+                       }
+
+                       if (!S_ISSOCK(buf.st_mode)) {
+                               errno = EADDRINUSE;
+                               return -1;
+                       }
+
+                       /* check permissions the permissions of the 
+                        * socket file.
+                        */
+
+                       /* read + write access */
+                       access_desired = R_BIT | W_BIT;
+
+                       euid = geteuid();
+                       egid = getegid();
+
+                       if (euid == -1 || egid == -1) {
+                               errno = EACCES;
+                               return -1;
+                       }
+
+                       bits = buf.st_mode;
+
+                       if (euid == ((uid_t) 0)) {
+                               perm_bits = R_BIT | W_BIT;
+                       } else {
+                               if (euid == buf.st_uid) {
+                                       shift = 6; /* owner */
+                               } else if (egid == buf.st_gid) {
+                                       shift = 3; /* group */
+                               } else if (in_group(euid, buf.st_gid)) {
+                                       shift = 3; /* suppl. groups */
+                               } else {
+                                       shift = 0; /* other */
+                               }
+
+                               perm_bits = 
+                               (bits >> shift) & (R_BIT | W_BIT | X_BIT);
+                       }
+
+                       if ((perm_bits | access_desired) != perm_bits) {
+                               errno = EACCES;
+                               return -1;
+                       }
+
+                       /* if we get here permissions are OK */
+
+               } else {
+
+                       return -1;
+               }
+       } else {
+               did_mknod = 1;
+       }
+
+       /* perform the bind */
+       r= ioctl(socket, NWIOSUDSADDR, (void *) address);
+
+       if (r == -1 && did_mknod) {
+
+               /* bind() failed in pfs, so we roll back the 
+                * file system change
+                */
+               unlink(((struct sockaddr_un *) address)->sun_path);
+       }
+
+       return r;
+}
index 614fee142a155a0eb515f5c45785fa22ca57bdc9..292df6e79e3faaa8c91ec24ec24f907270f8a14f 100644 (file)
@@ -1,9 +1,13 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <netinet/in.h>
 
 #include <net/gen/in.h>
 #include <net/gen/udp.h>
 #include <net/gen/udp_io.h>
 
+#include <minix/const.h>
+
 #define DEBUG 0
 
 static int _tcp_connect(int socket, const struct sockaddr *address,
        socklen_t address_len, nwio_tcpconf_t *tcpconfp);
 static int _udp_connect(int socket, const struct sockaddr *address,
        socklen_t address_len, nwio_udpopt_t *udpoptp);
+static int _uds_connect(int socket, const struct sockaddr *address,
+       socklen_t address_len);
 
 int connect(int socket, const struct sockaddr *address,
        socklen_t address_len)
@@ -47,6 +55,21 @@ int connect(int socket, const struct sockaddr *address,
                }
                return _udp_connect(socket, address, address_len, &udpopt);
        }
+
+       r= _uds_connect(socket, address, address_len);
+       if (r != -1 ||
+               (errno != ENOTTY && errno != EBADIOCTL &&
+                errno != EAFNOSUPPORT))
+       {
+               if (r == -1)
+               {
+                       /* Bad file descriptor */
+                       return -1;
+               }
+
+               return r;
+       }
+
 #if DEBUG
        fprintf(stderr, "connect: not implemented for fd %d\n", socket);
 #endif
@@ -136,3 +159,148 @@ static int _udp_connect(int socket, const struct sockaddr *address,
        r= ioctl(socket, NWIOSUDPOPT, &udpopt);
        return r;
 }
+
+static int in_group(uid_t uid, gid_t gid)
+{
+       int r, i;
+       int size;
+       gid_t *list;
+
+       size = sysconf(_SC_NGROUPS_MAX);
+       list = malloc(size * sizeof(gid_t));
+
+       if (list == NULL) {
+               return 0;
+       }
+
+       r= getgroups(size, list);
+       if (r == -1) {
+               free(list);
+               return 0;
+       }
+
+       for (i = 0; i < r; i++) {
+               if (gid == list[i]) {
+                       free(list);
+                       return 1;
+               }
+       }
+
+       free(list);
+       return 0;
+}
+
+static int _uds_connect(int socket, const struct sockaddr *address,
+       socklen_t address_len)
+{
+       mode_t bits, perm_bits, access_desired;
+       struct stat buf;
+       uid_t euid;
+       gid_t egid;
+       char real_sun_path[PATH_MAX+1];
+       char *realpath_result;
+       int i, r, shift;
+       int null_found;
+
+       if (address == NULL) {
+               errno = EFAULT;
+               return -1;
+       }
+
+       /* sun_family is always supposed to be AF_UNIX */
+       if (((struct sockaddr_un *) address)->sun_family != AF_UNIX) {
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       /* an empty path is not supported */
+       if (((struct sockaddr_un *) address)->sun_path[0] == '\0') {
+               errno = EINVAL;
+               return -1;
+       }
+
+       /* the path must be a null terminated string for realpath to work */
+       for (null_found = i = 0;
+               i < sizeof(((struct sockaddr_un *) address)->sun_path); i++) {
+
+               if (((struct sockaddr_un *) address)->sun_path[i] == '\0') {
+                       null_found = 1;
+                       break;
+               }
+       }
+
+       if (!null_found) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       /*
+        * Get the realpath(3) of the socket file.
+        */
+
+       realpath_result = realpath(((struct sockaddr_un *) address)->sun_path,
+                                                       real_sun_path);
+       if (realpath_result == NULL) {
+               return -1;
+       }
+
+       if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
+               errno = ENAMETOOLONG;
+               return -1;
+       }
+
+       strcpy(((struct sockaddr_un *) address)->sun_path, real_sun_path);
+
+       /*
+        * input parameters look good -- check the permissions of the 
+        * socket file. emulate eaccess() (i.e. the access(2) function 
+        * with effective UID/GID).
+        */
+
+       access_desired = R_BIT | W_BIT; /* read + write access */
+
+       euid = geteuid();
+       egid = getegid();
+
+       if (euid == -1 || egid == -1) {
+               errno = EACCES;
+               return -1;
+       }
+
+       r= stat(((struct sockaddr_un *) address)->sun_path, &buf);
+       if (r == -1) {
+               return -1;
+       }
+
+       if (!S_ISSOCK(buf.st_mode)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       bits = buf.st_mode;
+
+       if (euid == ((uid_t) 0)) {
+               perm_bits = R_BIT | W_BIT;
+       } else {
+               if (euid == buf.st_uid) {
+                       shift = 6; /* owner */
+               } else if (egid == buf.st_gid) {
+                       shift = 3; /* group */
+               } else if (in_group(euid, buf.st_gid)) {
+                       shift = 3; /* suppl. groups */
+               } else {
+                       shift = 0; /* other */
+               }
+
+               perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
+       }
+
+       if ((perm_bits | access_desired) != perm_bits) {
+               errno = EACCES;
+               return -1;
+       }
+
+       /* perform the connect */
+       r= ioctl(socket, NWIOSUDSCONN, (void *) address);
+       return r;
+}
diff --git a/lib/libc/ip/getpeereid.c b/lib/libc/ip/getpeereid.c
new file mode 100644 (file)
index 0000000..ef7f609
--- /dev/null
@@ -0,0 +1,35 @@
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+
+/*
+ * get the effective user ID and effective group ID of a peer
+ * connected through a Unix domain socket.
+ */
+int getpeereid(int sd, uid_t *euid, gid_t *egid) {
+       int rc;
+       struct ucred cred;
+       socklen_t ucred_length;
+
+       /* Initialize Data Structures */
+       ucred_length = sizeof(struct ucred);
+       memset(&cred, '\0', ucred_length);
+
+       /* Validate Input Parameters */
+       if (euid == NULL || egid == NULL) {
+               errno = EFAULT;
+               return -1;
+       } /* getsockopt will handle validating 'sd' */
+
+       /* Get the credentials of the peer at the other end of 'sd' */
+       rc = getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &cred, &ucred_length);
+       if (rc == 0) {
+               /* Success - return the results */
+               *euid = cred.uid;
+               *egid = cred.gid;
+               return 0;
+       } else {
+               /* Failure - getsockopt takes care of setting errno */
+               return -1;
+       }
+}
index bf6dacabbd3d6ae1cb839fecb9a51b5457e1f962..c45c005046431aa685ae8dc167059cc9b7ba2bea 100644 (file)
@@ -9,20 +9,25 @@
 #include <net/gen/tcp.h>
 #include <net/gen/tcp_io.h>
 #include <net/gen/udp.h>
+#include <sys/un.h>
 
 #define DEBUG 0
 
 static int _tcp_getpeername(int socket, struct sockaddr *_RESTRICT address,
        socklen_t *_RESTRICT address_len, nwio_tcpconf_t *tcpconfp);
 
+static int _uds_getpeername(int socket, struct sockaddr *_RESTRICT address,
+       socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr);
+
 int getpeername(int socket, struct sockaddr *_RESTRICT address,
        socklen_t *_RESTRICT address_len)
 {
        int r;
        nwio_tcpconf_t tcpconf;
+       struct sockaddr_un uds_addr;
 
        r= ioctl(socket, NWIOGTCPCONF, &tcpconf);
-       if (r != -1 || errno != ENOTTY)
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
        {
                if (r == -1)
                {
@@ -33,6 +38,19 @@ int getpeername(int socket, struct sockaddr *_RESTRICT address,
                        &tcpconf);
        }
 
+       r= ioctl(socket, NWIOGUDSPADDR, &uds_addr);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1)
+               {
+                       /* Bad file descriptor */
+                       return -1;
+               }
+               return _uds_getpeername(socket, address, address_len,
+                       &uds_addr);
+       }
+
+
 #if DEBUG
        fprintf(stderr, "getpeername: not implemented for fd %d\n", socket);
 #endif
@@ -67,3 +85,23 @@ static int _tcp_getpeername(int socket, struct sockaddr *_RESTRICT address,
        return 0;
 }
 
+static int _uds_getpeername(int socket, struct sockaddr *_RESTRICT address,
+       socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr)
+{
+       socklen_t len;
+
+       if (uds_addr->sun_family != AF_UNIX)
+       {
+               errno= ENOTCONN;
+               return -1;
+       }
+
+       len= *address_len;
+       if (len > sizeof(struct sockaddr_un))
+               len = sizeof(struct sockaddr_un);
+
+       memcpy(address, uds_addr, len);
+       *address_len= len;
+
+       return 0;
+}
index d3c9d7d71e245610b01ceb90046d62b44192575b..acfbfbbe0e77bdbf7266193a98c2e09ec8a21798 100644 (file)
 #include <net/gen/tcp.h>
 #include <net/gen/tcp_io.h>
 #include <net/gen/udp.h>
-
+#include <sys/un.h>
 
 /*
 #define DEBUG 0
 */
 
-/*
-   getsockname...
-*/
-int getsockname(int fd, struct sockaddr *_RESTRICT address, 
+static int _tcp_getsockname(int fd, struct sockaddr *_RESTRICT address,
+   socklen_t *_RESTRICT address_len, nwio_tcpconf_t *tcpconfp);
+
+static int _uds_getsockname(int fd, struct sockaddr *_RESTRICT address,
+   socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr);
+
+int getsockname(int fd, struct sockaddr *_RESTRICT address,
    socklen_t *_RESTRICT address_len)
 {
+       int r;
        nwio_tcpconf_t tcpconf;
-       socklen_t len;
-       struct sockaddr_in sin;
+       struct sockaddr_un uds_addr;
 
 #ifdef DEBUG
        fprintf(stderr,"mnx_getsockname: ioctl fd %d.\n", fd);
 #endif
-       if (ioctl(fd, NWIOGTCPCONF, &tcpconf)==-1) {
-#ifdef DEBUG
-          fprintf(stderr,"mnx_getsockname: error %d\n", errno);
+
+       r= ioctl(fd, NWIOGTCPCONF, &tcpconf);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1)
+               {
+                       /* Bad file descriptor */
+                       return -1;
+               }
+
+               return _tcp_getsockname(fd, address, address_len, &tcpconf);
+       }
+
+       r= ioctl(fd, NWIOGUDSADDR, &uds_addr);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1)
+               {
+                       /* Bad file descriptor */
+                       return -1;
+               }
+
+               return _uds_getsockname(fd, address, address_len, &uds_addr);
+       }
+
+#if DEBUG
+       fprintf(stderr, "getsockname: not implemented for fd %d\n", socket);
 #endif
-          return (-1);
-          }
+
+       errno= ENOSYS;
+       return -1;
+}
+
+
+static int _tcp_getsockname(int fd, struct sockaddr *_RESTRICT address,
+   socklen_t *_RESTRICT address_len, nwio_tcpconf_t *tcpconf)
+{
+       socklen_t len;
+       struct sockaddr_in sin;
+
 #ifdef DEBUG1
        fprintf(stderr, "mnx_getsockname: from %s, %u",
                        inet_ntoa(tcpconf.nwtc_remaddr),
@@ -51,14 +88,11 @@ int getsockname(int fd, struct sockaddr *_RESTRICT address,
                        inet_ntoa(tcpconf.nwtc_locaddr),
                        ntohs(tcpconf.nwtc_locport));
 #endif
-/*
-       addr->sin_addr.s_addr = tcpconf.nwtc_remaddr ;
-       addr->sin_port = tcpconf.nwtc_locport;
-*/
+
        memset(&sin, '\0', sizeof(sin));
        sin.sin_family= AF_INET;
-       sin.sin_addr.s_addr= tcpconf.nwtc_locaddr ;
-       sin.sin_port= tcpconf.nwtc_locport;
+       sin.sin_addr.s_addr= tcpconf->nwtc_locaddr ;
+       sin.sin_port= tcpconf->nwtc_locport;
 
        len= *address_len;
        if (len > sizeof(sin))
@@ -69,10 +103,23 @@ int getsockname(int fd, struct sockaddr *_RESTRICT address,
        return 0;
 }
 
+static int _uds_getsockname(int fd, struct sockaddr *_RESTRICT address,
+   socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr)
+{
+       socklen_t len;
 
+       if (uds_addr->sun_family != AF_UNIX)
+       {
+               errno= EINVAL;
+               return -1;
+       }
 
+       len= *address_len;
+       if (len > sizeof(struct sockaddr_un))
+               len = sizeof(struct sockaddr_un);
 
+       memcpy(address, uds_addr, len);
+       *address_len= len;
 
-
-
-
+       return 0;
+}
index 86127362830c416f5ae60af977fa8b53977a827b..816fb78bed82ce34546c05128c76760723fc7f27 100644 (file)
@@ -5,6 +5,7 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <sys/ucred.h>
 #include <netinet/tcp.h>
 
 #include <net/gen/in.h>
 #include <net/gen/udp.h>
 #include <net/gen/udp_io.h>
 
+#include <minix/type.h>
+
 #define DEBUG 0
 
 static int _tcp_getsockopt(int socket, int level, int option_name,
        void *_RESTRICT option_value, socklen_t *_RESTRICT option_len);
 static int _udp_getsockopt(int socket, int level, int option_name,
        void *_RESTRICT option_value, socklen_t *_RESTRICT option_len);
+static int _uds_getsockopt(int socket, int level, int option_name,
+       void *_RESTRICT option_value, socklen_t *_RESTRICT option_len);
 static void getsockopt_copy(void *return_value, size_t return_len,
        void *_RESTRICT option_value, socklen_t *_RESTRICT option_len);
 
@@ -28,9 +33,10 @@ int getsockopt(int socket, int level, int option_name,
        int r;
        nwio_tcpopt_t tcpopt;
        nwio_udpopt_t udpopt;
+       struct sockaddr_un uds_addr;
 
        r= ioctl(socket, NWIOGTCPOPT, &tcpopt);
-       if (r != -1 || errno != ENOTTY)
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
        {
                if (r == -1)
                {
@@ -42,7 +48,7 @@ int getsockopt(int socket, int level, int option_name,
        }
 
        r= ioctl(socket, NWIOGUDPOPT, &udpopt);
-       if (r != -1 || errno != ENOTTY)
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
        {
                if (r == -1)
                {
@@ -53,6 +59,19 @@ int getsockopt(int socket, int level, int option_name,
                        option_value, option_len);
        }
 
+       r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1)
+               {
+                       /* Bad file descriptor */
+                       return -1;
+               }
+               return _uds_getsockopt(socket, level, option_name,
+                       option_value, option_len);
+       }
+
+
 #if DEBUG
        fprintf(stderr, "getsockopt: not implemented for fd %d\n", socket);
 #endif
@@ -141,7 +160,7 @@ static int _udp_getsockopt(int socket, int level, int option_name,
 
        if (level == SOL_SOCKET && option_name == SO_TYPE)
        {
-               i = SOCK_DGRAM; /* this is a TCP socket */
+               i = SOCK_DGRAM; /* this is a UDP socket */
                getsockopt_copy(&i, sizeof(i), option_value, option_len);
                return 0;
        }
@@ -153,3 +172,83 @@ static int _udp_getsockopt(int socket, int level, int option_name,
        errno= ENOSYS;
        return -1;
 }
+
+static int _uds_getsockopt(int socket, int level, int option_name,
+       void *_RESTRICT option_value, socklen_t *_RESTRICT option_len)
+{
+       int i, r;
+       size_t size;
+
+       if (level == SOL_SOCKET && option_name == SO_RCVBUF)
+       {
+               r= ioctl(socket, NWIOGUDSRCVBUF, &size);
+               if (r == -1) {
+                       return r;
+               }
+
+               getsockopt_copy(&size, sizeof(size), option_value, option_len);
+               return 0;
+       }
+
+       if (level == SOL_SOCKET && option_name == SO_SNDBUF)
+       {
+               r= ioctl(socket, NWIOGUDSSNDBUF, &size);
+               if (r == -1) {
+                       return r;
+               }
+
+               getsockopt_copy(&size, sizeof(size), option_value, option_len);
+               return 0;
+       }
+
+       if (level == SOL_SOCKET && option_name == SO_TYPE)
+       {
+               r= ioctl(socket, NWIOGUDSSOTYPE, &i);
+               if (r == -1) {
+                       return r;
+               }
+
+               getsockopt_copy(&i, sizeof(i), option_value, option_len);
+               return 0;
+       }
+
+       if (level == SOL_SOCKET && option_name == SO_PEERCRED)
+       {
+               struct ucred cred;
+
+               r= ioctl(socket, NWIOGUDSPEERCRED, &cred);
+               if (r == -1) {
+                       return -1;
+               }
+
+               getsockopt_copy(&cred, sizeof(struct ucred), option_value,
+                                                       option_len);
+               return 0;
+       }
+
+
+       if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
+       {
+               i = 1;  /* as long as nobody is listen()ing on the address,
+                        * it can be reused without waiting for a 
+                        * timeout to expire.
+                        */
+               getsockopt_copy(&i, sizeof(i), option_value, option_len);
+               return 0;
+       }
+
+       if (level == SOL_SOCKET && option_name == SO_PASSCRED)
+       {
+               i = 1;  /* option is always 'on' */
+               getsockopt_copy(&i, sizeof(i), option_value, option_len);
+               return 0;
+       }
+
+#if DEBUG
+       fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n",
+               level, option_name);
+#endif
+
+       errno= ENOSYS;
+       return -1;
+}
index d2283e52ed3d6b9f0c2d6bca6bb873bf1d354c45..5a8f55d0300245ca04b21cd15cd9eb1ff2c8b08d 100644 (file)
@@ -21,6 +21,10 @@ int listen(int socket, int backlog)
        if (r != -1 || errno != EBADIOCTL)
                return r;
 
+       r= ioctl(socket, NWIOSUDSBLOG, &backlog);
+       if (r != -1 || errno != EBADIOCTL)
+               return r;
+
 #if DEBUG
        fprintf(stderr, "listen: not implemented for fd %d\n", socket);
 #endif
index 6806ef2b242c3c911fa93236e846993268e00ade..b40f0a6a9b28231fffd97e73c16177f0f5e1d0ae 100644 (file)
@@ -5,4 +5,3 @@ ssize_t recv(int socket, void *buffer, size_t length, int flags)
 {
        return recvfrom(socket, buffer, length, flags, NULL, NULL);
 }
-
index 6595356663e28b228b53ab230dedd2c800cf3d32..8c3097c1d23a3c24c048f317a084480126b77bd1 100644 (file)
@@ -25,6 +25,12 @@ static ssize_t _tcp_recvfrom(int socket, void *_RESTRICT buffer, size_t length,
 static ssize_t _udp_recvfrom(int socket, void *_RESTRICT buffer, size_t length,
        int flags, struct sockaddr *_RESTRICT address,
        socklen_t *_RESTRICT address_len, nwio_udpopt_t *udpoptp);
+static ssize_t _uds_recvfrom_conn(int socket, void *_RESTRICT buffer,
+       size_t length, int flags, struct sockaddr *_RESTRICT address,
+       socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr);
+static ssize_t _uds_recvfrom_dgram(int socket, void *_RESTRICT buffer,
+       size_t length, int flags, struct sockaddr *_RESTRICT address,
+       socklen_t *_RESTRICT address_len);
 
 ssize_t recvfrom(int socket, void *_RESTRICT buffer, size_t length,
        int flags, struct sockaddr *_RESTRICT address,
@@ -33,6 +39,8 @@ ssize_t recvfrom(int socket, void *_RESTRICT buffer, size_t length,
        int r;
        nwio_tcpconf_t tcpconf;
        nwio_udpopt_t udpopt;
+       struct sockaddr_un uds_addr;
+       int uds_sotype = -1;
 
 #if DEBUG
        fprintf(stderr, "recvfrom: for fd %d\n", socket);
@@ -56,6 +64,24 @@ ssize_t recvfrom(int socket, void *_RESTRICT buffer, size_t length,
                        address, address_len, &udpopt);
        }
 
+       r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+
+               if (r == -1) {
+                       return r;
+               }
+
+               if (uds_sotype == SOCK_DGRAM) {
+                       return _uds_recvfrom_dgram(socket, buffer, 
+                               length, flags, address, address_len);
+               } else {
+                       return _uds_recvfrom_conn(socket, buffer, 
+                               length, flags, address, address_len, 
+                               &uds_addr);
+               }
+       }
+
 #if DEBUG
        fprintf(stderr, "recvfrom: not implemented for fd %d\n", socket);
 #endif
@@ -197,3 +223,70 @@ static ssize_t _udp_recvfrom(int socket, void *_RESTRICT buffer, size_t length,
        return length;
 }
 
+static ssize_t _uds_recvfrom_conn(int socket, void *_RESTRICT buffer, 
+       size_t length, int flags, struct sockaddr *_RESTRICT address,
+       socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr)
+{
+       int r;
+       size_t len;
+
+       /* for connection oriented unix domain sockets (SOCK_STREAM / 
+        * SOCK_SEQPACKET)
+        */
+
+       if (flags != 0)
+       {
+#if DEBUG
+               fprintf(stderr, "recvfrom(uds): flags not implemented\n");
+#endif
+               errno= ENOSYS;
+               return -1;
+       }
+
+       r = read(socket, buffer, length);
+
+       if (r >= 0 && address != NULL)
+       {
+
+               len= *address_len;
+               if (len > sizeof(struct sockaddr_un))
+                       len= sizeof(struct sockaddr_un);
+               memcpy(address, uds_addr, len);
+               *address_len= sizeof(struct sockaddr_un);
+       }       
+
+       return r;
+}
+
+static ssize_t _uds_recvfrom_dgram(int socket, void *_RESTRICT buffer, 
+       size_t length, int flags, struct sockaddr *_RESTRICT address,
+       socklen_t *_RESTRICT address_len)
+{
+       int r;
+       size_t len;
+
+       /* for connectionless unix domain sockets (SOCK_DGRAM) */
+
+       if (flags != 0)
+       {
+#if DEBUG
+               fprintf(stderr, "recvfrom(uds): flags not implemented\n");
+#endif
+               errno= ENOSYS;
+               return -1;
+       }
+
+       r = read(socket, buffer, length);
+
+       if (r >= 0 && address != NULL)
+       {
+               len= *address_len;
+               if (len > sizeof(struct sockaddr_un))
+                       len= sizeof(struct sockaddr_un);
+               ioctl(socket, NWIOGUDSFADDR, address);
+               *address_len= sizeof(struct sockaddr_un);
+       }       
+
+       return r;
+}
+
diff --git a/lib/libc/ip/recvmsg.c b/lib/libc/ip/recvmsg.c
new file mode 100644 (file)
index 0000000..426c719
--- /dev/null
@@ -0,0 +1,95 @@
+#undef NDEBUG
+
+#include <errno.h>
+#include <net/ioctl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#define DEBUG 0
+
+static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags);
+static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags);
+
+ssize_t recvmsg(int socket, struct msghdr *msg, int flags)
+{
+       int r;
+       int uds_sotype;
+
+       if (msg == NULL) {
+               errno= EFAULT;
+               return -1;
+       }
+
+       r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1) {
+                       return r;
+               }
+
+               if (uds_sotype == SOCK_DGRAM) {
+                       return _uds_recvmsg_dgram(socket, msg, flags);
+               } else {
+                       return _uds_recvmsg_conn(socket, msg, flags);
+               }
+       }
+
+#if DEBUG
+       fprintf(stderr, "recvmsg: not implemented for fd %d\n", socket);
+#endif
+
+       errno= ENOSYS;
+       return -1;
+}
+
+static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags)
+{
+       int r;
+
+       if (flags != 0) {
+#if DEBUG
+               fprintf(stderr, "recvmsg(uds): flags not implemented\n");
+#endif
+               errno= ENOSYS;
+               return -1;
+       }
+
+       r = readv(socket, msg->msg_iov, msg->msg_iovlen);
+
+       if (r >= 0 && msg->msg_name && msg->msg_namelen > 0)
+       {
+               getpeername(socket, msg->msg_name, &msg->msg_namelen);
+       }
+
+       msg->msg_flags = 0;
+
+       return r;
+}
+
+static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags)
+{
+       int r;
+
+       if (flags != 0) {
+#if DEBUG
+               fprintf(stderr, "recvmsg(uds): flags not implemented\n");
+#endif
+               errno= ENOSYS;
+               return -1;
+       }
+
+       r = readv(socket, msg->msg_iov, msg->msg_iovlen);
+
+       if (r >= 0 && msg->msg_name && msg->msg_namelen > 0)
+       {
+               ioctl(socket, NWIOGUDSFADDR, msg->msg_name);
+               msg->msg_namelen= sizeof(struct sockaddr_un);
+
+       }
+
+       msg->msg_flags = 0;
+
+       return r;
+}
index 3e12dd90ec399bb7a0c1c58d467a5a217c3d13a2..3bba66bf137bbff9e265395838c04d28e82114b5 100644 (file)
@@ -5,4 +5,3 @@ ssize_t send(int socket, const void *buffer, size_t length, int flags)
 {
        return sendto(socket, buffer, length, flags, NULL, 0);
 }
-
diff --git a/lib/libc/ip/sendmsg.c b/lib/libc/ip/sendmsg.c
new file mode 100644 (file)
index 0000000..3e70951
--- /dev/null
@@ -0,0 +1,139 @@
+#undef NDEBUG
+
+#include <errno.h>
+#include <net/ioctl.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#define DEBUG 0
+
+static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg, 
+       int flags);
+static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg, 
+       int flags);
+
+ssize_t sendmsg(int socket, const struct msghdr *msg, int flags)
+{
+       int r;
+       int uds_sotype;
+
+       if (msg == NULL) {
+               errno= EFAULT;
+               return -1;
+       }
+
+       r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1) {
+                       return r;
+               }
+
+               if (uds_sotype == SOCK_DGRAM) {
+                       return _uds_sendmsg_dgram(socket, msg, flags);
+               } else {
+                       return _uds_sendmsg_conn(socket, msg, flags);
+               }
+
+       }
+
+#if DEBUG
+       fprintf(stderr, "sendmsg: not implemented for fd %d\n", socket);
+#endif
+
+       errno= ENOSYS;
+       return -1;
+}
+
+static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg, 
+       int flags)
+{
+
+       if (flags != 0) {
+#if DEBUG
+               fprintf(stderr, "sendmsg(uds): flags not implemented\n");
+#endif
+               errno= ENOSYS;
+               return -1;
+
+       }
+
+       /* Silently ignore destination, if given. */
+
+       return writev(socket, msg->msg_iov, msg->msg_iovlen);
+}
+
+static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg, 
+       int flags)
+{
+       char real_sun_path[PATH_MAX+1];
+       char *realpath_result;
+       char *dest_addr;
+       int null_found;
+       int i, r;
+
+       if (flags != 0) {
+#if DEBUG
+               fprintf(stderr, "sendmsg(uds): flags not implemented\n");
+#endif
+               errno= ENOSYS;
+               return -1;
+
+       }
+
+       dest_addr = msg->msg_name;
+       if (dest_addr == NULL) {
+               errno= EFAULT;
+               return -1;
+       }
+
+       /* sun_family is always supposed to be AF_UNIX */
+       if (((struct sockaddr_un *) dest_addr)->sun_family != AF_UNIX) {
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       /* an empty path is not supported */
+       if (((struct sockaddr_un *) dest_addr)->sun_path[0] == '\0') {
+               errno = ENOENT;
+               return -1;
+       }
+
+       /* the path must be a null terminated string for realpath to work */
+       for (null_found = i = 0;
+               i < sizeof(((struct sockaddr_un *) dest_addr)->sun_path); i++) {
+               if (((struct sockaddr_un *) dest_addr)->sun_path[i] == '\0') {
+                       null_found = 1;
+                       break;
+               }
+       }
+
+       if (!null_found) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       realpath_result = realpath(
+               ((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path);
+
+       if (realpath_result == NULL) {
+               return -1;
+       }
+
+       if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
+               errno = ENAMETOOLONG;
+               return -1;
+       }
+
+       /* set the target address */
+       r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
+       if (r == -1) {
+               return r;
+       }
+
+       /* do the send */
+       return writev(socket, msg->msg_iov, msg->msg_iovlen);
+}
index 193bf61a7178f1a6a9e6e2cae46ea8a7cc9ae822..ae62a2658bc5180aeadac193ffb22aee02c9fd63 100644 (file)
@@ -24,6 +24,10 @@ static ssize_t _tcp_sendto(int socket, const void *message, size_t length,
 static ssize_t _udp_sendto(int socket, const void *message, size_t length,
        int flags, const struct sockaddr *dest_addr, socklen_t dest_len,
        nwio_udpopt_t *udpoptp);
+static ssize_t _uds_sendto_conn(int socket, const void *message, size_t length,
+       int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
+static ssize_t _uds_sendto_dgram(int socket, const void *message, size_t length,
+       int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
 
 ssize_t sendto(int socket, const void *message, size_t length, int flags,
        const struct sockaddr *dest_addr, socklen_t dest_len)
@@ -31,6 +35,8 @@ ssize_t sendto(int socket, const void *message, size_t length, int flags,
        int r;
        nwio_tcpopt_t tcpopt;
        nwio_udpopt_t udpopt;
+       struct sockaddr_un uds_addr;
+       int uds_sotype = -1;
 
        r= ioctl(socket, NWIOGTCPOPT, &tcpopt);
        if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
@@ -50,6 +56,24 @@ ssize_t sendto(int socket, const void *message, size_t length, int flags,
                        dest_addr, dest_len, &udpopt);
        }
 
+       r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1) {
+                       return r;
+               }
+
+               if (uds_sotype == SOCK_DGRAM) {
+
+                       return _uds_sendto_dgram(socket, message, 
+                               length, flags,dest_addr, dest_len);
+               } else {
+
+                       return _uds_sendto_conn(socket, message,
+                               length, flags, dest_addr, dest_len);
+               }
+       }
+
 #if DEBUG
        fprintf(stderr, "sendto: not implemented for fd %d\n", socket);
 #endif
@@ -158,3 +182,96 @@ static ssize_t _udp_sendto(int socket, const void *message, size_t length,
        return length;
 }
 
+static ssize_t _uds_sendto_conn(int socket, const void *message, size_t length,
+       int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
+{
+
+       /* for connection oriented unix domain sockets (SOCK_STREAM / 
+        * SOCK_SEQPACKET)
+        */
+
+       if (flags != 0) {
+#if DEBUG
+               fprintf(stderr, "sendto(uds): flags not implemented\n");
+#endif
+               errno= ENOSYS;
+               return -1;
+       }
+
+       /* Silently ignore destination, if given. */
+
+       return write(socket, message, length);
+}
+
+static ssize_t _uds_sendto_dgram(int socket, const void *message, size_t length,
+       int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
+{
+       char real_sun_path[PATH_MAX+1];
+       char *realpath_result;
+       int null_found;
+       int i, r;
+
+       /* for connectionless unix domain sockets (SOCK_DGRAM) */
+
+       if (flags != 0) {
+#if DEBUG
+               fprintf(stderr, "sendto(uds): flags not implemented\n");
+#endif
+               errno= ENOSYS;
+               return -1;
+       }
+
+       if (dest_addr == NULL) {
+               errno = EFAULT;
+               return -1;
+       }
+
+       /* sun_family is always supposed to be AF_UNIX */
+       if (((struct sockaddr_un *) dest_addr)->sun_family != AF_UNIX) {
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       /* an empty path is not supported */
+       if (((struct sockaddr_un *) dest_addr)->sun_path[0] == '\0') {
+               errno = ENOENT;
+               return -1;
+       }
+
+       /* the path must be a null terminated string for realpath to work */
+       for (null_found = i = 0;
+               i < sizeof(((struct sockaddr_un *) dest_addr)->sun_path); i++) {
+               if (((struct sockaddr_un *) dest_addr)->sun_path[i] == '\0') {
+                       null_found = 1;
+                       break;
+               }
+       }
+
+       if (!null_found) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       realpath_result = realpath(
+               ((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path);
+
+       if (realpath_result == NULL) {
+               return -1;
+       }
+
+       if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
+               errno = ENAMETOOLONG;
+               return -1;
+       }
+
+       strcpy(((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path);
+
+       /* set the target address */
+       r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
+       if (r == -1) {
+               return r;
+       }
+
+       /* do the send */
+       return write(socket, message, length);
+}
index c5d362ac50c8c9df19d86af6c56c4469aca7bc45..4e204a495db9dd84e56d891cfc9a544bd8196b95 100644 (file)
@@ -20,15 +20,19 @@ static int _tcp_setsockopt(int socket, int level, int option_name,
 static int _udp_setsockopt(int socket, int level, int option_name,
        const void *option_value, socklen_t option_len);
 
+static int _uds_setsockopt(int socket, int level, int option_name,
+       const void *option_value, socklen_t option_len);
+
 int setsockopt(int socket, int level, int option_name,
         const void *option_value, socklen_t option_len)
 {
        int r;
        nwio_tcpopt_t tcpopt;
        nwio_udpopt_t udpopt;
+       struct sockaddr_un uds_addr;
 
        r= ioctl(socket, NWIOGTCPOPT, &tcpopt);
-       if (r != -1 || errno != ENOTTY)
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
        {
                if (r == -1)
                {
@@ -40,7 +44,7 @@ int setsockopt(int socket, int level, int option_name,
        }
 
        r= ioctl(socket, NWIOGUDPOPT, &udpopt);
-       if (r != -1 || errno != ENOTTY)
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
        {
                if (r == -1)
                {
@@ -51,6 +55,19 @@ int setsockopt(int socket, int level, int option_name,
                        option_value, option_len);
        }
 
+       r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1)
+               {
+                       /* Bad file descriptor */
+                       return -1;
+               }
+               return _uds_setsockopt(socket, level, option_name,
+                       option_value, option_len);
+       }
+
+
 #if DEBUG
        fprintf(stderr, "setsockopt: not implemented for fd %d\n", socket);
 #endif
@@ -178,3 +195,76 @@ static int _udp_setsockopt(int socket, int level, int option_name,
        return -1;
 }
 
+
+static int _uds_setsockopt(int socket, int level, int option_name,
+       const void *option_value, socklen_t option_len)
+{
+       int i;
+       size_t size;
+
+       if (level == SOL_SOCKET && option_name == SO_RCVBUF)
+       {
+               if (option_len != sizeof(size))
+               {
+                       errno= EINVAL;
+                       return -1;
+               }
+               size= *(size_t *)option_value;
+               return ioctl(socket, NWIOSUDSRCVBUF, &size);
+       }
+
+       if (level == SOL_SOCKET && option_name == SO_SNDBUF)
+       {
+               if (option_len != sizeof(size))
+               {
+                       errno= EINVAL;
+                       return -1;
+               }
+               size= *(size_t *)option_value;
+               return ioctl(socket, NWIOSUDSSNDBUF, &size);
+       }
+
+       if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
+       {
+               if (option_len != sizeof(i))
+               {
+                       errno= EINVAL;
+                       return -1;
+               }
+               i= *(int *)option_value;
+               if (!i)
+               {
+                       /* At the moment there is no way to turn off 
+                        * reusing addresses.
+                        */
+                       errno= ENOSYS;
+                       return -1;
+               }
+               return 0;
+       }
+
+       if (level == SOL_SOCKET && option_name == SO_PASSCRED)
+       {
+               if (option_len != sizeof(i))
+               {
+                       errno= EINVAL;
+                       return -1;
+               }
+               i= *(int *)option_value;
+               if (!i)
+               {
+                       /* credentials can always be received. */
+                       errno= ENOSYS;
+                       return -1;
+               }
+               return 0;
+       }
+
+#if DEBUG
+       fprintf(stderr, "_uds_setsocketopt: level %d, name %d\n",
+               level, option_name);
+#endif
+
+       errno= ENOSYS;
+       return -1;
+}
index 128ded5275466cda63529209973dd19776f6b3c1..b2df69be69a5cdc47f76280a1133d87ab5c7ee82 100644 (file)
@@ -2,22 +2,25 @@
 #include <stdio.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 
 #include <net/gen/in.h>
 #include <net/gen/tcp.h>
 #include <net/gen/tcp_io.h>
 
-#define DEBUG 1
+#define DEBUG 0
 
 static int _tcp_shutdown(int socket, int how);
+static int _uds_shutdown(int socket, int how);
 
 int shutdown(int socket, int how)
 {
        int r;
+       struct sockaddr_un uds_addr;
        nwio_tcpconf_t tcpconf;
 
        r= ioctl(socket, NWIOGTCPCONF, &tcpconf);
-       if (r != -1 || errno != ENOTTY)
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
        {
                if (r == -1)
                {
@@ -26,6 +29,18 @@ int shutdown(int socket, int how)
                }
                return _tcp_shutdown(socket, how);
        }
+
+       r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
+       if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
+       {
+               if (r == -1)
+               {
+                       /* Bad file descriptor */
+                       return -1;
+               }
+               return _uds_shutdown(socket, how);
+       }
+
 #if DEBUG
        fprintf(stderr, "shutdown: not implemented for fd %d\n", socket);
 #endif
@@ -51,4 +66,7 @@ static int _tcp_shutdown(int socket, int how)
        return -1;
 }
 
-
+static int _uds_shutdown(int socket, int how)
+{
+       return ioctl(socket, NWIOSUDSSHUT, &how);
+}
index c08ded1bc65f5b5d81d59ee072d78a3558317ad8..0c53aaa8d839a28489d98c0eb8c08b56a7da10bc 100644 (file)
@@ -6,12 +6,14 @@
 #include <sys/socket.h>
 
 #include <net/netlib.h>
+#include <net/ioctl.h>
 #include <netinet/in.h>
 
 #define DEBUG 0
 
 static int _tcp_socket(int protocol);
 static int _udp_socket(int protocol);
+static int _uds_socket(int type, int protocol);
 
 int socket(int domain, int type, int protocol)
 {
@@ -19,7 +21,7 @@ int socket(int domain, int type, int protocol)
        fprintf(stderr, "socket: domain %d, type %d, protocol %d\n",
                domain, type, protocol);
 #endif
-       if (domain != AF_INET)
+       if (domain != AF_INET && domain != AF_UNIX)
        {
 #if DEBUG
                fprintf(stderr, "socket: bad domain %d\n", domain);
@@ -27,10 +29,15 @@ int socket(int domain, int type, int protocol)
                errno= EAFNOSUPPORT;
                return -1;
        }
-       if (type == SOCK_STREAM)
+
+       if (domain == AF_UNIX && (type == SOCK_STREAM ||
+                               type == SOCK_DGRAM || type == SOCK_SEQPACKET))
+               return _uds_socket(type, protocol);
+
+       if (domain == AF_INET && type == SOCK_STREAM)
                return _tcp_socket(protocol);
 
-       if (type == SOCK_DGRAM)
+       if (domain == AF_INET && type == SOCK_DGRAM)
                return _udp_socket(protocol);
 
 #if DEBUG
@@ -88,3 +95,38 @@ static int _udp_socket(int protocol)
        return fd;
 }
 
+static int _uds_socket(int type, int protocol)
+{
+       int fd, r;
+       if (protocol != 0)
+       {
+#if DEBUG
+               fprintf(stderr, "socket(uds): bad protocol %d\n", protocol);
+#endif
+               errno= EPROTONOSUPPORT;
+               return -1;
+       }
+
+       fd= open(UDS_DEVICE, O_RDWR);
+       if (fd == -1) {
+               return fd;
+       }
+
+       /* set the type for the socket via ioctl (SOCK_DGRAM, 
+        * SOCK_STREAM, SOCK_SEQPACKET, etc)
+        */
+       r= ioctl(fd, NWIOSUDSTYPE, &type);
+       if (r == -1) {
+               int ioctl_errno;
+
+               /* if that failed rollback socket creation */
+               ioctl_errno= errno;
+               close(fd);
+
+               /* return the error thrown by the call to ioctl */
+               errno= ioctl_errno;
+               return -1;
+       }
+
+       return fd;
+}
diff --git a/lib/libc/ip/socketpair.c b/lib/libc/ip/socketpair.c
new file mode 100644 (file)
index 0000000..55a2c7d
--- /dev/null
@@ -0,0 +1,135 @@
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <net/ioctl.h>
+#include <net/netlib.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#define DEBUG 0
+
+static int _uds_socketpair(int type, int protocol, int sv[2]);
+
+/*
+ * Create a pair of connected sockets
+ */
+int socketpair(int domain, int type, int protocol, int sv[2]) {
+
+#if DEBUG
+       fprintf(stderr, "socketpair: domain %d, type %d, protocol %d\n",
+               domain, type, protocol);
+#endif
+
+       if (domain != AF_UNIX)
+       {
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       if (domain == AF_UNIX &&
+                       (type == SOCK_STREAM || type == SOCK_SEQPACKET))
+               return _uds_socketpair(type, protocol, sv);
+
+#if DEBUG
+       fprintf(stderr,
+               "socketpair: nothing for domain %d, type %d, protocol %d\n",
+               domain, type, protocol);
+#endif
+
+       errno= EPROTOTYPE;
+       return -1;
+}
+
+static int _uds_socketpair(int type, int protocol, int sv[2])
+{
+       dev_t dev;
+       int r, i;
+       struct stat sbuf;
+
+       if (protocol != 0)
+       {
+#if DEBUG
+               fprintf(stderr, "socketpair(uds): bad protocol %d\n", protocol);
+#endif
+               errno= EPROTONOSUPPORT;
+               return -1;
+       }
+
+       /* in this 'for' loop two unconnected sockets are created */
+       for (i = 0; i < 2; i++) {
+               sv[i]= open(UDS_DEVICE, O_RDWR);
+               if (sv[i] == -1) {
+                       int open_errno = errno;
+
+                       if (i == 1) {
+                               /* if we failed to open() the 2nd 
+                                * socket, we need to close the 1st
+                                */
+                               close(sv[0]);
+                               errno = open_errno;
+                       }
+
+                       return -1;
+               }
+
+               /* set the type for the socket via ioctl
+                * (SOCK_STREAM, SOCK_SEQPACKET, etc)
+                */
+               r= ioctl(sv[i], NWIOSUDSTYPE, &type);
+               if (r == -1) {
+                       int ioctl_errno;
+
+                       /* if that failed rollback socket creation */
+                       ioctl_errno= errno;
+                       close(sv[i]);
+
+                       if (i == 1) {
+                               /* if we just closed the 2nd socket, we 
+                                * need to close the 1st
+                                */
+                               close(sv[0]);
+                       }
+
+                       /* return the error thrown by the call to ioctl */
+                       errno= ioctl_errno;
+                       return -1;
+               }
+       }
+
+       r= fstat(sv[1], &sbuf);
+       if (r == -1) {
+               int fstat_errno;
+
+               /* if that failed rollback socket creation */
+               fstat_errno= errno;
+
+               close(sv[0]);
+               close(sv[1]);
+
+               /* return the error thrown by the call to fstat */
+               errno= fstat_errno;
+               return -1;
+       }
+
+       dev = sbuf.st_dev;
+
+       /* connect the sockets sv[0] and sv[1] */
+       r= ioctl(sv[0], NWIOSUDSPAIR, &dev);
+       if (r == -1) {
+               int ioctl_errno;
+
+               /* if that failed rollback socket creation */
+               ioctl_errno= errno;
+
+               close(sv[0]);
+               close(sv[1]);
+
+               /* return the error thrown by the call to ioctl */
+               errno= ioctl_errno;
+               return -1;
+       }
+
+
+       return 0;
+}