Add support for UNIX Domain Sockets to the C lib. Contributed by Thomas Cort

This commit is contained in:
Thomas Veerman 2010-07-15 14:05:23 +00:00
parent 5aff633a0b
commit f531dba2d2
20 changed files with 1412 additions and 35 deletions

View 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

View 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

View 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;
}

View 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>
@ -10,6 +16,10 @@
#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;
}

View 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>
@ -12,12 +16,16 @@
#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;
}

35
lib/libc/ip/getpeereid.c Normal file
View file

@ -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;
}
}

View 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;
}

View file

@ -18,31 +18,68 @@
#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;
}

View 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>
@ -13,12 +14,16 @@
#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;
}

View 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

View 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);
}

View 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;
}

95
lib/libc/ip/recvmsg.c Normal file
View file

@ -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;
}

View 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);
}

139
lib/libc/ip/sendmsg.c Normal file
View file

@ -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);
}

View 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);
}

View 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;
}

View 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);
}

View 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;
}

135
lib/libc/ip/socketpair.c Normal file
View file

@ -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;
}