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