144 lines
2.6 KiB
C
144 lines
2.6 KiB
C
|
#include <sys/cdefs.h>
|
||
|
#include "namespace.h"
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <stdio.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
#include <net/netlib.h>
|
||
|
#include <sys/ioc_net.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/un.h>
|
||
|
|
||
|
#ifdef __weak_alias
|
||
|
__weak_alias(socketpair, _socketpair)
|
||
|
#endif
|
||
|
|
||
|
#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;
|
||
|
}
|