+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
getnetbyaddr.c \
getnetbyname.c \
getnetent.c \
+ getpeereid.c \
getpeername.c \
getproto.c \
getprotoent.c \
rcmd.c \
recv.c \
recvfrom.c \
+ recvmsg.c \
res_comp.c \
res_init.c \
res_mkquery.c \
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
#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>
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)
{
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.
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;
+}
+#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
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))
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
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;
+}
#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)
}
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
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;
+}
--- /dev/null
+#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;
+ }
+}
#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)
{
&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
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;
+}
#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),
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))
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;
+}
#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);
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)
{
}
r= ioctl(socket, NWIOGUDPOPT, &udpopt);
- if (r != -1 || errno != ENOTTY)
+ if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
{
if (r == -1)
{
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
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;
}
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;
+}
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
{
return recvfrom(socket, buffer, length, flags, NULL, NULL);
}
-
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,
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);
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
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;
+}
+
--- /dev/null
+#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;
+}
{
return sendto(socket, buffer, length, flags, NULL, 0);
}
-
--- /dev/null
+#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);
+}
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)
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))
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
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);
+}
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)
{
}
r= ioctl(socket, NWIOGUDPOPT, &udpopt);
- if (r != -1 || errno != ENOTTY)
+ if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
{
if (r == -1)
{
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
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;
+}
#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)
{
}
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
return -1;
}
-
+static int _uds_shutdown(int socket, int how)
+{
+ return ioctl(socket, NWIOSUDSSHUT, &how);
+}
#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)
{
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);
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
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;
+}
--- /dev/null
+#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;
+}