xref: /minix/minix/lib/libc/sys/socketpair.c (revision 83133719)
1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 
4 #include <errno.h>
5 #include <stdio.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8 #include <net/netlib.h>
9 #include <sys/ioc_net.h>
10 #include <sys/socket.h>
11 #include <sys/stat.h>
12 #include <sys/un.h>
13 
14 #define DEBUG 0
15 
16 static int _uds_socketpair(int type, int protocol, int sv[2]);
17 
18 /*
19  * Create a pair of connected sockets
20  */
21 int socketpair(int domain, int type, int protocol, int sv[2]) {
22 
23 #if DEBUG
24 	fprintf(stderr, "socketpair: domain %d, type %d, protocol %d\n",
25 		domain, type, protocol);
26 #endif
27 
28 	if (domain != AF_UNIX)
29 	{
30 		errno = EAFNOSUPPORT;
31 		return -1;
32 	}
33 
34 	if (domain == AF_UNIX &&
35 			(type == SOCK_STREAM || type == SOCK_SEQPACKET))
36 		return _uds_socketpair(type, protocol, sv);
37 
38 #if DEBUG
39 	fprintf(stderr,
40 		"socketpair: nothing for domain %d, type %d, protocol %d\n",
41 		domain, type, protocol);
42 #endif
43 
44 	errno= EPROTOTYPE;
45 	return -1;
46 }
47 
48 static int _uds_socketpair(int type, int protocol, int sv[2])
49 {
50 	dev_t dev;
51 	int r, i;
52 	struct stat sbuf;
53 
54 	if (protocol != 0)
55 	{
56 #if DEBUG
57 		fprintf(stderr, "socketpair(uds): bad protocol %d\n", protocol);
58 #endif
59 		errno= EPROTONOSUPPORT;
60 		return -1;
61 	}
62 
63 	/* in this 'for' loop two unconnected sockets are created */
64 	for (i = 0; i < 2; i++) {
65 		sv[i]= open(UDS_DEVICE, O_RDWR);
66 		if (sv[i] == -1) {
67 			int open_errno = errno;
68 
69 			if (i == 1) {
70 				/* if we failed to open() the 2nd
71 				 * socket, we need to close the 1st
72 				 */
73 				close(sv[0]);
74 				errno = open_errno;
75 			}
76 
77 			return -1;
78 		}
79 
80 		/* set the type for the socket via ioctl
81 		 * (SOCK_STREAM, SOCK_SEQPACKET, etc)
82 		 */
83 		r= ioctl(sv[i], NWIOSUDSTYPE, &type);
84 		if (r == -1) {
85 			int ioctl_errno;
86 
87 			/* if that failed rollback socket creation */
88 			ioctl_errno= errno;
89 			close(sv[i]);
90 
91 			if (i == 1) {
92 				/* if we just closed the 2nd socket, we
93 				 * need to close the 1st
94 				 */
95 				close(sv[0]);
96 			}
97 
98 			/* return the error thrown by the call to ioctl */
99 			errno= ioctl_errno;
100 			return -1;
101 		}
102 	}
103 
104 	r= fstat(sv[1], &sbuf);
105 	if (r == -1) {
106 		int fstat_errno;
107 
108 		/* if that failed rollback socket creation */
109 		fstat_errno= errno;
110 
111 		close(sv[0]);
112 		close(sv[1]);
113 
114 		/* return the error thrown by the call to fstat */
115 		errno= fstat_errno;
116 		return -1;
117 	}
118 
119 	dev = sbuf.st_rdev;
120 
121 	/* connect the sockets sv[0] and sv[1] */
122 	r= ioctl(sv[0], NWIOSUDSPAIR, &dev);
123 	if (r == -1) {
124 		int ioctl_errno;
125 
126 		/* if that failed rollback socket creation */
127 		ioctl_errno= errno;
128 
129 		close(sv[0]);
130 		close(sv[1]);
131 
132 		/* return the error thrown by the call to ioctl */
133 		errno= ioctl_errno;
134 		return -1;
135 	}
136 
137 
138 	return 0;
139 }
140