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