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
__socketpair(int domain,int type,int protocol,int sv[2])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
socketpair(int domain,int type,int protocol,int sv[2])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
_uds_socketpair(int type,int protocol,int sv[2])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